<NME> transformation_replace_params_with_struct_test.cpp
<BEF> // Copyright (c) 2020 Vasyl Teliman
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "source/fuzz/transformation_replace_params_with_struct.h"

#include "gtest/gtest.h"
#include "source/fuzz/fuzzer_util.h"
#include "test/fuzz/fuzz_test_util.h"

namespace spvtools {
namespace fuzz {
namespace {

TEST(TransformationReplaceParamsWithStructTest, BasicTest) {
  std::string shader = R"(
               OpCapability Shader
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Fragment %4 "main"
               OpExecutionMode %4 OriginUpperLeft
               OpSource ESSL 310
               OpMemberDecorate %13 0 RelaxedPrecision
               OpDecorate %16 RelaxedPrecision
          %2 = OpTypeVoid
          %6 = OpTypeInt 32 1
          %3 = OpTypeFunction %2
          %7 = OpTypePointer Private %6
          %8 = OpTypeFloat 32
          %9 = OpTypePointer Private %8
         %10 = OpTypeVector %8 2
         %11 = OpTypePointer Private %10
         %12 = OpTypeBool
         %51 = OpTypeFunction %2 %12
         %64 = OpTypeStruct %6
         %63 = OpTypeFunction %2 %64
         %65 = OpTypeFunction %2 %6
         %75 = OpTypeStruct %8
         %76 = OpTypeFunction %2 %75
         %77 = OpTypeFunction %2 %8
         %40 = OpTypePointer Function %12
         %13 = OpTypeStruct %6 %8
         %45 = OpTypeStruct %6 %10 %13
         %46 = OpTypeStruct %12
         %47 = OpTypeStruct %8 %45 %46
         %14 = OpTypePointer Private %13
         %15 = OpTypeFunction %2 %6 %8 %10 %13 %40 %12
         %22 = OpConstant %6 0
         %23 = OpConstant %8 0
         %26 = OpConstantComposite %10 %23 %23
         %27 = OpConstantTrue %12
         %28 = OpConstantComposite %13 %22 %23
          %4 = OpFunction %2 None %3
          %5 = OpLabel
         %41 = OpVariable %40 Function %27
         %33 = OpFunctionCall %2 %20 %22 %23 %26 %28 %41 %27
               OpReturn
               OpFunctionEnd

         ; adjust type of the function in-place
         %20 = OpFunction %2 None %15
         %16 = OpFunctionParameter %6
         %17 = OpFunctionParameter %8
         %18 = OpFunctionParameter %10
         %19 = OpFunctionParameter %13
         %42 = OpFunctionParameter %40
         %43 = OpFunctionParameter %12
         %21 = OpLabel
               OpReturn
               OpFunctionEnd

         ; create a new function type
         %50 = OpFunction %2 None %51
         %52 = OpFunctionParameter %12
         %53 = OpLabel
               OpReturn
               OpFunctionEnd
         %54 = OpFunction %2 None %51
         %55 = OpFunctionParameter %12
         %56 = OpLabel
               OpReturn
               OpFunctionEnd

         ; reuse an existing function type
         %57 = OpFunction %2 None %63
         %58 = OpFunctionParameter %64
         %59 = OpLabel
               OpReturn
               OpFunctionEnd
         %60 = OpFunction %2 None %65
         %61 = OpFunctionParameter %6
         %62 = OpLabel
               OpReturn
               OpFunctionEnd
         %66 = OpFunction %2 None %65
         %67 = OpFunctionParameter %6
         %68 = OpLabel
               OpReturn
               OpFunctionEnd

         ; don't adjust the type of the function if it creates a duplicate
         %69 = OpFunction %2 None %76
         %70 = OpFunctionParameter %75
         %71 = OpLabel
               OpReturn
               OpFunctionEnd
         %72 = OpFunction %2 None %77
         %73 = OpFunctionParameter %8
         %74 = 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);
  // |parameter_id| is empty.
  ASSERT_FALSE(
      TransformationReplaceParamsWithStruct({}, 90, 91, {{33, 92}, {90, 93}})
          .IsApplicable(context.get(), transformation_context));

