Perform merge return with single return in loop. (#2714)
Inlining does not inline functions that have a single return that is in a loop. This is because the return cannot be replaced by a branch outside of the loop easily. Merge return knows how to rewrite the function so the return is replaced by a branch.
Fixes #2038.
diff --git a/source/opt/merge_return_pass.cpp b/source/opt/merge_return_pass.cpp
index a12b2ca..0446331 100644
--- a/source/opt/merge_return_pass.cpp
+++ b/source/opt/merge_return_pass.cpp
@@ -36,7 +36,13 @@
ProcessFunction pfn = [&failed, is_shader, this](Function* function) {
std::vector<BasicBlock*> return_blocks = CollectReturnBlocks(function);
if (return_blocks.size() <= 1) {
- return false;
+ if (!is_shader || return_blocks.size() == 0) {
+ return false;
+ }
+ if (context()->GetStructuredCFGAnalysis()->ContainingConstruct(
+ return_blocks[0]->id()) == 0) {
+ return false;
+ }
}
function_ = function;
diff --git a/test/opt/pass_merge_return_test.cpp b/test/opt/pass_merge_return_test.cpp
index 2f2e74a..423e81d 100644
--- a/test/opt/pass_merge_return_test.cpp
+++ b/test/opt/pass_merge_return_test.cpp
@@ -1672,6 +1672,58 @@
SinglePassRunAndMatch<MergeReturnPass>(spirv, true);
}
+TEST_F(MergeReturnPassTest, SingleReturnInLoop) {
+ const std::string predefs =
+ R"(OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpSource ESSL 310
+%void = OpTypeVoid
+%7 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%9 = OpTypeFunction %float
+%float_1 = OpConstant %float 1
+)";
+
+ const std::string caller =
+ R"(
+; CHECK: OpFunction
+; CHECK: OpFunctionEnd
+%main = OpFunction %void None %7
+%22 = OpLabel
+%30 = OpFunctionCall %float %f_
+OpReturn
+OpFunctionEnd
+)";
+
+ const std::string callee =
+ R"(
+; CHECK: OpFunction
+; CHECK: OpLoopMerge [[merge:%\w+]]
+; CHECK: [[merge]] = OpLabel
+; CHECK: OpReturnValue
+; CHECK-NEXT: OpFunctionEnd
+%f_ = OpFunction %float None %9
+%33 = OpLabel
+OpBranch %34
+%34 = OpLabel
+OpLoopMerge %35 %36 None
+OpBranch %37
+%37 = OpLabel
+OpReturnValue %float_1
+%36 = OpLabel
+OpBranch %34
+%35 = OpLabel
+OpUnreachable
+OpFunctionEnd
+)";
+
+ SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+ SinglePassRunAndMatch<MergeReturnPass>(predefs + caller + callee, true);
+}
+
} // namespace
} // namespace opt
} // namespace spvtools