spirv-fuzz: Do not allow sampled image load when flattening conditionals (#3930)

Fixes #3928.
diff --git a/source/fuzz/transformation_flatten_conditional_branch.cpp b/source/fuzz/transformation_flatten_conditional_branch.cpp
index 7fc636a..86a0313 100644
--- a/source/fuzz/transformation_flatten_conditional_branch.cpp
+++ b/source/fuzz/transformation_flatten_conditional_branch.cpp
@@ -699,6 +699,15 @@
     return false;
   }
 
+  // We cannot handle a sampled image load, because we re-work loads using
+  // conditional branches and OpPhi instructions, and the result type of OpPhi
+  // cannot be OpTypeSampledImage.
+  if (instruction.opcode() == SpvOpLoad &&
+      ir_context->get_def_use_mgr()->GetDef(instruction.type_id())->opcode() ==
+          SpvOpTypeSampledImage) {
+    return false;
+  }
+
   // We cannot handle instructions with an id which return a void type, if the
   // result id is used in the module (e.g. a function call to a function that
   // returns nothing).
diff --git a/test/fuzz/transformation_flatten_conditional_branch_test.cpp b/test/fuzz/transformation_flatten_conditional_branch_test.cpp
index fddfdaf..ba34933 100644
--- a/test/fuzz/transformation_flatten_conditional_branch_test.cpp
+++ b/test/fuzz/transformation_flatten_conditional_branch_test.cpp
@@ -1233,6 +1233,70 @@
                                                kConsoleMessageConsumer));
 }
 
+TEST(TransformationFlattenConditionalBranchTest, InapplicableSampledImageLoad) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main" %12 %96
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+               OpDecorate %12 BuiltIn FragCoord
+               OpDecorate %91 DescriptorSet 0
+               OpDecorate %91 Binding 0
+               OpDecorate %96 Location 0
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 2
+         %10 = OpTypeVector %6 4
+         %11 = OpTypePointer Input %10
+         %12 = OpVariable %11 Input
+         %21 = OpConstant %6 2
+         %24 = OpTypeInt 32 1
+         %33 = OpTypeBool
+         %35 = OpConstantTrue %33
+         %88 = OpTypeImage %6 2D 0 0 0 1 Unknown
+         %89 = OpTypeSampledImage %88
+         %90 = OpTypePointer UniformConstant %89
+         %91 = OpVariable %90 UniformConstant
+         %95 = OpTypePointer Output %10
+         %96 = OpVariable %95 Output
+        %200 = OpUndef %89
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+               OpBranch %28
+         %28 = OpLabel
+               OpSelectionMerge %38 None
+               OpBranchConditional %35 %32 %37
+         %32 = OpLabel
+         %40 = OpLoad %89 %91
+               OpBranch %38
+         %37 = OpLabel
+               OpBranch %38
+         %38 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_3;
+  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_FALSE(TransformationFlattenConditionalBranch(
+                   28, true,
+                   {MakeSideEffectWrapperInfo(
+                       MakeInstructionDescriptor(40, SpvOpLoad, 0), 100, 101,
+                       102, 103, 104, 200)})
+                   .IsApplicable(context.get(), transformation_context));
+}
+
 }  // namespace
 }  // namespace fuzz
 }  // namespace spvtools