  // |parameter_id| has duplicates.
  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 16, 17}, 90, 91,
                                                     {{33, 92}, {90, 93}})
                   .IsApplicable(context.get(), transformation_context));

  // |parameter_id| has invalid values.
  ASSERT_FALSE(TransformationReplaceParamsWithStruct({21, 16, 17}, 90, 91,
                                                     {{33, 92}, {90, 93}})
                   .IsApplicable(context.get(), transformation_context));
  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 90, 17}, 90, 91,
                                                     {{33, 92}, {90, 93}})
                   .IsApplicable(context.get(), transformation_context));

  // Parameter's belong to different functions.
  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17, 52}, 90, 91,
                                                     {{33, 92}, {90, 93}})
                   .IsApplicable(context.get(), transformation_context));

  // Parameter has unsupported type.
  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17, 42, 43}, 90, 91,
                                                     {{33, 92}, {90, 93}})
                   .IsApplicable(context.get(), transformation_context));

  // OpTypeStruct does not exist in the module.
  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 43}, 90, 91,
                                                     {{33, 92}, {90, 93}})
                   .IsApplicable(context.get(), transformation_context));

  // |caller_id_to_fresh_composite_id| misses values.
  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 91,
                                                     {{33, 92}, {90, 93}})
                   .IsApplicable(context.get(), transformation_context));

  // All fresh ids must be unique.
  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 90,
                                                     {{33, 92}, {90, 93}})
                   .IsApplicable(context.get(), transformation_context));
  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 91,
                                                     {{33, 90}, {90, 93}})
                   .IsApplicable(context.get(), transformation_context));
  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 91,
                                                     {{33, 92}, {90, 92}})
                   .IsApplicable(context.get(), transformation_context));

  // All 'fresh' ids must be fresh.
  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 91,
                                                     {{33, 33}, {90, 93}})
                   .IsApplicable(context.get(), transformation_context));
  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 33, 91,
                                                     {{33, 92}, {90, 93}})
                   .IsApplicable(context.get(), transformation_context));
  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 33,
                                                     {{33, 92}, {90, 93}})
                   .IsApplicable(context.get(), transformation_context));

  {
    TransformationReplaceParamsWithStruct transformation({16, 18, 19}, 90, 91,
                                                         {{33, 92}, {90, 93}});
    ASSERT_TRUE(
        transformation.IsApplicable(context.get(), transformation_context));
    ApplyAndCheckFreshIds(transformation, context.get(),
                          &transformation_context);
  }
  {
    TransformationReplaceParamsWithStruct transformation({43}, 93, 94,
                                                         {{33, 95}});
    ASSERT_TRUE(
        transformation.IsApplicable(context.get(), transformation_context));
    ApplyAndCheckFreshIds(transformation, context.get(),
                          &transformation_context);
  }
  {
    TransformationReplaceParamsWithStruct transformation({17, 91, 94}, 96, 97,
                                                         {{33, 98}});
    ASSERT_TRUE(
        transformation.IsApplicable(context.get(), transformation_context));
    ApplyAndCheckFreshIds(transformation, context.get(),
                          &transformation_context);
  }
  {
    TransformationReplaceParamsWithStruct transformation({55}, 99, 100, {{}});
    ASSERT_TRUE(
        transformation.IsApplicable(context.get(), transformation_context));
    ApplyAndCheckFreshIds(transformation, context.get(),
                          &transformation_context);
  }
  {
    TransformationReplaceParamsWithStruct transformation({61}, 101, 102, {{}});
    ASSERT_TRUE(
        transformation.IsApplicable(context.get(), transformation_context));
    ApplyAndCheckFreshIds(transformation, context.get(),
                          &transformation_context);
  }
  {
    TransformationReplaceParamsWithStruct transformation({73}, 103, 104, {{}});
    ASSERT_TRUE(
        transformation.IsApplicable(context.get(), transformation_context));
    ApplyAndCheckFreshIds(transformation, 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 310
               OpMemberDecorate %13 0 RelaxedPrecision
               OpDecorate %16 RelaxedPrecision
          %2 = OpTypeVoid
          %6 = OpTypeInt 32 1
          %3 = OpTypeFunction %2
          %7 = OpTypePointer Private %6
          %8 = OpTypeFloat 32
          %9 = OpTypePointer Private %8
         %10 = OpTypeVector %8 2
         %11 = OpTypePointer Private %10
         %12 = OpTypeBool
         %51 = OpTypeFunction %2 %12
         %64 = OpTypeStruct %6
         %63 = OpTypeFunction %2 %64
         %65 = OpTypeFunction %2 %6
         %75 = OpTypeStruct %8
         %76 = OpTypeFunction %2 %75
         %40 = OpTypePointer Function %12
         %13 = OpTypeStruct %6 %8
         %45 = OpTypeStruct %6 %10 %13
         %46 = OpTypeStruct %12
         %47 = OpTypeStruct %8 %45 %46
         %14 = OpTypePointer Private %13
         %22 = OpConstant %6 0
         %23 = OpConstant %8 0
         %26 = OpConstantComposite %10 %23 %23
         %27 = OpConstantTrue %12
         %28 = OpConstantComposite %13 %22 %23
         %15 = OpTypeFunction %2 %40 %47
         %99 = OpTypeFunction %2 %46
          %4 = OpFunction %2 None %3
          %5 = OpLabel
         %41 = OpVariable %40 Function %27
         %92 = OpCompositeConstruct %45 %22 %26 %28
         %95 = OpCompositeConstruct %46 %27
         %98 = OpCompositeConstruct %47 %23 %92 %95
         %33 = OpFunctionCall %2 %20 %41 %98
               OpReturn
               OpFunctionEnd
         %20 = OpFunction %2 None %15
         %42 = OpFunctionParameter %40
         %97 = OpFunctionParameter %47
         %21 = OpLabel
         %94 = OpCompositeExtract %46 %97 2
         %91 = OpCompositeExtract %45 %97 1
         %17 = OpCompositeExtract %8 %97 0
         %43 = OpCompositeExtract %12 %94 0
         %19 = OpCompositeExtract %13 %91 2
         %18 = OpCompositeExtract %10 %91 1
         %16 = OpCompositeExtract %6 %91 0
               OpReturn
               OpFunctionEnd
         %50 = OpFunction %2 None %51
         %52 = OpFunctionParameter %12
         %53 = OpLabel
               OpReturn
               OpFunctionEnd
         %54 = OpFunction %2 None %99
        %100 = OpFunctionParameter %46
         %56 = OpLabel
         %55 = OpCompositeExtract %12 %100 0
               OpReturn
               OpFunctionEnd
         %57 = OpFunction %2 None %63
         %58 = OpFunctionParameter %64
         %59 = OpLabel
               OpReturn
               OpFunctionEnd
         %60 = OpFunction %2 None %63
        %102 = OpFunctionParameter %64
         %62 = OpLabel
         %61 = OpCompositeExtract %6 %102 0
               OpReturn
               OpFunctionEnd
         %66 = OpFunction %2 None %65
         %67 = OpFunctionParameter %6
         %68 = OpLabel
               OpReturn
               OpFunctionEnd
         %69 = OpFunction %2 None %76
         %70 = OpFunctionParameter %75
         %71 = OpLabel
               OpReturn
               OpFunctionEnd
         %72 = OpFunction %2 None %76
        %104 = OpFunctionParameter %75
         %74 = OpLabel
         %73 = OpCompositeExtract %8 %104 0
               OpReturn
               OpFunctionEnd
  )";

  ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
}

