spirv-fuzz: Handle OpPhis in TransformationInlineFunction (#3833)

Fixes #3829.
diff --git a/source/fuzz/transformation_inline_function.cpp b/source/fuzz/transformation_inline_function.cpp
index f244f0d..dfa66f8 100644
--- a/source/fuzz/transformation_inline_function.cpp
+++ b/source/fuzz/transformation_inline_function.cpp
@@ -211,31 +211,46 @@
   const auto result_id_map =
       fuzzerutil::RepeatedUInt32PairToMap(message_.result_id_map());
 
-  // Replaces the operand ids with their mapped result ids.
-  instruction_to_be_inlined->ForEachInId([called_function,
-                                          function_call_instruction,
-                                          &result_id_map](uint32_t* id) {
-    // If |id| is mapped, then set it to its mapped value.
-    if (result_id_map.count(*id)) {
-      *id = result_id_map.at(*id);
-      return;
-    }
+  const auto* function_call_block =
+      ir_context->get_instr_block(function_call_instruction);
+  assert(function_call_block && "OpFunctionCall must belong to some block");
 
-    uint32_t parameter_index = 0;
-    called_function->ForEachParam(
-        [id, function_call_instruction,
-         &parameter_index](opt::Instruction* parameter_instruction) {
-          // If the id is a function parameter, then set it to the
-          // parameter value passed in the function call instruction.
-          if (*id == parameter_instruction->result_id()) {
-            // We do + 1 because the first in-operand for OpFunctionCall is
-            // the function id that is being called.
-            *id = function_call_instruction->GetSingleWordInOperand(
-                parameter_index + 1);
-          }
-          parameter_index++;
-        });
-  });
+  // Replaces the operand ids with their mapped result ids.
+  instruction_to_be_inlined->ForEachInId(
+      [called_function, function_call_instruction, &result_id_map,
+       function_call_block](uint32_t* id) {
+        // We are not inlining the entry block of the |called_function|.
+        //
+        // We must check this condition first since we can't use the fresh id
+        // from |result_id_map| even if it has one. This is because that fresh
+        // id will never be added to the module since entry blocks are not
+        // inlined.
+        if (*id == called_function->entry()->id()) {
+          *id = function_call_block->id();
+          return;
+        }
+
+        // If |id| is mapped, then set it to its mapped value.
+        if (result_id_map.count(*id)) {
+          *id = result_id_map.at(*id);
+          return;
+        }
+
+        uint32_t parameter_index = 0;
+        called_function->ForEachParam(
+            [id, function_call_instruction,
+             &parameter_index](opt::Instruction* parameter_instruction) {
+              // If the id is a function parameter, then set it to the
+              // parameter value passed in the function call instruction.
+              if (*id == parameter_instruction->result_id()) {
+                // We do + 1 because the first in-operand for OpFunctionCall is
+                // the function id that is being called.
+                *id = function_call_instruction->GetSingleWordInOperand(
+                    parameter_index + 1);
+              }
+              parameter_index++;
+            });
+      });
 
   // If |instruction_to_be_inlined| has result id, then set it to its mapped
   // value.
diff --git a/test/fuzz/transformation_inline_function_test.cpp b/test/fuzz/transformation_inline_function_test.cpp
index 694f19c..1d3b049 100644
--- a/test/fuzz/transformation_inline_function_test.cpp
+++ b/test/fuzz/transformation_inline_function_test.cpp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include "source/fuzz/transformation_inline_function.h"
+
 #include "source/fuzz/instruction_descriptor.h"
 #include "test/fuzz/fuzz_test_util.h"
 
@@ -751,6 +752,81 @@
   ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
 }
 
+TEST(TransformationInlineFunctionTest, HandlesOpPhisInTheSecondBlock) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %10 = OpTypeInt 32 0
+         %11 = OpUndef %10
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %6 = OpFunctionCall %2 %7
+               OpBranch %14
+         %14 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %7 = OpFunction %2 None %3
+          %8 = OpLabel
+               OpBranch %13
+         %13 = OpLabel
+         %12 = OpPhi %10 %11 %8
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_3;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  ASSERT_TRUE(IsValid(env, context.get()));
+
+  FactManager fact_manager;
+  spvtools::ValidatorOptions validator_options;
+  TransformationContext transformation_context(&fact_manager,
+                                               validator_options);
+
+  TransformationInlineFunction transformation(6,
+                                              {{{8, 20}, {13, 21}, {12, 22}}});
+  ASSERT_TRUE(
+      transformation.IsApplicable(context.get(), transformation_context));
+  transformation.Apply(context.get(), &transformation_context);
+  ASSERT_TRUE(IsValid(env, context.get()));
+
+  std::string after_transformation = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %10 = OpTypeInt 32 0
+         %11 = OpUndef %10
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+               OpBranch %21
+         %21 = OpLabel
+         %22 = OpPhi %10 %11 %5
+               OpBranch %14
+         %14 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %7 = OpFunction %2 None %3
+          %8 = OpLabel
+               OpBranch %13
+         %13 = OpLabel
+         %12 = OpPhi %10 %11 %8
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
 }  // namespace
 }  // namespace fuzz
 }  // namespace spvtools