spirv-fuzz: Skip early terminator wrappers when merging returns (#3968)

Fixes #3955.
diff --git a/source/fuzz/fuzzer_pass_merge_function_returns.cpp b/source/fuzz/fuzzer_pass_merge_function_returns.cpp
index 4bcedb8..fc9c74d 100644
--- a/source/fuzz/fuzzer_pass_merge_function_returns.cpp
+++ b/source/fuzz/fuzzer_pass_merge_function_returns.cpp
@@ -48,6 +48,12 @@
       continue;
     }
 
+    // We skip wrappers for early terminators, since this fuzzer pass introduces
+    // such wrappers to eliminate early terminators.
+    if (IsEarlyTerminatorWrapper(*function)) {
+      continue;
+    }
+
     // Only consider functions that have early returns.
     if (!function->HasEarlyReturn()) {
       continue;
@@ -316,5 +322,16 @@
   return result;
 }
 
+bool FuzzerPassMergeFunctionReturns::IsEarlyTerminatorWrapper(
+    const opt::Function& function) const {
+  for (SpvOp opcode : {SpvOpKill, SpvOpUnreachable, SpvOpTerminateInvocation}) {
+    if (TransformationWrapEarlyTerminatorInFunction::MaybeGetWrapperFunction(
+            GetIRContext(), opcode) == &function) {
+      return true;
+    }
+  }
+  return false;
+}
+
 }  // namespace fuzz
 }  // namespace spvtools
diff --git a/source/fuzz/fuzzer_pass_merge_function_returns.h b/source/fuzz/fuzzer_pass_merge_function_returns.h
index 2d79905..3b5a668 100644
--- a/source/fuzz/fuzzer_pass_merge_function_returns.h
+++ b/source/fuzz/fuzzer_pass_merge_function_returns.h
@@ -58,6 +58,10 @@
       const std::vector<uint32_t>& merge_blocks,
       std::map<uint32_t, std::vector<uint32_t>>*
           ids_available_after_entry_block);
+
+  // Returns true if and only if |function| is a wrapper for an early terminator
+  // instruction such as OpKill.
+  bool IsEarlyTerminatorWrapper(const opt::Function& function) const;
 };
 }  // namespace fuzz
 }  // namespace spvtools