TEST(TransformationReplaceParamsWithStructTest, ParametersRemainValid) {
  std::string shader = R"(
               OpCapability Shader
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Fragment %4 "main"
               OpExecutionMode %4 OriginUpperLeft
               OpSource ESSL 310
          %2 = OpTypeVoid
          %6 = OpTypeInt 32 1
          %3 = OpTypeFunction %2
          %8 = OpTypeFloat 32
         %10 = OpTypeVector %8 2
         %12 = OpTypeBool
         %40 = OpTypePointer Function %12
         %13 = OpTypeStruct %6 %8
         %45 = OpTypeStruct %6 %8 %13
         %47 = OpTypeStruct %45 %12 %10
         %15 = OpTypeFunction %2 %6 %8 %10 %13 %40 %12
          %4 = OpFunction %2 None %3
          %5 = OpLabel
               OpReturn
               OpFunctionEnd
         %20 = OpFunction %2 None %15
         %16 = OpFunctionParameter %6
         %17 = OpFunctionParameter %8
         %18 = OpFunctionParameter %10
         %19 = OpFunctionParameter %13
         %42 = OpFunctionParameter %40
         %43 = OpFunctionParameter %12
         %21 = 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);
  {
    // Try to replace parameters in "increasing" order of their declaration.
    TransformationReplaceParamsWithStruct transformation({16, 17, 19}, 70, 71,
                                                         {{}});
    ASSERT_TRUE(
        transformation.IsApplicable(context.get(), transformation_context));
    ApplyAndCheckFreshIds(transformation, context.get(),
                          &transformation_context);
    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
        context.get(), validator_options, kConsoleMessageConsumer));
  }

  std::string after_transformation = R"(
               OpCapability Shader
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Fragment %4 "main"
               OpExecutionMode %4 OriginUpperLeft
               OpSource ESSL 310
          %2 = OpTypeVoid
          %6 = OpTypeInt 32 1
          %3 = OpTypeFunction %2
          %8 = OpTypeFloat 32
         %10 = OpTypeVector %8 2
         %12 = OpTypeBool
         %40 = OpTypePointer Function %12
         %13 = OpTypeStruct %6 %8
         %45 = OpTypeStruct %6 %8 %13
         %47 = OpTypeStruct %45 %12 %10
         %15 = OpTypeFunction %2 %10 %40 %12 %45
          %4 = OpFunction %2 None %3
          %5 = OpLabel
               OpReturn
               OpFunctionEnd
         %20 = OpFunction %2 None %15
         %18 = OpFunctionParameter %10
         %42 = OpFunctionParameter %40
         %43 = OpFunctionParameter %12
         %71 = OpFunctionParameter %45
         %21 = OpLabel
         %19 = OpCompositeExtract %13 %71 2
         %17 = OpCompositeExtract %8 %71 1
         %16 = OpCompositeExtract %6 %71 0
               OpReturn
               OpFunctionEnd
  )";

  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));

  {
    // Try to replace parameters in "decreasing" order of their declaration.
    TransformationReplaceParamsWithStruct transformation({71, 43, 18}, 72, 73,
                                                         {{}});
    ASSERT_TRUE(
        transformation.IsApplicable(context.get(), transformation_context));
    ApplyAndCheckFreshIds(transformation, context.get(),
                          &transformation_context);
    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
        context.get(), validator_options, kConsoleMessageConsumer));
  }

  after_transformation = R"(
               OpCapability Shader
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Fragment %4 "main"
               OpExecutionMode %4 OriginUpperLeft
               OpSource ESSL 310
          %2 = OpTypeVoid
          %6 = OpTypeInt 32 1
          %3 = OpTypeFunction %2
          %8 = OpTypeFloat 32
         %10 = OpTypeVector %8 2
         %12 = OpTypeBool
         %40 = OpTypePointer Function %12
         %13 = OpTypeStruct %6 %8
         %45 = OpTypeStruct %6 %8 %13
         %47 = OpTypeStruct %45 %12 %10
         %15 = OpTypeFunction %2 %40 %47
          %4 = OpFunction %2 None %3
          %5 = OpLabel
               OpReturn
               OpFunctionEnd
         %20 = OpFunction %2 None %15
         %42 = OpFunctionParameter %40
         %73 = OpFunctionParameter %47
         %21 = OpLabel
         %18 = OpCompositeExtract %10 %73 2
         %43 = OpCompositeExtract %12 %73 1
         %71 = OpCompositeExtract %45 %73 0
         %19 = OpCompositeExtract %13 %71 2
         %17 = OpCompositeExtract %8 %71 1
         %16 = OpCompositeExtract %6 %71 0
               OpReturn
               OpFunctionEnd
  )";

  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
}

}  // namespace
}  // namespace fuzz
}  // namespace spvtools

<MSG> spirv-fuzz: Avoid the type manager when looking for struct types (#3963)

Fixes #3947.
<DFF> @@ -163,9 +163,9 @@ TEST(TransformationReplaceParamsWithStructTest, BasicTest) {
                    .IsApplicable(context.get(), transformation_context));
 
   // |caller_id_to_fresh_composite_id| misses values.
-  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 91,
-                                                     {{33, 92}, {90, 93}})
-                   .IsApplicable(context.get(), transformation_context));
+  ASSERT_FALSE(
+      TransformationReplaceParamsWithStruct({16, 17}, 90, 91, {{90, 93}})
+          .IsApplicable(context.get(), transformation_context));
 
   // All fresh ids must be unique.
   ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 90,
@@ -483,6 +483,45 @@ TEST(TransformationReplaceParamsWithStructTest, ParametersRemainValid) {
   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
 }
 
+TEST(TransformationReplaceParamsWithStructTest, IsomorphicStructs) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %16 "main"
+               OpExecutionMode %16 OriginUpperLeft
+               OpSource ESSL 310
+          %2 = OpTypeVoid
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeStruct %6
+          %8 = OpTypeStruct %6
+          %9 = OpTypeStruct %8
+         %10 = OpTypeFunction %2 %7
+         %15 = OpTypeFunction %2
+         %16 = OpFunction %2 None %15
+         %17 = OpLabel
+               OpReturn
+               OpFunctionEnd
+         %11 = OpFunction %2 None %10
+         %12 = OpFunctionParameter %7
+         %13 = 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(TransformationReplaceParamsWithStruct({12}, 100, 101, {{}})
+                   .IsApplicable(context.get(), transformation_context));
+}
+
 }  // namespace
 }  // namespace fuzz
 }  // namespace spvtools

