spirv-fuzz: Fix to TransformationDuplicateRegionWithSelection (#3941)

Also incorporates a few style fixes.

Fixes #3940.
diff --git a/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.cpp b/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.cpp
index db83daf..1651a9d 100644
--- a/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.cpp
+++ b/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.cpp
@@ -124,9 +124,8 @@
         TransformationDuplicateRegionWithSelection(
             GetFuzzerContext()->GetFreshId(), condition_id,
             GetFuzzerContext()->GetFreshId(), entry_block->id(),
-            exit_block->id(), std::move(original_label_to_duplicate_label),
-            std::move(original_id_to_duplicate_id),
-            std::move(original_id_to_phi_id));
+            exit_block->id(), original_label_to_duplicate_label,
+            original_id_to_duplicate_id, original_id_to_phi_id);
     MaybeApplyTransformation(transformation);
   }
 }
diff --git a/source/fuzz/transformation_duplicate_region_with_selection.cpp b/source/fuzz/transformation_duplicate_region_with_selection.cpp
index 2bce558..ba701a1 100644
--- a/source/fuzz/transformation_duplicate_region_with_selection.cpp
+++ b/source/fuzz/transformation_duplicate_region_with_selection.cpp
@@ -589,6 +589,21 @@
         }
       });
 
+  opt::Instruction* merge_block_terminator = merge_block->terminator();
+  switch (merge_block_terminator->opcode()) {
+    case SpvOpReturnValue:
+    case SpvOpBranchConditional: {
+      uint32_t operand = merge_block_terminator->GetSingleWordInOperand(0);
+      if (original_id_to_phi_id.count(operand)) {
+        merge_block_terminator->SetInOperand(
+            0, {original_id_to_phi_id.at(operand)});
+      }
+      break;
+    }
+    default:
+      break;
+  }
+
   // Insert the merge block after the |duplicated_exit_block| (the
   // last duplicated block).
   enclosing_function->InsertBasicBlockAfter(std::move(merge_block),
diff --git a/source/fuzz/transformation_merge_function_returns.cpp b/source/fuzz/transformation_merge_function_returns.cpp
index bdaec04..c693444 100644
--- a/source/fuzz/transformation_merge_function_returns.cpp
+++ b/source/fuzz/transformation_merge_function_returns.cpp
@@ -509,7 +509,7 @@
           {SPV_OPERAND_TYPE_LOOP_CONTROL, {SpvLoopControlMaskNone}}}));
 
   // Add conditional branch:
