[spirv] Fix static variable init from different storage class (#969)
If the initializer is in a different storage class, we sometimes need to decompose it and assign basic components recursively. Fixes https://github.com/Microsoft/DirectXShaderCompiler/issues/968
This commit is contained in:
Родитель
1d48a06455
Коммит
273e2a45af
|
@ -4018,7 +4018,10 @@ void SPIRVEmitter::initOnce(QualType varType, std::string varName,
|
||||||
theBuilder.setInsertPoint(todoBB);
|
theBuilder.setInsertPoint(todoBB);
|
||||||
// Do initialization and mark done
|
// Do initialization and mark done
|
||||||
if (varInit) {
|
if (varInit) {
|
||||||
theBuilder.createStore(varPtr, doExpr(varInit));
|
storeValue(
|
||||||
|
// Static function variable are of private storage class
|
||||||
|
SpirvEvalInfo(varPtr).setStorageClass(spv::StorageClass::Private),
|
||||||
|
doExpr(varInit), varInit->getType());
|
||||||
} else {
|
} else {
|
||||||
const auto typeId = typeTranslator.translateType(varType);
|
const auto typeId = typeTranslator.translateType(varType);
|
||||||
theBuilder.createStore(varPtr, theBuilder.getConstantNull(typeId));
|
theBuilder.createStore(varPtr, theBuilder.getConstantNull(typeId));
|
||||||
|
@ -7109,15 +7112,15 @@ bool SPIRVEmitter::emitEntryFunctionWrapper(const FunctionDecl *decl,
|
||||||
|
|
||||||
// Initialize all global variables at the beginning of the wrapper
|
// Initialize all global variables at the beginning of the wrapper
|
||||||
for (const VarDecl *varDecl : toInitGloalVars) {
|
for (const VarDecl *varDecl : toInitGloalVars) {
|
||||||
const auto id = declIdMapper.getDeclResultId(varDecl);
|
const auto varInfo = declIdMapper.getDeclResultId(varDecl);
|
||||||
if (const auto *init = varDecl->getInit()) {
|
if (const auto *init = varDecl->getInit()) {
|
||||||
theBuilder.createStore(id, doExpr(init));
|
storeValue(varInfo, doExpr(init), varDecl->getType());
|
||||||
|
|
||||||
// Update counter variable associatd with global variables
|
// Update counter variable associatd with global variables
|
||||||
tryToAssignCounterVar(varDecl, init);
|
tryToAssignCounterVar(varDecl, init);
|
||||||
} else {
|
} else {
|
||||||
const auto typeId = typeTranslator.translateType(varDecl->getType());
|
const auto typeId = typeTranslator.translateType(varDecl->getType());
|
||||||
theBuilder.createStore(id, theBuilder.getConstantNull(typeId));
|
theBuilder.createStore(varInfo, theBuilder.getConstantNull(typeId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
// Run: %dxc -T vs_6_0 -E main
|
||||||
|
|
||||||
|
// Tests struct variable initialization from different storage class
|
||||||
|
|
||||||
|
struct S {
|
||||||
|
float4 pos : POSITION;
|
||||||
|
};
|
||||||
|
|
||||||
|
cbuffer Constants {
|
||||||
|
S uniform_struct;
|
||||||
|
}
|
||||||
|
|
||||||
|
// uniform_struct is of type %S, while (fn_)private_struct and s is of type %S_0.
|
||||||
|
// So we need to decompose and assign for uniform_struct -> (fn_)private_struct,
|
||||||
|
// but not private_struct -> s.
|
||||||
|
|
||||||
|
// CHECK-LABEL: %main = OpFunction
|
||||||
|
|
||||||
|
// CHECK: [[ptr:%\d+]] = OpAccessChain %_ptr_Uniform_S %var_Constants %int_0
|
||||||
|
// CHECK-NEXT: [[uniform:%\d+]] = OpLoad %S [[ptr]]
|
||||||
|
// CHECK-NEXT: [[vec:%\d+]] = OpCompositeExtract %v4float [[uniform]] 0
|
||||||
|
// CHECK-NEXT: [[ptr:%\d+]] = OpAccessChain %_ptr_Private_v4float %private_struct %uint_0
|
||||||
|
// CHECK-NEXT: OpStore [[ptr]] [[vec]]
|
||||||
|
static const S private_struct = uniform_struct; // Unifrom -> Private
|
||||||
|
|
||||||
|
float4 foo();
|
||||||
|
|
||||||
|
S main()
|
||||||
|
// CHECK-LABEL: %src_main = OpFunction
|
||||||
|
{
|
||||||
|
S Out;
|
||||||
|
// CHECK: [[private:%\d+]] = OpLoad %S_0 %private_struct
|
||||||
|
// CHECK-NEXT: OpStore %s [[private]]
|
||||||
|
S s = private_struct; // Private -> Function
|
||||||
|
Out.pos = s.pos + foo();
|
||||||
|
return Out;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 foo()
|
||||||
|
// CHECK-LABEL: %foo = OpFunction
|
||||||
|
{
|
||||||
|
// CHECK: [[ptr:%\d+]] = OpAccessChain %_ptr_Uniform_S %var_Constants %int_0
|
||||||
|
// CHECK-NEXT: [[uniform:%\d+]] = OpLoad %S [[ptr]]
|
||||||
|
// CHECK-NEXT: [[vec:%\d+]] = OpCompositeExtract %v4float [[uniform]] 0
|
||||||
|
// CHECK-NEXT: [[ptr:%\d+]] = OpAccessChain %_ptr_Private_v4float %fn_private_struct %uint_0
|
||||||
|
// CHECK-NEXT: OpStore [[ptr]] [[vec]]
|
||||||
|
static S fn_private_struct = uniform_struct; // Uniform -> Private
|
||||||
|
return fn_private_struct.pos;
|
||||||
|
}
|
|
@ -102,6 +102,9 @@ TEST_F(FileTest, VarInitTbuffer) {
|
||||||
runFileTest("var.init.tbuffer.hlsl", FileTest::Expect::Warning);
|
runFileTest("var.init.tbuffer.hlsl", FileTest::Expect::Warning);
|
||||||
}
|
}
|
||||||
TEST_F(FileTest, VarInitOpaque) { runFileTest("var.init.opaque.hlsl"); }
|
TEST_F(FileTest, VarInitOpaque) { runFileTest("var.init.opaque.hlsl"); }
|
||||||
|
TEST_F(FileTest, VarInitCrossStorageClass) {
|
||||||
|
runFileTest("var.init.cross-storage-class.hlsl");
|
||||||
|
}
|
||||||
TEST_F(FileTest, StaticVar) { runFileTest("var.static.hlsl"); }
|
TEST_F(FileTest, StaticVar) { runFileTest("var.static.hlsl"); }
|
||||||
|
|
||||||
// For prefix/postfix increment/decrement
|
// For prefix/postfix increment/decrement
|
||||||
|
|
Загрузка…
Ссылка в новой задаче