{'commit': 'diff --git a/source/fuzz/fuzzer_util.cpp b/source/fuzz/fuzzer_util.cpp\nindex 19478537..a691a91c 100644\n--- a/source/fuzz/fuzzer_util.cpp\n+++ b/source/fuzz/fuzzer_util.cpp\n@@ -418,6 +418,8 @@ bool IsValidAndWellFormed(const opt::IRContext* ir_context,\n                           spv_validator_options validator_options,\n                           MessageConsumer consumer) {\n   if (!IsValid(ir_context, validator_options, consumer)) {\n+    // Expression to dump |ir_context| to /data/temp/shader.spv:\n+    //    DumpShader(ir_context, "/data/temp/shader.spv")\n     consumer(SPV_MSG_INFO, nullptr, {},\n              "Module is invalid (set a breakpoint to inspect).");\n     return false;\n@@ -1052,18 +1054,24 @@ uint32_t MaybeGetVectorType(opt::IRContext* ir_context,\n \n uint32_t MaybeGetStructType(opt::IRContext* ir_context,\n                             const std::vector<uint32_t>& component_type_ids) {\n-  std::vector<const opt::analysis::Type*> component_types;\n-  component_types.reserve(component_type_ids.size());\n-\n-  for (auto type_id : component_type_ids) {\n-    const auto* component_type = ir_context->get_type_mgr()->GetType(type_id);\n-    assert(component_type && !component_type->AsFunction() &&\n-           "Component type is invalid");\n-    component_types.push_back(component_type);\n+  for (auto& type_or_value : ir_context->types_values()) {\n+    if (type_or_value.opcode() != SpvOpTypeStruct ||\n+        type_or_value.NumInOperands() !=\n+            static_cast<uint32_t>(component_type_ids.size())) {\n+      continue;\n+    }\n+    bool all_components_match = true;\n+    for (uint32_t i = 0; i < component_type_ids.size(); i++) {\n+      if (type_or_value.GetSingleWordInOperand(i) != component_type_ids[i]) {\n+        all_components_match = false;\n+        break;\n+      }\n+    }\n+    if (all_components_match) {\n+      return type_or_value.result_id();\n+    }\n   }\n-\n-  opt::analysis::Struct type(component_types);\n-  return ir_context->get_type_mgr()->GetId(&type);\n+  return 0;\n }\n \n uint32_t MaybeGetVoidType(opt::IRContext* ir_context) {\ndiff --git a/source/fuzz/fuzzer_util.h b/source/fuzz/fuzzer_util.h\nindex 566c535e..f23826ae 100644\n--- a/source/fuzz/fuzzer_util.h\n+++ b/source/fuzz/fuzzer_util.h\n@@ -388,7 +388,8 @@ uint32_t MaybeGetBoolType(opt::IRContext* ir_context);\n uint32_t MaybeGetVectorType(opt::IRContext* ir_context,\n                             uint32_t component_type_id, uint32_t element_count);\n \n-// Returns a result id of an OpTypeStruct instruction if present. Returns 0\n+// Returns a result id of an OpTypeStruct instruction whose field types exactly\n+// match |component_type_ids| if such an instruction is present. Returns 0\n // otherwise. |component_type_ids| may not contain a result id of an\n // OpTypeFunction.\n uint32_t MaybeGetStructType(opt::IRContext* ir_context,\ndiff --git a/test/fuzz/transformation_replace_params_with_struct_test.cpp b/test/fuzz/transformation_replace_params_with_struct_test.cpp\nindex 58fff65f..afa782e4 100644\n--- a/test/fuzz/transformation_replace_params_with_struct_test.cpp\n+++ b/test/fuzz/transformation_replace_params_with_struct_test.cpp\n@@ -163,9 +163,9 @@ TEST(TransformationReplaceParamsWithStructTest, BasicTest) {\n                    .IsApplicable(context.get(), transformation_context));\n \n   // |caller_id_to_fresh_composite_id| misses values.\n-  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 91,\n-                                                     {{33, 92}, {90, 93}})\n-                   .IsApplicable(context.get(), transformation_context));\n+  ASSERT_FALSE(\n+      TransformationReplaceParamsWithStruct({16, 17}, 90, 91, {{90, 93}})\n+          .IsApplicable(context.get(), transformation_context));\n \n   // All fresh ids must be unique.\n   ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 90,\n@@ -483,6 +483,45 @@ TEST(TransformationReplaceParamsWithStructTest, ParametersRemainValid) {\n   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));\n }\n \n+TEST(TransformationReplaceParamsWithStructTest, IsomorphicStructs) {\n+  std::string shader = R"(\n+               OpCapability Shader\n+          %1 = OpExtInstImport "GLSL.std.450"\n+               OpMemoryModel Logical GLSL450\n+               OpEntryPoint Fragment %16 "main"\n+               OpExecutionMode %16 OriginUpperLeft\n+               OpSource ESSL 310\n+          %2 = OpTypeVoid\n+          %6 = OpTypeInt 32 1\n+          %7 = OpTypeStruct %6\n+          %8 = OpTypeStruct %6\n+          %9 = OpTypeStruct %8\n+         %10 = OpTypeFunction %2 %7\n+         %15 = OpTypeFunction %2\n+         %16 = OpFunction %2 None %15\n+         %17 = OpLabel\n+               OpReturn\n+               OpFunctionEnd\n+         %11 = OpFunction %2 None %10\n+         %12 = OpFunctionParameter %7\n+         %13 = OpLabel\n+               OpReturn\n+               OpFunctionEnd\n+  )";\n+\n+  const auto env = SPV_ENV_UNIVERSAL_1_3;\n+  const auto consumer = nullptr;\n+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);\n+  spvtools::ValidatorOptions validator_options;\n+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,\n+                                               kConsoleMessageConsumer));\n+  TransformationContext transformation_context(\n+      MakeUnique<FactManager>(context.get()), validator_options);\n+\n+  ASSERT_FALSE(TransformationReplaceParamsWithStruct({12}, 100, 101, {{}})\n+                   .IsApplicable(context.get(), transformation_context));\n+}\n+\n }  // namespace\n }  // namespace fuzz\n }  // namespace spvtools\n', 'commit_subject': 'spirv-fuzz: Avoid the type manager when looking for struct types (#3963)', 'repo_name': 'KhronosGroup/SPIRV-Tools', 'committer': {'name': 'GitHub', 'email': '1505422b2465e9a84f6fdfaa161078890c593f06@github.com', 'time_sec': '1603301285', 'tz_offset': '60', 'date': {'seconds': '1603301285'}}, 'commit_tree': '4b77e835372917896ef28d59097e972c5dd865b4', 'commit_message': 'spirv-fuzz: Avoid the type manager when looking for struct types (#3963)\n\nFixes #3947.', 'language_name': 'Python', 'license': 'apache-2.0', 'hunks': '@@ -163,9 +163,9 @@ TEST(TransformationReplaceParamsWithStructTest, BasicTest) {\n                    .IsApplicable(context.get(), transformation_context));\n \n   // |caller_id_to_fresh_composite_id| misses values.\n-  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 91,\n-                                                     {{33, 92}, {90, 93}})\n-                   .IsApplicable(context.get(), transformation_context));\n+  ASSERT_FALSE(\n+      TransformationReplaceParamsWithStruct({16, 17}, 90, 91, {{90, 93}})\n+          .IsApplicable(context.get(), transformation_context));\n \n   // All fresh ids must be unique.\n   ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 90,\n@@ -483,6 +483,45 @@ TEST(TransformationReplaceParamsWithStructTest, ParametersRemainValid) {\n   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));\n }\n \n+TEST(TransformationReplaceParamsWithStructTest, IsomorphicStructs) {\n+  std::string shader = R"(\n+               OpCapability Shader\n+          %1 = OpExtInstImport "GLSL.std.450"\n+               OpMemoryModel Logical GLSL450\n+               OpEntryPoint Fragment %16 "main"\n+               OpExecutionMode %16 OriginUpperLeft\n+               OpSource ESSL 310\n+          %2 = OpTypeVoid\n+          %6 = OpTypeInt 32 1\n+          %7 = OpTypeStruct %6\n+          %8 = OpTypeStruct %6\n+          %9 = OpTypeStruct %8\n+         %10 = OpTypeFunction %2 %7\n+         %15 = OpTypeFunction %2\n+         %16 = OpFunction %2 None %15\n+         %17 = OpLabel\n+               OpReturn\n+               OpFunctionEnd\n+         %11 = OpFunction %2 None %10\n+         %12 = OpFunctionParameter %7\n+         %13 = OpLabel\n+               OpReturn\n+               OpFunctionEnd\n+  )";\n+\n+  const auto env = SPV_ENV_UNIVERSAL_1_3;\n+  const auto consumer = nullptr;\n+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);\n+  spvtools::ValidatorOptions validator_options;\n+  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,\n+                                               kConsoleMessageConsumer));\n+  TransformationContext transformation_context(\n+      MakeUnique<FactManager>(context.get()), validator_options);\n+\n+  ASSERT_FALSE(TransformationReplaceParamsWithStruct({12}, 100, 101, {{}})\n+                   .IsApplicable(context.get(), transformation_context));\n+}\n+\n }  // namespace\n }  // namespace fuzz\n }  // namespace spvtools\n', 'addition_count': 42, 'deletion_count': 3, 'src_file': 'a/test/fuzz/transformation_replace_params_with_struct_test.cpp', 'tgt_file': 'b/test/fuzz/transformation_replace_params_with_struct_test.cpp', 'file_extension': '.cpp', 'before_file': '// Copyright (c) 2020 Vasyl Teliman\n//\n// Licensed under the Apache License, Version 2.0 (the "License");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an "AS IS" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include "source/fuzz/transformation_replace_params_with_struct.h"\n\n#include "gtest/gtest.h"\n#include "source/fuzz/fuzzer_util.h"\n#include "test/fuzz/fuzz_test_util.h"\n\nnamespace spvtools {\nnamespace fuzz {\nnamespace {\n\nTEST(TransformationReplaceParamsWithStructTest, BasicTest) {\n  std::string shader = R"(\n               OpCapability Shader\n          %1 = OpExtInstImport "GLSL.std.450"\n               OpMemoryModel Logical GLSL450\n               OpEntryPoint Fragment %4 "main"\n               OpExecutionMode %4 OriginUpperLeft\n               OpSource ESSL 310\n               OpMemberDecorate %13 0 RelaxedPrecision\n               OpDecorate %16 RelaxedPrecision\n          %2 = OpTypeVoid\n          %6 = OpTypeInt 32 1\n          %3 = OpTypeFunction %2\n          %7 = OpTypePointer Private %6\n          %8 = OpTypeFloat 32\n          %9 = OpTypePointer Private %8\n         %10 = OpTypeVector %8 2\n         %11 = OpTypePointer Private %10\n         %12 = OpTypeBool\n         %51 = OpTypeFunction %2 %12\n         %64 = OpTypeStruct %6\n         %63 = OpTypeFunction %2 %64\n         %65 = OpTypeFunction %2 %6\n         %75 = OpTypeStruct %8\n         %76 = OpTypeFunction %2 %75\n         %77 = OpTypeFunction %2 %8\n         %40 = OpTypePointer Function %12\n         %13 = OpTypeStruct %6 %8\n         %45 = OpTypeStruct %6 %10 %13\n         %46 = OpTypeStruct %12\n         %47 = OpTypeStruct %8 %45 %46\n         %14 = OpTypePointer Private %13\n         %15 = OpTypeFunction %2 %6 %8 %10 %13 %40 %12\n         %22 = OpConstant %6 0\n         %23 = OpConstant %8 0\n         %26 = OpConstantComposite %10 %23 %23\n         %27 = OpConstantTrue %12\n         %28 = OpConstantComposite %13 %22 %23\n          %4 = OpFunction %2 None %3\n          %5 = OpLabel\n         %41 = OpVariable %40 Function %27\n         %33 = OpFunctionCall %2 %20 %22 %23 %26 %28 %41 %27\n               OpReturn\n               OpFunctionEnd\n\n         ; adjust type of the function in-place\n         %20 = OpFunction %2 None %15\n         %16 = OpFunctionParameter %6\n         %17 = OpFunctionParameter %8\n         %18 = OpFunctionParameter %10\n         %19 = OpFunctionParameter %13\n         %42 = OpFunctionParameter %40\n         %43 = OpFunctionParameter %12\n         %21 = OpLabel\n               OpReturn\n               OpFunctionEnd\n\n         ; create a new function type\n         %50 = OpFunction %2 None %51\n         %52 = OpFunctionParameter %12\n         %53 = OpLabel\n               OpReturn\n               OpFunctionEnd\n         %54 = OpFunction %2 None %51\n         %55 = OpFunctionParameter %12\n         %56 = OpLabel\n               OpReturn\n               OpFunctionEnd\n\n         ; reuse an existing function type\n         %57 = OpFunction %2 None %63\n         %58 = OpFunctionParameter %64\n         %59 = OpLabel\n               OpReturn\n               OpFunctionEnd\n         %60 = OpFunction %2 None %65\n         %61 = OpFunctionParameter %6\n         %62 = OpLabel\n               OpReturn\n               OpFunctionEnd\n         %66 = OpFunction %2 None %65\n         %67 = OpFunctionParameter %6\n         %68 = OpLabel\n               OpReturn\n               OpFunctionEnd\n\n         ; don\'t adjust the type of the function if it creates a duplicate\n         %69 = OpFunction %2 None %76\n         %70 = OpFunctionParameter %75\n         %71 = OpLabel\n               OpReturn\n               OpFunctionEnd\n         %72 = OpFunction %2 None %77\n         %73 = OpFunctionParameter %8\n         %74 = OpLabel\n               OpReturn\n               OpFunctionEnd\n  )";\n\n  const auto env = SPV_ENV_UNIVERSAL_1_3;\n  const auto consumer = nullptr;\n  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);\n  spvtools::ValidatorOptions validator_options;\n  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,\n                                               kConsoleMessageConsumer));\n  TransformationContext transformation_context(\n      MakeUnique<FactManager>(context.get()), validator_options);\n  // |parameter_id| is empty.\n  ASSERT_FALSE(\n      TransformationReplaceParamsWithStruct({}, 90, 91, {{33, 92}, {90, 93}})\n          .IsApplicable(context.get(), transformation_context));\n\n  // |parameter_id| has duplicates.\n  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 16, 17}, 90, 91,\n                                                     {{33, 92}, {90, 93}})\n                   .IsApplicable(context.get(), transformation_context));\n\n  // |parameter_id| has invalid values.\n  ASSERT_FALSE(TransformationReplaceParamsWithStruct({21, 16, 17}, 90, 91,\n                                                     {{33, 92}, {90, 93}})\n                   .IsApplicable(context.get(), transformation_context));\n  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 90, 17}, 90, 91,\n                                                     {{33, 92}, {90, 93}})\n                   .IsApplicable(context.get(), transformation_context));\n\n  // Parameter\'s belong to different functions.\n  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17, 52}, 90, 91,\n                                                     {{33, 92}, {90, 93}})\n                   .IsApplicable(context.get(), transformation_context));\n\n  // Parameter has unsupported type.\n  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17, 42, 43}, 90, 91,\n                                                     {{33, 92}, {90, 93}})\n                   .IsApplicable(context.get(), transformation_context));\n\n  // OpTypeStruct does not exist in the module.\n  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 43}, 90, 91,\n                                                     {{33, 92}, {90, 93}})\n                   .IsApplicable(context.get(), transformation_context));\n\n  // |caller_id_to_fresh_composite_id| misses values.\n  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 91,\n                                                     {{33, 92}, {90, 93}})\n                   .IsApplicable(context.get(), transformation_context));\n\n  // All fresh ids must be unique.\n  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 90,\n                                                     {{33, 92}, {90, 93}})\n                   .IsApplicable(context.get(), transformation_context));\n  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 91,\n                                                     {{33, 90}, {90, 93}})\n                   .IsApplicable(context.get(), transformation_context));\n  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 91,\n                                                     {{33, 92}, {90, 92}})\n                   .IsApplicable(context.get(), transformation_context));\n\n  // All \'fresh\' ids must be fresh.\n  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 91,\n                                                     {{33, 33}, {90, 93}})\n                   .IsApplicable(context.get(), transformation_context));\n  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 33, 91,\n                                                     {{33, 92}, {90, 93}})\n                   .IsApplicable(context.get(), transformation_context));\n  ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 33,\n                                                     {{33, 92}, {90, 93}})\n                   .IsApplicable(context.get(), transformation_context));\n\n  {\n    TransformationReplaceParamsWithStruct transformation({16, 18, 19}, 90, 91,\n                                                         {{33, 92}, {90, 93}});\n    ASSERT_TRUE(\n        transformation.IsApplicable(context.get(), transformation_context));\n    ApplyAndCheckFreshIds(transformation, context.get(),\n                          &transformation_context);\n  }\n  {\n    TransformationReplaceParamsWithStruct transformation({43}, 93, 94,\n                                                         {{33, 95}});\n    ASSERT_TRUE(\n        transformation.IsApplicable(context.get(), transformation_context));\n    ApplyAndCheckFreshIds(transformation, context.get(),\n                          &transformation_context);\n  }\n  {\n    TransformationReplaceParamsWithStruct transformation({17, 91, 94}, 96, 97,\n                                                         {{33, 98}});\n    ASSERT_TRUE(\n        transformation.IsApplicable(context.get(), transformation_context));\n    ApplyAndCheckFreshIds(transformation, context.get(),\n                          &transformation_context);\n  }\n  {\n    TransformationReplaceParamsWithStruct transformation({55}, 99, 100, {{}});\n    ASSERT_TRUE(\n        transformation.IsApplicable(context.get(), transformation_context));\n    ApplyAndCheckFreshIds(transformation, context.get(),\n                          &transformation_context);\n  }\n  {\n    TransformationReplaceParamsWithStruct transformation({61}, 101, 102, {{}});\n    ASSERT_TRUE(\n        transformation.IsApplicable(context.get(), transformation_context));\n    ApplyAndCheckFreshIds(transformation, context.get(),\n                          &transformation_context);\n  }\n  {\n    TransformationReplaceParamsWithStruct transformation({73}, 103, 104, {{}});\n    ASSERT_TRUE(\n        transformation.IsApplicable(context.get(), transformation_context));\n    ApplyAndCheckFreshIds(transformation, context.get(),\n                          &transformation_context);\n  }\n\n  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,\n                                               kConsoleMessageConsumer));\n\n  std::string expected_shader = R"(\n               OpCapability Shader\n          %1 = OpExtInstImport "GLSL.std.450"\n               OpMemoryModel Logical GLSL450\n               OpEntryPoint Fragment %4 "main"\n               OpExecutionMode %4 OriginUpperLeft\n               OpSource ESSL 310\n               OpMemberDecorate %13 0 RelaxedPrecision\n               OpDecorate %16 RelaxedPrecision\n          %2 = OpTypeVoid\n          %6 = OpTypeInt 32 1\n          %3 = OpTypeFunction %2\n          %7 = OpTypePointer Private %6\n          %8 = OpTypeFloat 32\n          %9 = OpTypePointer Private %8\n         %10 = OpTypeVector %8 2\n         %11 = OpTypePointer Private %10\n         %12 = OpTypeBool\n         %51 = OpTypeFunction %2 %12\n         %64 = OpTypeStruct %6\n         %63 = OpTypeFunction %2 %64\n         %65 = OpTypeFunction %2 %6\n         %75 = OpTypeStruct %8\n         %76 = OpTypeFunction %2 %75\n         %40 = OpTypePointer Function %12\n         %13 = OpTypeStruct %6 %8\n         %45 = OpTypeStruct %6 %10 %13\n         %46 = OpTypeStruct %12\n         %47 = OpTypeStruct %8 %45 %46\n         %14 = OpTypePointer Private %13\n         %22 = OpConstant %6 0\n         %23 = OpConstant %8 0\n         %26 = OpConstantComposite %10 %23 %23\n         %27 = OpConstantTrue %12\n         %28 = OpConstantComposite %13 %22 %23\n         %15 = OpTypeFunction %2 %40 %47\n         %99 = OpTypeFunction %2 %46\n          %4 = OpFunction %2 None %3\n          %5 = OpLabel\n         %41 = OpVariable %40 Function %27\n         %92 = OpCompositeConstruct %45 %22 %26 %28\n         %95 = OpCompositeConstruct %46 %27\n         %98 = OpCompositeConstruct %47 %23 %92 %95\n         %33 = OpFunctionCall %2 %20 %41 %98\n               OpReturn\n               OpFunctionEnd\n         %20 = OpFunction %2 None %15\n         %42 = OpFunctionParameter %40\n         %97 = OpFunctionParameter %47\n         %21 = OpLabel\n         %94 = OpCompositeExtract %46 %97 2\n         %91 = OpCompositeExtract %45 %97 1\n         %17 = OpCompositeExtract %8 %97 0\n         %43 = OpCompositeExtract %12 %94 0\n         %19 = OpCompositeExtract %13 %91 2\n         %18 = OpCompositeExtract %10 %91 1\n         %16 = OpCompositeExtract %6 %91 0\n               OpReturn\n               OpFunctionEnd\n         %50 = OpFunction %2 None %51\n         %52 = OpFunctionParameter %12\n         %53 = OpLabel\n               OpReturn\n               OpFunctionEnd\n         %54 = OpFunction %2 None %99\n        %100 = OpFunctionParameter %46\n         %56 = OpLabel\n         %55 = OpCompositeExtract %12 %100 0\n               OpReturn\n               OpFunctionEnd\n         %57 = OpFunction %2 None %63\n         %58 = OpFunctionParameter %64\n         %59 = OpLabel\n               OpReturn\n               OpFunctionEnd\n         %60 = OpFunction %2 None %63\n        %102 = OpFunctionParameter %64\n         %62 = OpLabel\n         %61 = OpCompositeExtract %6 %102 0\n               OpReturn\n               OpFunctionEnd\n         %66 = OpFunction %2 None %65\n         %67 = OpFunctionParameter %6\n         %68 = OpLabel\n               OpReturn\n               OpFunctionEnd\n         %69 = OpFunction %2 None %76\n         %70 = OpFunctionParameter %75\n         %71 = OpLabel\n               OpReturn\n               OpFunctionEnd\n         %72 = OpFunction %2 None %76\n        %104 = OpFunctionParameter %75\n         %74 = OpLabel\n         %73 = OpCompositeExtract %8 %104 0\n               OpReturn\n               OpFunctionEnd\n  )";\n\n  ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));\n}\n\nTEST(TransformationReplaceParamsWithStructTest, ParametersRemainValid) {\n  std::string shader = R"(\n               OpCapability Shader\n          %1 = OpExtInstImport "GLSL.std.450"\n               OpMemoryModel Logical GLSL450\n               OpEntryPoint Fragment %4 "main"\n               OpExecutionMode %4 OriginUpperLeft\n               OpSource ESSL 310\n          %2 = OpTypeVoid\n          %6 = OpTypeInt 32 1\n          %3 = OpTypeFunction %2\n          %8 = OpTypeFloat 32\n         %10 = OpTypeVector %8 2\n         %12 = OpTypeBool\n         %40 = OpTypePointer Function %12\n         %13 = OpTypeStruct %6 %8\n         %45 = OpTypeStruct %6 %8 %13\n         %47 = OpTypeStruct %45 %12 %10\n         %15 = OpTypeFunction %2 %6 %8 %10 %13 %40 %12\n          %4 = OpFunction %2 None %3\n          %5 = OpLabel\n               OpReturn\n               OpFunctionEnd\n         %20 = OpFunction %2 None %15\n         %16 = OpFunctionParameter %6\n         %17 = OpFunctionParameter %8\n         %18 = OpFunctionParameter %10\n         %19 = OpFunctionParameter %13\n         %42 = OpFunctionParameter %40\n         %43 = OpFunctionParameter %12\n         %21 = OpLabel\n               OpReturn\n               OpFunctionEnd\n  )";\n\n  const auto env = SPV_ENV_UNIVERSAL_1_3;\n  const auto consumer = nullptr;\n  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);\n  spvtools::ValidatorOptions validator_options;\n  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,\n                                               kConsoleMessageConsumer));\n  TransformationContext transformation_context(\n      MakeUnique<FactManager>(context.get()), validator_options);\n  {\n    // Try to replace parameters in "increasing" order of their declaration.\n    TransformationReplaceParamsWithStruct transformation({16, 17, 19}, 70, 71,\n                                                         {{}});\n    ASSERT_TRUE(\n        transformation.IsApplicable(context.get(), transformation_context));\n    ApplyAndCheckFreshIds(transformation, context.get(),\n                          &transformation_context);\n    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(\n        context.get(), validator_options, kConsoleMessageConsumer));\n  }\n\n  std::string after_transformation = R"(\n               OpCapability Shader\n          %1 = OpExtInstImport "GLSL.std.450"\n               OpMemoryModel Logical GLSL450\n               OpEntryPoint Fragment %4 "main"\n               OpExecutionMode %4 OriginUpperLeft\n               OpSource ESSL 310\n          %2 = OpTypeVoid\n          %6 = OpTypeInt 32 1\n          %3 = OpTypeFunction %2\n          %8 = OpTypeFloat 32\n         %10 = OpTypeVector %8 2\n         %12 = OpTypeBool\n         %40 = OpTypePointer Function %12\n         %13 = OpTypeStruct %6 %8\n         %45 = OpTypeStruct %6 %8 %13\n         %47 = OpTypeStruct %45 %12 %10\n         %15 = OpTypeFunction %2 %10 %40 %12 %45\n          %4 = OpFunction %2 None %3\n          %5 = OpLabel\n               OpReturn\n               OpFunctionEnd\n         %20 = OpFunction %2 None %15\n         %18 = OpFunctionParameter %10\n         %42 = OpFunctionParameter %40\n         %43 = OpFunctionParameter %12\n         %71 = OpFunctionParameter %45\n         %21 = OpLabel\n         %19 = OpCompositeExtract %13 %71 2\n         %17 = OpCompositeExtract %8 %71 1\n         %16 = OpCompositeExtract %6 %71 0\n               OpReturn\n               OpFunctionEnd\n  )";\n\n  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));\n\n  {\n    // Try to replace parameters in "decreasing" order of their declaration.\n    TransformationReplaceParamsWithStruct transformation({71, 43, 18}, 72, 73,\n                                                         {{}});\n    ASSERT_TRUE(\n        transformation.IsApplicable(context.get(), transformation_context));\n    ApplyAndCheckFreshIds(transformation, context.get(),\n                          &transformation_context);\n    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(\n        context.get(), validator_options, kConsoleMessageConsumer));\n  }\n\n  after_transformation = R"(\n               OpCapability Shader\n          %1 = OpExtInstImport "GLSL.std.450"\n               OpMemoryModel Logical GLSL450\n               OpEntryPoint Fragment %4 "main"\n               OpExecutionMode %4 OriginUpperLeft\n               OpSource ESSL 310\n          %2 = OpTypeVoid\n          %6 = OpTypeInt 32 1\n          %3 = OpTypeFunction %2\n          %8 = OpTypeFloat 32\n         %10 = OpTypeVector %8 2\n         %12 = OpTypeBool\n         %40 = OpTypePointer Function %12\n         %13 = OpTypeStruct %6 %8\n         %45 = OpTypeStruct %6 %8 %13\n         %47 = OpTypeStruct %45 %12 %10\n         %15 = OpTypeFunction %2 %40 %47\n          %4 = OpFunction %2 None %3\n          %5 = OpLabel\n               OpReturn\n               OpFunctionEnd\n         %20 = OpFunction %2 None %15\n         %42 = OpFunctionParameter %40\n         %73 = OpFunctionParameter %47\n         %21 = OpLabel\n         %18 = OpCompositeExtract %10 %73 2\n         %43 = OpCompositeExtract %12 %73 1\n         %71 = OpCompositeExtract %45 %73 0\n         %19 = OpCompositeExtract %13 %71 2\n         %17 = OpCompositeExtract %8 %71 1\n         %16 = OpCompositeExtract %6 %71 0\n               OpReturn\n               OpFunctionEnd\n  )";\n\n  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));\n}\n\n}  // namespace\n}  // namespace fuzz\n}  // namespace spvtools\n', 'message': 'spirv-fuzz: Avoid the type manager when looking for struct types (#3963)\n\nFixes #3947.', 'author_name': 'GitHub', 'lang': 'cpp'}