From 1649dfadd714c76e655bb2e6e4f8298c2bebab1a Mon Sep 17 00:00:00 2001 From: David Neto Date: Tue, 2 Jun 2020 19:56:07 +0000 Subject: [PATCH] [spirv-reader] Support unreachable, as a return Bug: tint:3 Change-Id: Ia1384f84f7851a9e155c1536a624213ef51ee0a1 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/22521 Reviewed-by: dan sinclair --- src/reader/spirv/function.cc | 16 +++- src/reader/spirv/function_cfg_test.cc | 115 ++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 1 deletion(-) diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc index 399ed3f514..e3ef47426d 100644 --- a/src/reader/spirv/function.cc +++ b/src/reader/spirv/function.cc @@ -1772,10 +1772,24 @@ bool FunctionEmitter::EmitNormalTerminator(const BlockInfo& block_info) { // TODO(dneto): https://github.com/gpuweb/gpuweb/issues/676 AddStatement(std::make_unique()); return true; + case SpvOpUnreachable: + // Translate as if it's a return. This avoids the problem where WGSL + // requires a return statement at the end of the function body. + { + const auto* result_type = type_mgr_->GetType(function_.type_id()); + if (result_type->AsVoid() != nullptr) { + AddStatement(std::make_unique()); + } else { + auto* ast_type = parser_impl_.ConvertType(function_.type_id()); + AddStatement(std::make_unique( + parser_impl_.MakeNullValue(ast_type))); + } + } + return true; default: break; } - // TODO(dneto): emit fallthrough, break, continue, kill + // TODO(dneto): emit fallthrough, break, continue return success(); } diff --git a/src/reader/spirv/function_cfg_test.cc b/src/reader/spirv/function_cfg_test.cc index 1f05bbc0ef..b9bc306d45 100644 --- a/src/reader/spirv/function_cfg_test.cc +++ b/src/reader/spirv/function_cfg_test.cc @@ -7947,6 +7947,121 @@ Kill{} )")) << ToString(fe.ast_body()); } +TEST_F(SpvParserTest, EmitBody_Unreachable_TopLevel) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %100 = OpFunction %void None %voidfn + + %10 = OpLabel + OpUnreachable + + 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_Unreachable_InsideIf) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %100 = OpFunction %void None %voidfn + + %10 = OpLabel + OpSelectionMerge %99 None + OpBranchConditional %cond %20 %99 + + %20 = OpLabel + OpUnreachable + + %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_Unreachable_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 + OpUnreachable + + %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_Unreachable_InNonVoidFunction) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %200 = OpFunction %uint None %uintfn + + %210 = OpLabel + OpUnreachable + + 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{0} + } +} +)")) << ToString(fe.ast_body()); +} + } // namespace } // namespace spirv } // namespace reader