spirv-reader: handle OpUndef at module scope
Fixed: tint:523
Change-Id: I47639c8f701ca049c7215874cdea27f86d8a415b
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/43760
Auto-Submit: David Neto <dneto@google.com>
Commit-Queue: David Neto <dneto@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index e9f0494..663d5cd 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -2091,6 +2091,13 @@
create<ast::IdentifierExpression>(
Source{}, builder_.Symbols().Register(name))};
}
+ case SpvOpUndef:
+ // Substitute a null value for undef.
+ // This case occurs when OpUndef appears at module scope, as if it were
+ // a constant.
+ return parser_impl_.MakeNullExpression(
+ parser_impl_.ConvertType(inst->type_id()));
+
default:
break;
}
@@ -3294,7 +3301,7 @@
if (opcode == SpvOpUndef) {
// Replace undef with the null value.
- return {ast_type, parser_impl_.MakeNullValue(ast_type)};
+ return parser_impl_.MakeNullExpression(ast_type);
}
if (opcode == SpvOpSelect) {
diff --git a/src/reader/spirv/function_misc_test.cc b/src/reader/spirv/function_misc_test.cc
index 4971866..8cf1b36 100644
--- a/src/reader/spirv/function_misc_test.cc
+++ b/src/reader/spirv/function_misc_test.cc
@@ -40,6 +40,7 @@
%int = OpTypeInt 32 1
%float = OpTypeFloat 32
+ %v2bool = OpTypeVector %bool 2
%v2uint = OpTypeVector %uint 2
%v2int = OpTypeVector %int 2
%v2float = OpTypeVector %float 2
@@ -48,6 +49,149 @@
using SpvParserTestMiscInstruction = SpvParserTest;
+TEST_F(SpvParserTestMiscInstruction, OpUndef_BeforeFunction_Scalar) {
+ const auto assembly = CommonTypes() + R"(
+ %1 = OpUndef %bool
+ %2 = OpUndef %uint
+ %3 = OpUndef %int
+ %4 = OpUndef %float
+
+ %100 = OpFunction %void None %voidfn
+ %entry = OpLabel
+ %11 = OpCopyObject %bool %1
+ %12 = OpCopyObject %uint %2
+ %13 = OpCopyObject %int %3
+ %14 = OpCopyObject %float %4
+ OpReturn
+ OpFunctionEnd
+)";
+ auto p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+ FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ EXPECT_THAT(ToString(p->builder(), fe.ast_body()),
+ HasSubstr(R"(VariableDeclStatement{
+ VariableConst{
+ x_11
+ none
+ __bool
+ {
+ ScalarConstructor[not set]{false}
+ }
+ }
+}
+VariableDeclStatement{
+ VariableConst{
+ x_12
+ none
+ __u32
+ {
+ ScalarConstructor[not set]{0}
+ }
+ }
+}
+VariableDeclStatement{
+ VariableConst{
+ x_13
+ none
+ __i32
+ {
+ ScalarConstructor[not set]{0}
+ }
+ }
+}
+VariableDeclStatement{
+ VariableConst{
+ x_14
+ none
+ __f32
+ {
+ ScalarConstructor[not set]{0.000000}
+ }
+ }
+})")) << ToString(p->builder(), fe.ast_body());
+}
+
+TEST_F(SpvParserTestMiscInstruction, OpUndef_BeforeFunction_Vector) {
+ const auto assembly = CommonTypes() + R"(
+ %4 = OpUndef %v2bool
+ %1 = OpUndef %v2uint
+ %2 = OpUndef %v2int
+ %3 = OpUndef %v2float
+
+ %100 = OpFunction %void None %voidfn
+ %entry = OpLabel
+
+ %14 = OpCopyObject %v2uint %4
+ %11 = OpCopyObject %v2uint %1
+ %12 = OpCopyObject %v2int %2
+ %13 = OpCopyObject %v2float %3
+ OpReturn
+ OpFunctionEnd
+)";
+ auto p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+ FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ EXPECT_THAT(ToString(p->builder(), fe.ast_body()),
+ HasSubstr(R"(VariableDeclStatement{
+ VariableConst{
+ x_14
+ none
+ __vec_2__bool
+ {
+ TypeConstructor[not set]{
+ __vec_2__bool
+ ScalarConstructor[not set]{false}
+ ScalarConstructor[not set]{false}
+ }
+ }
+ }
+}
+VariableDeclStatement{
+ VariableConst{
+ x_11
+ none
+ __vec_2__u32
+ {
+ TypeConstructor[not set]{
+ __vec_2__u32
+ ScalarConstructor[not set]{0}
+ ScalarConstructor[not set]{0}
+ }
+ }
+ }
+}
+VariableDeclStatement{
+ VariableConst{
+ x_12
+ none
+ __vec_2__i32
+ {
+ TypeConstructor[not set]{
+ __vec_2__i32
+ ScalarConstructor[not set]{0}
+ ScalarConstructor[not set]{0}
+ }
+ }
+ }
+}
+VariableDeclStatement{
+ VariableConst{
+ x_13
+ none
+ __vec_2__f32
+ {
+ TypeConstructor[not set]{
+ __vec_2__f32
+ ScalarConstructor[not set]{0.000000}
+ ScalarConstructor[not set]{0.000000}
+ }
+ }
+ }
+})")) << ToString(p->builder(), fe.ast_body());
+}
+
TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Scalar) {
const auto assembly = CommonTypes() + R"(
%100 = OpFunction %void None %voidfn
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index 5d7af74..9a2855f 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -1538,6 +1538,10 @@
return nullptr;
}
+TypedExpression ParserImpl::MakeNullExpression(type::Type* type) {
+ return {type, MakeNullValue(type)};
+}
+
TypedExpression ParserImpl::RectifyOperandSignedness(
const spvtools::opt::Instruction& inst,
TypedExpression&& expr) {
diff --git a/src/reader/spirv/parser_impl.h b/src/reader/spirv/parser_impl.h
index a023a3c..cdfa256 100644
--- a/src/reader/spirv/parser_impl.h
+++ b/src/reader/spirv/parser_impl.h
@@ -326,6 +326,11 @@
/// @returns a new expression
ast::Expression* MakeNullValue(type::Type* type);
+ /// Make a typed expression for the null value for the given type.
+ /// @param type the AST type
+ /// @returns a new typed expression
+ TypedExpression MakeNullExpression(type::Type* type);
+
/// Converts a given expression to the signedness demanded for an operand
/// of the given SPIR-V instruction, if required. If the instruction assumes
/// signed integer operands, and `expr` is unsigned, then return an