From cb48e79fa5c9799a2f79893215df4b921afa95c5 Mon Sep 17 00:00:00 2001 From: David Neto Date: Tue, 2 Jun 2020 16:48:27 +0000 Subject: [PATCH] [spirv-reader] Support return, return-value Bug: tint:3 Change-Id: Iaaf6ace739ac30e7f9f0bd4ddcef209ab1b71ed8 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/22480 Reviewed-by: dan sinclair --- src/reader/spirv/function.cc | 21 +- src/reader/spirv/function_cfg_test.cc | 235 ++++++++++++++++++ .../spirv/parser_impl_function_decl_test.cc | 16 +- 3 files changed, 268 insertions(+), 4 deletions(-) diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc index d6a25bda31..79bbd0e54d 100644 --- a/src/reader/spirv/function.cc +++ b/src/reader/spirv/function.cc @@ -32,6 +32,7 @@ #include "src/ast/if_statement.h" #include "src/ast/loop_statement.h" #include "src/ast/member_accessor_expression.h" +#include "src/ast/return_statement.h" #include "src/ast/scalar_constructor_expression.h" #include "src/ast/storage_class.h" #include "src/ast/switch_statement.h" @@ -1753,9 +1754,23 @@ bool FunctionEmitter::EmitContinuingStart(const Construct* construct) { return success(); } -bool FunctionEmitter::EmitNormalTerminator(const BlockInfo&) { - // TODO(dneto): emit fallthrough, break, continue, return, kill - return true; +bool FunctionEmitter::EmitNormalTerminator(const BlockInfo& block_info) { + const auto& terminator = *(block_info.basic_block->terminator()); + switch (terminator.opcode()) { + case SpvOpReturn: + AddStatement(std::make_unique()); + return true; + case SpvOpReturnValue: { + auto value = MakeExpression(terminator.GetSingleWordInOperand(0)); + AddStatement( + std::make_unique(std::move(value.expr))); + } + return true; + default: + break; + } + // TODO(dneto): emit fallthrough, break, continue, kill + return success(); } bool FunctionEmitter::EmitStatementsInBasicBlock(const BlockInfo& block_info, diff --git a/src/reader/spirv/function_cfg_test.cc b/src/reader/spirv/function_cfg_test.cc index 14605563d6..58e4502ddb 100644 --- a/src/reader/spirv/function_cfg_test.cc +++ b/src/reader/spirv/function_cfg_test.cc @@ -62,6 +62,8 @@ std::string CommonTypes() { %uint = OpTypeInt 32 0 %selector = OpConstant %uint 42 + %uintfn = OpTypeFunction %uint + %uint_0 = OpConstant %uint 0 %uint_1 = OpConstant %uint 1 %uint_2 = OpConstant %uint 2 @@ -6771,6 +6773,7 @@ Else{ { } } +Return{} )")); } @@ -6820,6 +6823,7 @@ Assignment{ Identifier{var} ScalarConstructor{999} } +Return{} )")); } @@ -6869,6 +6873,7 @@ Assignment{ Identifier{var} ScalarConstructor{999} } +Return{} )")); } @@ -6926,6 +6931,7 @@ Assignment{ Identifier{var} ScalarConstructor{999} } +Return{} )")); } @@ -6994,6 +7000,7 @@ Assignment{ Identifier{var} ScalarConstructor{999} } +Return{} )")); } @@ -7052,6 +7059,7 @@ Assignment{ Identifier{var} ScalarConstructor{999} } +Return{} )")); } @@ -7110,6 +7118,7 @@ Assignment{ Identifier{var} ScalarConstructor{999} } +Return{} )")); } @@ -7223,6 +7232,7 @@ Assignment{ Identifier{var} ScalarConstructor{999} } +Return{} )")); } @@ -7264,6 +7274,7 @@ Assignment{ Identifier{var} ScalarConstructor{999} } +Return{} )")); } @@ -7305,6 +7316,7 @@ Assignment{ Identifier{var} ScalarConstructor{999} } +Return{} )")); } @@ -7345,6 +7357,7 @@ Assignment{ Identifier{var} ScalarConstructor{999} } +Return{} )")); } @@ -7385,6 +7398,7 @@ Assignment{ Identifier{var} ScalarConstructor{999} } +Return{} )")); } @@ -7443,6 +7457,7 @@ Assignment{ Identifier{var} ScalarConstructor{999} } +Return{} )")) << ToString(fe.ast_body()); } @@ -7509,6 +7524,7 @@ Assignment{ Identifier{var} ScalarConstructor{999} } +Return{} )")) << ToString(fe.ast_body()); } @@ -7595,6 +7611,7 @@ Assignment{ Identifier{var} ScalarConstructor{999} } +Return{} )")) << ToString(fe.ast_body()); } @@ -7626,6 +7643,224 @@ TEST_F(SpvParserTest, DISABLED_EmitBody_Loop_BodyConditionallyBreaks) { // TODO(dneto): Needs "break" support } +TEST_F(SpvParserTest, EmitBody_Return_TopLevel) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %100 = OpFunction %void None %voidfn + + %10 = OpLabel + OpReturn + + OpFunctionEnd + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error(); + FunctionEmitter fe(p, *spirv_function(100)); + EXPECT_TRUE(fe.EmitBody()) << p->error(); + + EXPECT_THAT(ToString(fe.ast_body()), Eq(R"(Return{} +)")) << ToString(fe.ast_body()); +} + +TEST_F(SpvParserTest, EmitBody_Return_InsideIf) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %100 = OpFunction %void None %voidfn + + %10 = OpLabel + OpSelectionMerge %99 None + OpBranchConditional %cond %20 %99 + + %20 = OpLabel + OpReturn + + %99 = OpLabel + OpReturn + + OpFunctionEnd + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error(); + FunctionEmitter fe(p, *spirv_function(100)); + EXPECT_TRUE(fe.EmitBody()) << p->error(); + + EXPECT_THAT(ToString(fe.ast_body()), Eq(R"(If{ + ( + ScalarConstructor{false} + ) + { + Return{} + } +} +Else{ + { + } +} +Return{} +)")) << ToString(fe.ast_body()); +} + +TEST_F(SpvParserTest, EmitBody_Return_InsideLoop) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %100 = OpFunction %void None %voidfn + + %10 = OpLabel + OpBranch %20 + + %20 = OpLabel + OpLoopMerge %99 %80 None + OpBranchConditional %cond %30 %30 + + %30 = OpLabel + OpReturn + + %80 = OpLabel + OpBranch %20 + + %99 = OpLabel + OpReturn + + OpFunctionEnd + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error(); + FunctionEmitter fe(p, *spirv_function(100)); + EXPECT_TRUE(fe.EmitBody()) << p->error(); + + EXPECT_THAT(ToString(fe.ast_body()), Eq(R"(Loop{ + Return{} +} +Return{} +)")) << ToString(fe.ast_body()); +} + +TEST_F(SpvParserTest, EmitBody_ReturnValue_TopLevel) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %200 = OpFunction %uint None %uintfn + + %210 = OpLabel + OpReturnValue %uint_2 + + OpFunctionEnd + + %100 = OpFunction %void None %voidfn + + %10 = OpLabel + %11 = OpFunctionCall %uint %200 + OpReturn + + OpFunctionEnd + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error(); + FunctionEmitter fe(p, *spirv_function(200)); + EXPECT_TRUE(fe.EmitBody()) << p->error(); + + EXPECT_THAT(ToString(fe.ast_body()), Eq(R"(Return{ + { + ScalarConstructor{2} + } +} +)")) << ToString(fe.ast_body()); +} + +TEST_F(SpvParserTest, EmitBody_ReturnValue_InsideIf) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %200 = OpFunction %uint None %uintfn + + %210 = OpLabel + OpSelectionMerge %299 None + OpBranchConditional %cond %220 %299 + + %220 = OpLabel + OpReturnValue %uint_2 + + %299 = OpLabel + OpReturnValue %uint_3 + + OpFunctionEnd + + + %100 = OpFunction %void None %voidfn + + %10 = OpLabel + %11 = OpFunctionCall %uint %200 + OpReturn + + OpFunctionEnd + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error(); + FunctionEmitter fe(p, *spirv_function(200)); + EXPECT_TRUE(fe.EmitBody()) << p->error(); + + EXPECT_THAT(ToString(fe.ast_body()), Eq(R"(If{ + ( + ScalarConstructor{false} + ) + { + Return{ + { + ScalarConstructor{2} + } + } + } +} +Else{ + { + } +} +Return{ + { + ScalarConstructor{3} + } +} +)")) << ToString(fe.ast_body()); +} + +TEST_F(SpvParserTest, EmitBody_ReturnValue_Loop) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %200 = OpFunction %void None %voidfn + + %210 = OpLabel + OpBranch %220 + + %220 = OpLabel + OpLoopMerge %299 %280 None + OpBranchConditional %cond %230 %230 + + %230 = OpLabel + OpReturnValue %uint_2 + + %280 = OpLabel + OpBranch %220 + + %299 = OpLabel + OpReturnValue %uint_3 + + OpFunctionEnd + + + %100 = OpFunction %void None %voidfn + + %10 = OpLabel + %11 = OpFunctionCall %uint %200 + OpReturn + + OpFunctionEnd + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error(); + FunctionEmitter fe(p, *spirv_function(200)); + EXPECT_TRUE(fe.EmitBody()) << p->error(); + + EXPECT_THAT(ToString(fe.ast_body()), Eq(R"(Loop{ + Return{ + { + ScalarConstructor{2} + } + } +} +Return{ + { + ScalarConstructor{3} + } +} +)")) << ToString(fe.ast_body()); +} + } // namespace } // namespace spirv } // namespace reader diff --git a/src/reader/spirv/parser_impl_function_decl_test.cc b/src/reader/spirv/parser_impl_function_decl_test.cc index ab6f5abc67..03ef8766da 100644 --- a/src/reader/spirv/parser_impl_function_decl_test.cc +++ b/src/reader/spirv/parser_impl_function_decl_test.cc @@ -107,18 +107,24 @@ TEST_F(SpvParserTest, EmitFunctions_CalleePrecedesCaller) { EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->error().empty()); const auto module_ast = p->module().to_str(); + // TODO(dneto): This will need to be updated when function calls are + // supported. Otherwise, use more general matching instead of substring + // equality. EXPECT_THAT(module_ast, HasSubstr(R"( Function leaf -> __void () { + Return{} } Function branch -> __void () { + Return{} } Function root -> __void () { + Return{} })")); } @@ -138,7 +144,13 @@ TEST_F(SpvParserTest, EmitFunctions_NonVoidResultType) { Function ret_float -> __f32 () { - })")); + Return{ + { + ScalarConstructor{0.000000} + } + } + })")) + << module_ast; } TEST_F(SpvParserTest, EmitFunctions_MixedParamTypes) { @@ -177,6 +189,7 @@ TEST_F(SpvParserTest, EmitFunctions_MixedParamTypes) { } ) { + Return{} })")); } @@ -215,6 +228,7 @@ TEST_F(SpvParserTest, EmitFunctions_GenerateParamNames) { } ) { + Return{} })")); }