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