[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 <dsinclair@google.com>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 399ed3f..e3ef474 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -1772,10 +1772,24 @@
// TODO(dneto): https://github.com/gpuweb/gpuweb/issues/676
AddStatement(std::make_unique<ast::KillStatement>());
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<ast::ReturnStatement>());
+ } else {
+ auto* ast_type = parser_impl_.ConvertType(function_.type_id());
+ AddStatement(std::make_unique<ast::ReturnStatement>(
+ 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 1f05bbc..b9bc306 100644
--- a/src/reader/spirv/function_cfg_test.cc
+++ b/src/reader/spirv/function_cfg_test.cc
@@ -7947,6 +7947,121 @@
)")) << 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