-  // 	OpBranchConditional %true %block_after_entry %outer_header_id
+  //   OpBranchConditional %true %block_after_entry %outer_header_id
   // This will always branch to %block_after_entry, but it also creates a back
   // edge for the loop (which is never traversed).
   outer_loop_header->AddInstruction(MakeUnique<opt::Instruction>(
diff --git a/test/fuzz/fuzzer_replayer_test.cpp b/test/fuzz/fuzzer_replayer_test.cpp
index 43bc0b5..dc90574 100644
--- a/test/fuzz/fuzzer_replayer_test.cpp
+++ b/test/fuzz/fuzzer_replayer_test.cpp
@@ -1590,7 +1590,7 @@
           %2 = OpFunction %132 None %133
         %164 = OpLabel
         %184 = OpLoad %15 %40
-	%213 = OpLoad %38 %41
+        %213 = OpLoad %38 %41
         %216 = OpSampledImage %45 %184 %213
         %217 = OpImageSampleImplicitLod %76 %216 %112 Bias %55
                OpReturn
diff --git a/test/fuzz/transformation_compute_data_synonym_fact_closure_test.cpp b/test/fuzz/transformation_compute_data_synonym_fact_closure_test.cpp
index 7a36c5c..995b260 100644
--- a/test/fuzz/transformation_compute_data_synonym_fact_closure_test.cpp
+++ b/test/fuzz/transformation_compute_data_synonym_fact_closure_test.cpp
@@ -45,7 +45,7 @@
   // void main() {
   //   T myT = T(bool[5](true, false, true, false, true),
   //             mat4x2(vec2(1.0, 2.0), vec2(3.0, 4.0),
-  // 	           vec2(5.0, 6.0), vec2(7.0, 8.0)),
+  //                    vec2(5.0, 6.0), vec2(7.0, 8.0)),
   //             S(10, uvec2(100u, 200u)));
   // }
 
diff --git a/test/fuzz/transformation_duplicate_region_with_selection_test.cpp b/test/fuzz/transformation_duplicate_region_with_selection_test.cpp
index 98b81f8..d4850ce 100644
--- a/test/fuzz/transformation_duplicate_region_with_selection_test.cpp
+++ b/test/fuzz/transformation_duplicate_region_with_selection_test.cpp
@@ -1904,7 +1904,7 @@
           %9 = OpConstant %6 0
          %16 = OpConstant %6 100
          %17 = OpTypeBool
-	 %50 = OpConstantTrue %17
+         %50 = OpConstantTrue %17
          %20 = OpConstant %6 1
           %4 = OpFunction %2 None %3
           %5 = OpLabel
@@ -1971,7 +1971,7 @@
           %9 = OpConstant %6 0
          %16 = OpConstant %6 100
          %17 = OpTypeBool
-	 %50 = OpConstantTrue %17
+         %50 = OpConstantTrue %17
          %20 = OpConstant %6 1
           %4 = OpFunction %2 None %3
           %5 = OpLabel
@@ -2015,6 +2015,230 @@
   ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
 }
 
+TEST(TransformationDuplicateRegionWithSelectionTest,
+     RegionExitIsOpBranchConditionalUsingBooleanDefinedInBlock) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+               OpName %4 "main"
+               OpName %8 "i"
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypePointer Function %6
+          %9 = OpConstant %6 0
+         %16 = OpConstant %6 100
+         %17 = OpTypeBool
+         %50 = OpConstantTrue %17
+         %20 = OpConstant %6 1
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+               OpStore %8 %9
+               OpBranch %10
+         %10 = OpLabel
+               OpLoopMerge %12 %13 None
+               OpBranch %14
+         %14 = OpLabel
+         %15 = OpLoad %6 %8
+         %18 = OpSLessThan %17 %15 %16
+               OpBranchConditional %18 %11 %12
+         %11 = OpLabel
+         %19 = OpLoad %6 %8
+         %21 = OpIAdd %6 %19 %20
+         %70 = OpCopyObject %17 %50
+               OpStore %8 %21
+               OpBranchConditional %70 %13 %12
+         %13 = OpLabel
+         %22 = OpLoad %6 %8
+         %23 = OpIAdd %6 %22 %20
+               OpStore %8 %23
+               OpBranch %10
+         %12 = OpLabel
+               OpReturn
+               OpFunctionEnd
+         )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  TransformationDuplicateRegionWithSelection transformation_good_1 =
+      TransformationDuplicateRegionWithSelection(
+          600, 50, 601, 11, 11, {{11, 602}}, {{19, 603}, {21, 604}, {70, 608}},
+          {{19, 605}, {21, 606}, {70, 607}});
+  ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
+                                                 transformation_context));
+  ApplyAndCheckFreshIds(transformation_good_1, context.get(),
+                        &transformation_context);
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  std::string expected_shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+               OpName %4 "main"
+               OpName %8 "i"
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypePointer Function %6
+          %9 = OpConstant %6 0
+         %16 = OpConstant %6 100
+         %17 = OpTypeBool
+         %50 = OpConstantTrue %17
+         %20 = OpConstant %6 1
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+               OpStore %8 %9
+               OpBranch %10
+         %10 = OpLabel
+               OpLoopMerge %12 %13 None
+               OpBranch %14
+         %14 = OpLabel
+         %15 = OpLoad %6 %8
+         %18 = OpSLessThan %17 %15 %16
+               OpBranchConditional %18 %600 %12
+        %600 = OpLabel
+               OpSelectionMerge %601 None
+               OpBranchConditional %50 %11 %602
+         %11 = OpLabel
+         %19 = OpLoad %6 %8
+         %21 = OpIAdd %6 %19 %20
+         %70 = OpCopyObject %17 %50
+               OpStore %8 %21
+               OpBranch %601
+        %602 = OpLabel
+        %603 = OpLoad %6 %8
+        %604 = OpIAdd %6 %603 %20
+        %608 = OpCopyObject %17 %50
+               OpStore %8 %604
+               OpBranch %601
+        %601 = OpLabel
+        %605 = OpPhi %6 %19 %11 %603 %602
+        %606 = OpPhi %6 %21 %11 %604 %602
+        %607 = OpPhi %17 %70 %11 %608 %602
+               OpBranchConditional %607 %13 %12
+         %13 = OpLabel
+         %22 = OpLoad %6 %8
+         %23 = OpIAdd %6 %22 %20
+               OpStore %8 %23
+               OpBranch %10
+         %12 = OpLabel
+               OpReturn
+               OpFunctionEnd
+        )";
+
+  ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
+}
+
+TEST(TransformationDuplicateRegionWithSelectionTest,
+     RegionExitUsesOpReturnValueWithIdDefinedInRegion) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeFunction %6
+         %10 = OpConstant %6 2
+         %30 = OpTypeBool
+         %31 = OpConstantTrue %30
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %13 = OpFunctionCall %6 %8
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %6 None %7
+          %9 = OpLabel
+               OpBranch %20
+         %20 = OpLabel
+         %21 = OpCopyObject %6 %10
+               OpReturnValue %21
+               OpFunctionEnd
+         )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  spvtools::ValidatorOptions validator_options;
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  TransformationDuplicateRegionWithSelection transformation_good_1 =
+      TransformationDuplicateRegionWithSelection(
+          600, 31, 601, 20, 20, {{20, 602}}, {{21, 603}}, {{21, 605}});
+  ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
+                                                 transformation_context));
+  ApplyAndCheckFreshIds(transformation_good_1, context.get(),
+                        &transformation_context);
+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+                                               kConsoleMessageConsumer));
+
+  std::string expected_shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeFunction %6
+         %10 = OpConstant %6 2
+         %30 = OpTypeBool
+         %31 = OpConstantTrue %30
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %13 = OpFunctionCall %6 %8
+               OpReturn
+               OpFunctionEnd
+          %8 = OpFunction %6 None %7
+          %9 = OpLabel
+               OpBranch %600
+        %600 = OpLabel
+               OpSelectionMerge %601 None
+               OpBranchConditional %31 %20 %602
+         %20 = OpLabel
+         %21 = OpCopyObject %6 %10
+               OpBranch %601
+        %602 = OpLabel
+        %603 = OpCopyObject %6 %10
+               OpBranch %601
+        %601 = OpLabel
+        %605 = OpPhi %6 %21 %20 %603 %602
+               OpReturnValue %605
+               OpFunctionEnd
+        )";
+
+  ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
+}
+
 }  // namespace
 }  // namespace fuzz
 }  // namespace spvtools