writer/spirv: Fix constant initialization
The code to auto-generate initializers for overridable pipeline constants was in the non-const code path, so move it to the right place and fix the tests that were wrongly testing non-const variables. Bug: tint:254 Change-Id: Ifc96681492768ecf844f67e114377cc643ef7609 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/50040 Auto-Submit: James Price <jrprice@google.com> Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
0aeb77c40f
commit
a67f8a44bb
|
@ -688,9 +688,34 @@ bool Builder::GenerateGlobalVariable(ast::Variable* var) {
|
|||
|
||||
if (var->is_const()) {
|
||||
if (!var->has_constructor()) {
|
||||
// Constants must have an initializer unless they have an override
|
||||
// decoration.
|
||||
if (!ast::HasDecoration<ast::OverrideDecoration>(var->decorations())) {
|
||||
error_ = "missing constructor for constant";
|
||||
return false;
|
||||
}
|
||||
|
||||
// SPIR-V requires specialization constants to have initializers.
|
||||
if (sem->Type()->Is<sem::F32>()) {
|
||||
ast::FloatLiteral l(ProgramID(), Source{}, 0.0f);
|
||||
init_id = GenerateLiteralIfNeeded(var, &l);
|
||||
} else if (sem->Type()->Is<sem::U32>()) {
|
||||
ast::UintLiteral l(ProgramID(), Source{}, 0);
|
||||
init_id = GenerateLiteralIfNeeded(var, &l);
|
||||
} else if (sem->Type()->Is<sem::I32>()) {
|
||||
ast::SintLiteral l(ProgramID(), Source{}, 0);
|
||||
init_id = GenerateLiteralIfNeeded(var, &l);
|
||||
} else if (sem->Type()->Is<sem::Bool>()) {
|
||||
ast::BoolLiteral l(ProgramID(), Source{}, false);
|
||||
init_id = GenerateLiteralIfNeeded(var, &l);
|
||||
} else {
|
||||
error_ = "invalid type for pipeline constant ID, must be scalar";
|
||||
return false;
|
||||
}
|
||||
if (init_id == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
push_debug(spv::Op::OpName,
|
||||
{Operand::Int(init_id),
|
||||
Operand::String(builder_.Symbols().NameFor(var->symbol()))});
|
||||
|
@ -743,36 +768,9 @@ bool Builder::GenerateGlobalVariable(ast::Variable* var) {
|
|||
}
|
||||
}
|
||||
} else if (!type_no_ac->Is<sem::Sampler>()) {
|
||||
// Certain cases require us to generate a constructor value.
|
||||
//
|
||||
// 1- Pipeline constant IDs must be attached to the OpConstant, if we have a
|
||||
// variable with an override attribute that doesn't have a constructor we
|
||||
// make one
|
||||
// 2- If we don't have a constructor and we're an Output or Private variable
|
||||
// then WGSL requires an initializer.
|
||||
if (ast::HasDecoration<ast::OverrideDecoration>(var->decorations())) {
|
||||
if (type_no_ac->Is<sem::F32>()) {
|
||||
ast::FloatLiteral l(ProgramID(), Source{}, 0.0f);
|
||||
init_id = GenerateLiteralIfNeeded(var, &l);
|
||||
} else if (type_no_ac->Is<sem::U32>()) {
|
||||
ast::UintLiteral l(ProgramID(), Source{}, 0);
|
||||
init_id = GenerateLiteralIfNeeded(var, &l);
|
||||
} else if (type_no_ac->Is<sem::I32>()) {
|
||||
ast::SintLiteral l(ProgramID(), Source{}, 0);
|
||||
init_id = GenerateLiteralIfNeeded(var, &l);
|
||||
} else if (type_no_ac->Is<sem::Bool>()) {
|
||||
ast::BoolLiteral l(ProgramID(), Source{}, false);
|
||||
init_id = GenerateLiteralIfNeeded(var, &l);
|
||||
} else {
|
||||
error_ = "invalid type for pipeline constant ID, must be scalar";
|
||||
return false;
|
||||
}
|
||||
if (init_id == 0) {
|
||||
return 0;
|
||||
}
|
||||
ops.push_back(Operand::Int(init_id));
|
||||
} else if (sem->StorageClass() == ast::StorageClass::kPrivate ||
|
||||
sem->StorageClass() == ast::StorageClass::kNone ||
|
||||
// If we don't have a constructor and we're an Output or Private variable,
|
||||
// then WGSL requires that we zero-initialize.
|
||||
if (sem->StorageClass() == ast::StorageClass::kPrivate ||
|
||||
sem->StorageClass() == ast::StorageClass::kOutput) {
|
||||
init_id = GenerateConstantNullIfNeeded(type_no_ac);
|
||||
if (init_id == 0) {
|
||||
|
|
|
@ -203,8 +203,8 @@ TEST_F(BuilderTest, GlobalVar_WithBuiltin) {
|
|||
)");
|
||||
}
|
||||
|
||||
TEST_F(BuilderTest, GlobalVar_ConstantId_Bool) {
|
||||
auto* v = Global("var", ty.bool_(), ast::StorageClass::kInput, Expr(true),
|
||||
TEST_F(BuilderTest, GlobalVar_Override_Bool) {
|
||||
auto* v = GlobalConst("var", ty.bool_(), Expr(true),
|
||||
ast::DecorationList{
|
||||
create<ast::OverrideDecoration>(1200),
|
||||
});
|
||||
|
@ -212,19 +212,17 @@ TEST_F(BuilderTest, GlobalVar_ConstantId_Bool) {
|
|||
spirv::Builder& b = Build();
|
||||
|
||||
EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
|
||||
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "var"
|
||||
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
|
||||
)");
|
||||
EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 1200
|
||||
)");
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
|
||||
%2 = OpSpecConstantTrue %1
|
||||
%4 = OpTypePointer Input %1
|
||||
%3 = OpVariable %4 Input %2
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(BuilderTest, GlobalVar_ConstantId_Bool_NoConstructor) {
|
||||
auto* v = Global("var", ty.bool_(), ast::StorageClass::kInput, nullptr,
|
||||
TEST_F(BuilderTest, GlobalVar_Override_Bool_NoConstructor) {
|
||||
auto* v = GlobalConst("var", ty.bool_(), nullptr,
|
||||
ast::DecorationList{
|
||||
create<ast::OverrideDecoration>(1200),
|
||||
});
|
||||
|
@ -232,19 +230,17 @@ TEST_F(BuilderTest, GlobalVar_ConstantId_Bool_NoConstructor) {
|
|||
spirv::Builder& b = Build();
|
||||
|
||||
EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
|
||||
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
|
||||
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
|
||||
)");
|
||||
EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %4 SpecId 1200
|
||||
EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 1200
|
||||
)");
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeBool
|
||||
%2 = OpTypePointer Input %3
|
||||
%4 = OpSpecConstantFalse %3
|
||||
%1 = OpVariable %2 Input %4
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
|
||||
%2 = OpSpecConstantFalse %1
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(BuilderTest, GlobalVar_ConstantId_Scalar) {
|
||||
auto* v = Global("var", ty.f32(), ast::StorageClass::kInput, Expr(2.f),
|
||||
TEST_F(BuilderTest, GlobalVar_Override_Scalar) {
|
||||
auto* v = GlobalConst("var", ty.f32(), Expr(2.f),
|
||||
ast::DecorationList{
|
||||
create<ast::OverrideDecoration>(0),
|
||||
});
|
||||
|
@ -252,19 +248,17 @@ TEST_F(BuilderTest, GlobalVar_ConstantId_Scalar) {
|
|||
spirv::Builder& b = Build();
|
||||
|
||||
EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
|
||||
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "var"
|
||||
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
|
||||
)");
|
||||
EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
|
||||
)");
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
|
||||
%2 = OpSpecConstant %1 2
|
||||
%4 = OpTypePointer Input %1
|
||||
%3 = OpVariable %4 Input %2
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(BuilderTest, GlobalVar_ConstantId_Scalar_F32_NoConstructor) {
|
||||
auto* v = Global("var", ty.f32(), ast::StorageClass::kInput, nullptr,
|
||||
TEST_F(BuilderTest, GlobalVar_Override_Scalar_F32_NoConstructor) {
|
||||
auto* v = GlobalConst("var", ty.f32(), nullptr,
|
||||
ast::DecorationList{
|
||||
create<ast::OverrideDecoration>(0),
|
||||
});
|
||||
|
@ -272,19 +266,17 @@ TEST_F(BuilderTest, GlobalVar_ConstantId_Scalar_F32_NoConstructor) {
|
|||
spirv::Builder& b = Build();
|
||||
|
||||
EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
|
||||
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
|
||||
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
|
||||
)");
|
||||
EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %4 SpecId 0
|
||||
EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
|
||||
)");
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
|
||||
%2 = OpTypePointer Input %3
|
||||
%4 = OpSpecConstant %3 0
|
||||
%1 = OpVariable %2 Input %4
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
|
||||
%2 = OpSpecConstant %1 0
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(BuilderTest, GlobalVar_ConstantId_Scalar_I32_NoConstructor) {
|
||||
auto* v = Global("var", ty.i32(), ast::StorageClass::kInput, nullptr,
|
||||
TEST_F(BuilderTest, GlobalVar_Override_Scalar_I32_NoConstructor) {
|
||||
auto* v = GlobalConst("var", ty.i32(), nullptr,
|
||||
ast::DecorationList{
|
||||
create<ast::OverrideDecoration>(0),
|
||||
});
|
||||
|
@ -292,19 +284,17 @@ TEST_F(BuilderTest, GlobalVar_ConstantId_Scalar_I32_NoConstructor) {
|
|||
spirv::Builder& b = Build();
|
||||
|
||||
EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
|
||||
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
|
||||
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
|
||||
)");
|
||||
EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %4 SpecId 0
|
||||
EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
|
||||
)");
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
|
||||
%2 = OpTypePointer Input %3
|
||||
%4 = OpSpecConstant %3 0
|
||||
%1 = OpVariable %2 Input %4
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
|
||||
%2 = OpSpecConstant %1 0
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(BuilderTest, GlobalVar_ConstantId_Scalar_U32_NoConstructor) {
|
||||
auto* v = Global("var", ty.u32(), ast::StorageClass::kInput, nullptr,
|
||||
TEST_F(BuilderTest, GlobalVar_Override_Scalar_U32_NoConstructor) {
|
||||
auto* v = GlobalConst("var", ty.u32(), nullptr,
|
||||
ast::DecorationList{
|
||||
create<ast::OverrideDecoration>(0),
|
||||
});
|
||||
|
@ -312,14 +302,12 @@ TEST_F(BuilderTest, GlobalVar_ConstantId_Scalar_U32_NoConstructor) {
|
|||
spirv::Builder& b = Build();
|
||||
|
||||
EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
|
||||
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
|
||||
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
|
||||
)");
|
||||
EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %4 SpecId 0
|
||||
EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
|
||||
)");
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 0
|
||||
%2 = OpTypePointer Input %3
|
||||
%4 = OpSpecConstant %3 0
|
||||
%1 = OpVariable %2 Input %4
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
|
||||
%2 = OpSpecConstant %1 0
|
||||
)");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue