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