Răsfoiți Sursa

Updated spirv-tools.

Бранимир Караџић 6 ani în urmă
părinte
comite
8580112ecb
60 a modificat fișierele cu 2460 adăugiri și 2297 ștergeri
  1. 1 1
      3rdparty/spirv-tools/include/generated/build-version.inc
  2. 4 0
      3rdparty/spirv-tools/include/generated/core.insts-unified1.inc
  3. 2 1
      3rdparty/spirv-tools/include/generated/enum_string_mapping.inc
  4. 1 0
      3rdparty/spirv-tools/include/generated/extension_enum.inc
  5. 2 0
      3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc
  6. 2 0
      3rdparty/spirv-tools/source/fuzz/CMakeLists.txt
  7. 53 5
      3rdparty/spirv-tools/source/fuzz/fact_manager.cpp
  8. 8 5
      3rdparty/spirv-tools/source/fuzz/fact_manager.h
  9. 1 3
      3rdparty/spirv-tools/source/fuzz/fuzzer.cpp
  10. 0 1
      3rdparty/spirv-tools/source/fuzz/fuzzer.h
  11. 10 13
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp
  12. 42 58
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.cpp
  13. 12 21
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.cpp
  14. 5 8
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.cpp
  15. 6 8
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp
  16. 8 122
      3rdparty/spirv-tools/source/fuzz/replayer.cpp
  17. 0 1
      3rdparty/spirv-tools/source/fuzz/replayer.h
  18. 80 0
      3rdparty/spirv-tools/source/fuzz/transformation.cpp
  19. 91 0
      3rdparty/spirv-tools/source/fuzz/transformation.h
  20. 21 17
      3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.cpp
  21. 20 13
      3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.h
  22. 28 24
      3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.cpp
  23. 22 13
      3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.h
  24. 60 63
      3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.cpp
  25. 60 32
      3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.h
  26. 19 16
      3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.cpp
  27. 19 12
      3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.h
  28. 23 19
      3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.cpp
  29. 20 13
      3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.h
  30. 26 21
      3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.cpp
  31. 21 14
      3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.h
  32. 25 21
      3rdparty/spirv-tools/source/fuzz/transformation_add_type_pointer.cpp
  33. 22 13
      3rdparty/spirv-tools/source/fuzz/transformation_add_type_pointer.h
  34. 26 19
      3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.cpp
  35. 23 15
      3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.h
  36. 50 37
      3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp
  37. 43 32
      3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h
  38. 55 50
      3rdparty/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.cpp
  39. 57 39
      3rdparty/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.h
  40. 38 42
      3rdparty/spirv-tools/source/fuzz/transformation_split_block.cpp
  41. 42 25
      3rdparty/spirv-tools/source/fuzz/transformation_split_block.h
  42. 8 2
      3rdparty/spirv-tools/source/opt/ir_context.cpp
  43. 30 0
      3rdparty/spirv-tools/source/spirv_target_env.cpp
  44. 3 0
      3rdparty/spirv-tools/source/spirv_target_env.h
  45. 24 0
      3rdparty/spirv-tools/source/val/validate_decorations.cpp
  46. 19 33
      3rdparty/spirv-tools/test/fuzz/transformation_add_constant_boolean_test.cpp
  47. 40 62
      3rdparty/spirv-tools/test/fuzz/transformation_add_constant_scalar_test.cpp
  48. 376 552
      3rdparty/spirv-tools/test/fuzz/transformation_add_dead_break_test.cpp
  49. 7 10
      3rdparty/spirv-tools/test/fuzz/transformation_add_type_boolean_test.cpp
  50. 7 11
      3rdparty/spirv-tools/test/fuzz/transformation_add_type_float_test.cpp
  51. 15 20
      3rdparty/spirv-tools/test/fuzz/transformation_add_type_int_test.cpp
  52. 19 31
      3rdparty/spirv-tools/test/fuzz/transformation_add_type_pointer_test.cpp
  53. 196 356
      3rdparty/spirv-tools/test/fuzz/transformation_move_block_down_test.cpp
  54. 59 87
      3rdparty/spirv-tools/test/fuzz/transformation_replace_boolean_constant_with_constant_binary_test.cpp
  55. 186 226
      3rdparty/spirv-tools/test/fuzz/transformation_replace_constant_with_uniform_test.cpp
  56. 62 86
      3rdparty/spirv-tools/test/fuzz/transformation_split_block_test.cpp
  57. 322 0
      3rdparty/spirv-tools/test/opt/inst_bindless_check_test.cpp
  58. 38 21
      3rdparty/spirv-tools/test/val/val_decoration_test.cpp
  59. 1 1
      3rdparty/spirv-tools/tools/fuzz/fuzz.cpp
  60. 0 2
      3rdparty/spirv-tools/tools/reduce/reduce.cpp

+ 1 - 1
3rdparty/spirv-tools/include/generated/build-version.inc

@@ -1 +1 @@
-"v2019.4-dev", "SPIRV-Tools v2019.4-dev v2019.3-60-gdf86bb44"
+"v2019.4-dev", "SPIRV-Tools v2019.4-dev v2019.3-67-g9702d47c"

+ 4 - 0
3rdparty/spirv-tools/include/generated/core.insts-unified1.inc

@@ -3,6 +3,7 @@ static const SpvCapability pygen_variable_caps_AddressesPhysicalStorageBufferAdd
 static const SpvCapability pygen_variable_caps_AddressesVariablePointersVariablePointersStorageBuffer[] = {SpvCapabilityAddresses, SpvCapabilityVariablePointers, SpvCapabilityVariablePointersStorageBuffer};
 static const SpvCapability pygen_variable_caps_AddressesVariablePointersVariablePointersStorageBufferPhysicalStorageBufferAddressesEXT[] = {SpvCapabilityAddresses, SpvCapabilityVariablePointers, SpvCapabilityVariablePointersStorageBuffer, SpvCapabilityPhysicalStorageBufferAddressesEXT};
 static const SpvCapability pygen_variable_caps_CooperativeMatrixNV[] = {SpvCapabilityCooperativeMatrixNV};
+static const SpvCapability pygen_variable_caps_DemoteToHelperInvocationEXT[] = {SpvCapabilityDemoteToHelperInvocationEXT};
 static const SpvCapability pygen_variable_caps_DerivativeControl[] = {SpvCapabilityDerivativeControl};
 static const SpvCapability pygen_variable_caps_DeviceEnqueue[] = {SpvCapabilityDeviceEnqueue};
 static const SpvCapability pygen_variable_caps_FragmentMaskAMD[] = {SpvCapabilityFragmentMaskAMD};
@@ -45,6 +46,7 @@ static const SpvCapability pygen_variable_caps_SubgroupVoteKHR[] = {SpvCapabilit
 
 static const spvtools::Extension pygen_variable_exts_SPV_AMD_shader_ballot[] = {spvtools::Extension::kSPV_AMD_shader_ballot};
 static const spvtools::Extension pygen_variable_exts_SPV_AMD_shader_fragment_mask[] = {spvtools::Extension::kSPV_AMD_shader_fragment_mask};
+static const spvtools::Extension pygen_variable_exts_SPV_EXT_demote_to_helper_invocation[] = {spvtools::Extension::kSPV_EXT_demote_to_helper_invocation};
 static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_shader_interlock[] = {spvtools::Extension::kSPV_EXT_fragment_shader_interlock};
 static const spvtools::Extension pygen_variable_exts_SPV_GOOGLE_decorate_stringSPV_GOOGLE_hlsl_functionality1[] = {spvtools::Extension::kSPV_GOOGLE_decorate_string, spvtools::Extension::kSPV_GOOGLE_hlsl_functionality1};
 static const spvtools::Extension pygen_variable_exts_SPV_GOOGLE_hlsl_functionality1[] = {spvtools::Extension::kSPV_GOOGLE_hlsl_functionality1};
@@ -433,6 +435,8 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = {
   {"CooperativeMatrixLengthNV", SpvOpCooperativeMatrixLengthNV, 1, pygen_variable_caps_CooperativeMatrixNV, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 1, pygen_variable_exts_SPV_NV_cooperative_matrix, 0xffffffffu, 0xffffffffu},
   {"BeginInvocationInterlockEXT", SpvOpBeginInvocationInterlockEXT, 3, pygen_variable_caps_FragmentShaderSampleInterlockEXTFragmentShaderPixelInterlockEXTFragmentShaderShadingRateInterlockEXT, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, 0xffffffffu, 0xffffffffu},
   {"EndInvocationInterlockEXT", SpvOpEndInvocationInterlockEXT, 3, pygen_variable_caps_FragmentShaderSampleInterlockEXTFragmentShaderPixelInterlockEXTFragmentShaderShadingRateInterlockEXT, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, 0xffffffffu, 0xffffffffu},
+  {"DemoteToHelperInvocationEXT", SpvOpDemoteToHelperInvocationEXT, 1, pygen_variable_caps_DemoteToHelperInvocationEXT, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_EXT_demote_to_helper_invocation, 0xffffffffu, 0xffffffffu},
+  {"IsHelperInvocationEXT", SpvOpIsHelperInvocationEXT, 1, pygen_variable_caps_DemoteToHelperInvocationEXT, 2, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}, 1, 1, 1, pygen_variable_exts_SPV_EXT_demote_to_helper_invocation, 0xffffffffu, 0xffffffffu},
   {"SubgroupShuffleINTEL", SpvOpSubgroupShuffleINTEL, 1, pygen_variable_caps_SubgroupShuffleINTEL, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
   {"SubgroupShuffleDownINTEL", SpvOpSubgroupShuffleDownINTEL, 1, pygen_variable_caps_SubgroupShuffleINTEL, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},
   {"SubgroupShuffleUpINTEL", SpvOpSubgroupShuffleUpINTEL, 1, pygen_variable_caps_SubgroupShuffleINTEL, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu},

Fișier diff suprimat deoarece este prea mare
+ 2 - 1
3rdparty/spirv-tools/include/generated/enum_string_mapping.inc


+ 1 - 0
3rdparty/spirv-tools/include/generated/extension_enum.inc

@@ -8,6 +8,7 @@ kSPV_AMD_shader_fragment_mask,
 kSPV_AMD_shader_image_load_store_lod,
 kSPV_AMD_shader_trinary_minmax,
 kSPV_AMD_texture_gather_bias_lod,
+kSPV_EXT_demote_to_helper_invocation,
 kSPV_EXT_descriptor_indexing,
 kSPV_EXT_fragment_fully_covered,
 kSPV_EXT_fragment_invocation_density,

+ 2 - 0
3rdparty/spirv-tools/include/generated/operand.kinds-unified1.inc

@@ -90,6 +90,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_AMD_shader_explicit_ver
 static const spvtools::Extension pygen_variable_exts_SPV_AMD_shader_fragment_mask[] = {spvtools::Extension::kSPV_AMD_shader_fragment_mask};
 static const spvtools::Extension pygen_variable_exts_SPV_AMD_shader_image_load_store_lod[] = {spvtools::Extension::kSPV_AMD_shader_image_load_store_lod};
 static const spvtools::Extension pygen_variable_exts_SPV_AMD_texture_gather_bias_lod[] = {spvtools::Extension::kSPV_AMD_texture_gather_bias_lod};
+static const spvtools::Extension pygen_variable_exts_SPV_EXT_demote_to_helper_invocation[] = {spvtools::Extension::kSPV_EXT_demote_to_helper_invocation};
 static const spvtools::Extension pygen_variable_exts_SPV_EXT_descriptor_indexing[] = {spvtools::Extension::kSPV_EXT_descriptor_indexing};
 static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_fully_covered[] = {spvtools::Extension::kSPV_EXT_fragment_fully_covered};
 static const spvtools::Extension pygen_variable_exts_SPV_EXT_fragment_invocation_densitySPV_NV_shading_rate[] = {spvtools::Extension::kSPV_EXT_fragment_invocation_density, spvtools::Extension::kSPV_NV_shading_rate};
@@ -817,6 +818,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = {
   {"FragmentShaderShadingRateInterlockEXT", 5372, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, {}, 0xffffffffu, 0xffffffffu},
   {"ShaderSMBuiltinsNV", 5373, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_NV_shader_sm_builtins, {}, 0xffffffffu, 0xffffffffu},
   {"FragmentShaderPixelInterlockEXT", 5378, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, {}, 0xffffffffu, 0xffffffffu},
+  {"DemoteToHelperInvocationEXT", 5379, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_demote_to_helper_invocation, {}, 0xffffffffu, 0xffffffffu},
   {"SubgroupShuffleINTEL", 5568, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu, 0xffffffffu},
   {"SubgroupBufferBlockIOINTEL", 5569, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu, 0xffffffffu},
   {"SubgroupImageBlockIOINTEL", 5570, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroups, {}, 0xffffffffu, 0xffffffffu},

+ 2 - 0
3rdparty/spirv-tools/source/fuzz/CMakeLists.txt

@@ -41,6 +41,7 @@ if(SPIRV_BUILD_FUZZER)
         pseudo_random_generator.h
         random_generator.h
         replayer.h
+        transformation.h
         transformation_add_constant_boolean.h
         transformation_add_constant_scalar.h
         transformation_add_dead_break.h
@@ -69,6 +70,7 @@ if(SPIRV_BUILD_FUZZER)
         pseudo_random_generator.cpp
         random_generator.cpp
         replayer.cpp
+        transformation.cpp
         transformation_add_constant_boolean.cpp
         transformation_add_constant_scalar.cpp
         transformation_add_dead_break.cpp

+ 53 - 5
3rdparty/spirv-tools/source/fuzz/fact_manager.cpp

@@ -14,12 +14,60 @@
 
 #include "source/fuzz/fact_manager.h"
 
+#include <sstream>
+
 #include "source/fuzz/uniform_buffer_element_descriptor.h"
 #include "source/opt/ir_context.h"
 
 namespace spvtools {
 namespace fuzz {
 
+namespace {
+
+std::string ToString(const protobufs::Fact& fact) {
+  assert(fact.fact_case() == protobufs::Fact::kConstantUniformFact &&
+         "Right now this is the only fact.");
+  std::stringstream stream;
+  stream << "("
+         << fact.constant_uniform_fact()
+                .uniform_buffer_element_descriptor()
+                .descriptor_set()
+         << ", "
+         << fact.constant_uniform_fact()
+                .uniform_buffer_element_descriptor()
+                .binding()
+         << ")[";
+
+  bool first = true;
+  for (auto index : fact.constant_uniform_fact()
+                        .uniform_buffer_element_descriptor()
+                        .index()) {
+    if (first) {
+      first = false;
+    } else {
+      stream << ", ";
+    }
+    stream << index;
+  }
+
+  stream << "] == [";
+
+  first = true;
+  for (auto constant_word : fact.constant_uniform_fact().constant_word()) {
+    if (first) {
+      first = false;
+    } else {
+      stream << ", ";
+    }
+    stream << constant_word;
+  }
+
+  stream << "]";
+  return stream.str();
+}
+
+}  // namespace
+
 // The purpose of this struct is to group the fields and data used to represent
 // facts about uniform constants.
 struct FactManager::ConstantUniformFacts {
@@ -288,16 +336,16 @@ FactManager::FactManager() {
 
 FactManager::~FactManager() = default;
 
-bool FactManager::AddFacts(const protobufs::FactSequence& initial_facts,
+void FactManager::AddFacts(const MessageConsumer& message_consumer,
+                           const protobufs::FactSequence& initial_facts,
                            opt::IRContext* context) {
   for (auto& fact : initial_facts.fact()) {
     if (!AddFact(fact, context)) {
-      // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2621) Provide
-      //  information about the fact that could not be added.
-      return false;
+      message_consumer(
+          SPV_MSG_WARNING, nullptr, {},
+          ("Invalid fact " + ToString(fact) + " ignored.").c_str());
     }
   }
-  return true;
 }
 
 bool FactManager::AddFact(const spvtools::fuzz::protobufs::Fact& fact,

+ 8 - 5
3rdparty/spirv-tools/source/fuzz/fact_manager.h

@@ -41,11 +41,14 @@ class FactManager {
   ~FactManager();
 
   // Adds all the facts from |facts|, checking them for validity with respect to
-  // |context|. Returns true if and only if all facts are valid.
-  bool AddFacts(const protobufs::FactSequence& facts, opt::IRContext* context);
-
-  // Adds |fact| to the fact manager, checking it for validity with respect to
-  // |context|. Returns true if and only if the fact is valid.
+  // |context|.  Warnings about invalid facts are communicated via
+  // |message_consumer|; such facts are otherwise ignored.
+  void AddFacts(const MessageConsumer& message_consumer,
+                const protobufs::FactSequence& facts, opt::IRContext* context);
+
+  // Checks the fact for validity with respect to |context|.  Returns false,
+  // with no side effects, if the fact is invalid.  Otherwise adds |fact| to the
+  // fact manager.
   bool AddFact(const protobufs::Fact& fact, opt::IRContext* context);
 
   // The fact manager will ultimately be responsible for managing a few distinct

+ 1 - 3
3rdparty/spirv-tools/source/fuzz/fuzzer.cpp

@@ -97,9 +97,7 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
   FuzzerContext fuzzer_context(&random_generator, minimum_fresh_id);
 
   FactManager fact_manager;
-  if (!fact_manager.AddFacts(initial_facts, ir_context.get())) {
-    return Fuzzer::FuzzerResultStatus::kInitialFactsInvalid;
-  }
+  fact_manager.AddFacts(impl_->consumer, initial_facts, ir_context.get());
 
   // Add some essential ingredients to the module if they are not already
   // present, such as boolean constants.

+ 0 - 1
3rdparty/spirv-tools/source/fuzz/fuzzer.h

@@ -33,7 +33,6 @@ class Fuzzer {
     kComplete,
     kFailedToCreateSpirvToolsInterface,
     kInitialBinaryInvalid,
-    kInitialFactsInvalid,
   };
 
   // Constructs a fuzzer from the given target environment.

+ 10 - 13
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp

@@ -30,7 +30,7 @@ FuzzerPassAddDeadBreaks::~FuzzerPassAddDeadBreaks() = default;
 
 void FuzzerPassAddDeadBreaks::Apply() {
   // We first collect up lots of possibly-applicable transformations.
-  std::vector<protobufs::TransformationAddDeadBreak> candidate_transformations;
+  std::vector<TransformationAddDeadBreak> candidate_transformations;
   // We consider each function separately.
   for (auto& function : *GetIRContext()->module()) {
     // For a given function, we find all the merge blocks in that function.
@@ -51,13 +51,12 @@ void FuzzerPassAddDeadBreaks::Apply() {
         //  merge blocks.  This will lead to interesting opportunities being
         //  missed.
         std::vector<uint32_t> phi_ids;
-        auto candidate_transformation =
-            transformation::MakeTransformationAddDeadBreak(
-                block.id(), merge_block_id,
-                GetFuzzerContext()->GetRandomGenerator()->RandomBool(),
-                std::move(phi_ids));
-        if (transformation::IsApplicable(candidate_transformation,
-                                         GetIRContext(), *GetFactManager())) {
+        auto candidate_transformation = TransformationAddDeadBreak(
+            block.id(), merge_block_id,
+            GetFuzzerContext()->GetRandomGenerator()->RandomBool(),
+            std::move(phi_ids));
+        if (candidate_transformation.IsApplicable(GetIRContext(),
+                                                  *GetFactManager())) {
           // Only consider a transformation as a candidate if it is applicable.
           candidate_transformations.push_back(
               std::move(candidate_transformation));
@@ -92,11 +91,9 @@ void FuzzerPassAddDeadBreaks::Apply() {
     }
     // If the transformation can be applied, apply it and add it to the
     // sequence of transformations that have been applied.
-    if (transformation::IsApplicable(transformation, GetIRContext(),
-                                     *GetFactManager())) {
-      transformation::Apply(transformation, GetIRContext(), GetFactManager());
-      *GetTransformations()->add_transformation()->mutable_add_dead_break() =
-          transformation;
+    if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) {
+      transformation.Apply(GetIRContext(), GetFactManager());
+      *GetTransformations()->add_transformation() = transformation.ToMessage();
     }
   }
 }

+ 42 - 58
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.cpp

@@ -48,15 +48,13 @@ void FuzzerPassAddUsefulConstructs::MaybeAddIntConstant(
          "The relevant int type should have been added to the module already.");
   opt::analysis::IntConstant int_constant(registered_int_type, data);
   if (!GetIRContext()->get_constant_mgr()->FindConstant(&int_constant)) {
-    protobufs::TransformationAddConstantScalar add_constant_int =
-        transformation::MakeTransformationAddConstantScalar(
-            GetFuzzerContext()->GetFreshId(), int_type_id, data);
-    assert(transformation::IsApplicable(add_constant_int, GetIRContext(),
-                                        *GetFactManager()) &&
+    TransformationAddConstantScalar add_constant_int =
+        TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(),
+                                        int_type_id, data);
+    assert(add_constant_int.IsApplicable(GetIRContext(), *GetFactManager()) &&
            "Should be applicable by construction.");
-    transformation::Apply(add_constant_int, GetIRContext(), GetFactManager());
-    *GetTransformations()->add_transformation()->mutable_add_constant_scalar() =
-        add_constant_int;
+    add_constant_int.Apply(GetIRContext(), GetFactManager());
+    *GetTransformations()->add_transformation() = add_constant_int.ToMessage();
   }
 }
 
@@ -76,15 +74,14 @@ void FuzzerPassAddUsefulConstructs::MaybeAddFloatConstant(
       "The relevant float type should have been added to the module already.");
   opt::analysis::FloatConstant float_constant(registered_float_type, data);
   if (!GetIRContext()->get_constant_mgr()->FindConstant(&float_constant)) {
-    protobufs::TransformationAddConstantScalar add_constant_float =
-        transformation::MakeTransformationAddConstantScalar(
-            GetFuzzerContext()->GetFreshId(), float_type_id, data);
-    assert(transformation::IsApplicable(add_constant_float, GetIRContext(),
-                                        *GetFactManager()) &&
+    TransformationAddConstantScalar add_constant_float =
+        TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(),
+                                        float_type_id, data);
+    assert(add_constant_float.IsApplicable(GetIRContext(), *GetFactManager()) &&
            "Should be applicable by construction.");
-    transformation::Apply(add_constant_float, GetIRContext(), GetFactManager());
-    *GetTransformations()->add_transformation()->mutable_add_constant_scalar() =
-        add_constant_float;
+    add_constant_float.Apply(GetIRContext(), GetFactManager());
+    *GetTransformations()->add_transformation() =
+        add_constant_float.ToMessage();
   }
 }
 
@@ -93,15 +90,13 @@ void FuzzerPassAddUsefulConstructs::Apply() {
     // Add boolean type if not present.
     opt::analysis::Bool temp_bool_type;
     if (!GetIRContext()->get_type_mgr()->GetId(&temp_bool_type)) {
-      protobufs::TransformationAddTypeBoolean add_type_boolean =
-          transformation::MakeTransformationAddTypeBoolean(
-              GetFuzzerContext()->GetFreshId());
-      assert(transformation::IsApplicable(add_type_boolean, GetIRContext(),
-                                          *GetFactManager()) &&
+      auto add_type_boolean =
+          TransformationAddTypeBoolean(GetFuzzerContext()->GetFreshId());
+      assert(add_type_boolean.IsApplicable(GetIRContext(), *GetFactManager()) &&
              "Should be applicable by construction.");
-      transformation::Apply(add_type_boolean, GetIRContext(), GetFactManager());
-      *GetTransformations()->add_transformation()->mutable_add_type_boolean() =
-          add_type_boolean;
+      add_type_boolean.Apply(GetIRContext(), GetFactManager());
+      *GetTransformations()->add_transformation() =
+          add_type_boolean.ToMessage();
     }
   }
 
@@ -110,15 +105,12 @@ void FuzzerPassAddUsefulConstructs::Apply() {
     for (auto is_signed : {true, false}) {
       opt::analysis::Integer temp_int_type(32, is_signed);
       if (!GetIRContext()->get_type_mgr()->GetId(&temp_int_type)) {
-        protobufs::TransformationAddTypeInt add_type_int =
-            transformation::MakeTransformationAddTypeInt(
-                GetFuzzerContext()->GetFreshId(), 32, is_signed);
-        assert(transformation::IsApplicable(add_type_int, GetIRContext(),
-                                            *GetFactManager()) &&
+        TransformationAddTypeInt add_type_int = TransformationAddTypeInt(
+            GetFuzzerContext()->GetFreshId(), 32, is_signed);
+        assert(add_type_int.IsApplicable(GetIRContext(), *GetFactManager()) &&
                "Should be applicable by construction.");
-        transformation::Apply(add_type_int, GetIRContext(), GetFactManager());
-        *GetTransformations()->add_transformation()->mutable_add_type_int() =
-            add_type_int;
+        add_type_int.Apply(GetIRContext(), GetFactManager());
+        *GetTransformations()->add_transformation() = add_type_int.ToMessage();
       }
     }
   }
@@ -127,15 +119,12 @@ void FuzzerPassAddUsefulConstructs::Apply() {
     // Add 32-bit float type if not present.
     opt::analysis::Float temp_float_type(32);
     if (!GetIRContext()->get_type_mgr()->GetId(&temp_float_type)) {
-      protobufs::TransformationAddTypeFloat add_type_float =
-          transformation::MakeTransformationAddTypeFloat(
-              GetFuzzerContext()->GetFreshId(), 32);
-      assert(transformation::IsApplicable(add_type_float, GetIRContext(),
-                                          *GetFactManager()) &&
+      TransformationAddTypeFloat add_type_float =
+          TransformationAddTypeFloat(GetFuzzerContext()->GetFreshId(), 32);
+      assert(add_type_float.IsApplicable(GetIRContext(), *GetFactManager()) &&
              "Should be applicable by construction.");
-      transformation::Apply(add_type_float, GetIRContext(), GetFactManager());
-      *GetTransformations()->add_transformation()->mutable_add_type_float() =
-          add_type_float;
+      add_type_float.Apply(GetIRContext(), GetFactManager());
+      *GetTransformations()->add_transformation() = add_type_float.ToMessage();
     }
   }
 
@@ -149,17 +138,14 @@ void FuzzerPassAddUsefulConstructs::Apply() {
     // Add OpConstantTrue/False if not already there.
     opt::analysis::BoolConstant bool_constant(bool_type, boolean_value);
     if (!GetIRContext()->get_constant_mgr()->FindConstant(&bool_constant)) {
-      protobufs::TransformationAddConstantBoolean add_constant_boolean =
-          transformation::MakeTransformationAddConstantBoolean(
-              GetFuzzerContext()->GetFreshId(), boolean_value);
-      assert(transformation::IsApplicable(add_constant_boolean, GetIRContext(),
-                                          *GetFactManager()) &&
+      TransformationAddConstantBoolean add_constant_boolean(
+          GetFuzzerContext()->GetFreshId(), boolean_value);
+      assert(add_constant_boolean.IsApplicable(GetIRContext(),
+                                               *GetFactManager()) &&
              "Should be applicable by construction.");
-      transformation::Apply(add_constant_boolean, GetIRContext(),
-                            GetFactManager());
-      *GetTransformations()
-           ->add_transformation()
-           ->mutable_add_constant_boolean() = add_constant_boolean;
+      add_constant_boolean.Apply(GetIRContext(), GetFactManager());
+      *GetTransformations()->add_transformation() =
+          add_constant_boolean.ToMessage();
     }
   }
 
@@ -196,15 +182,13 @@ void FuzzerPassAddUsefulConstructs::Apply() {
     opt::analysis::Pointer uniform_pointer(element_type,
                                            SpvStorageClassUniform);
     if (!GetIRContext()->get_type_mgr()->GetId(&uniform_pointer)) {
-      auto add_pointer = transformation::MakeTransformationAddTypePointer(
-          GetFuzzerContext()->GetFreshId(), SpvStorageClassUniform,
-          element_type_id);
-      assert(transformation::IsApplicable(add_pointer, GetIRContext(),
-                                          *GetFactManager()) &&
+      auto add_pointer =
+          TransformationAddTypePointer(GetFuzzerContext()->GetFreshId(),
+                                       SpvStorageClassUniform, element_type_id);
+      assert(add_pointer.IsApplicable(GetIRContext(), *GetFactManager()) &&
              "Should be applicable by construction.");
-      transformation::Apply(add_pointer, GetIRContext(), GetFactManager());
-      *GetTransformations()->add_transformation()->mutable_add_type_pointer() =
-          add_pointer;
+      add_pointer.Apply(GetIRContext(), GetFactManager());
+      *GetTransformations()->add_transformation() = add_pointer.ToMessage();
     }
     std::vector<uint32_t> words;
     for (auto word : fact_and_type_id.first.constant_word()) {

+ 12 - 21
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.cpp

@@ -80,25 +80,20 @@ void FuzzerPassObfuscateConstants::ObfuscateBoolConstantViaConstantPair(
   // We can now make a transformation that will replace |bool_constant_use|
   // with an expression of the form (written using infix notation):
   // |lhs_id| |comparison_opcode| |rhs_id|
-  auto transformation = transformation::
-      MakeTransformationReplaceBooleanConstantWithConstantBinary(
-          bool_constant_use, lhs_id, rhs_id, comparison_opcode,
-          GetFuzzerContext()->GetFreshId());
+  auto transformation = TransformationReplaceBooleanConstantWithConstantBinary(
+      bool_constant_use, lhs_id, rhs_id, comparison_opcode,
+      GetFuzzerContext()->GetFreshId());
   // The transformation should be applicable by construction.
-  assert(transformation::IsApplicable(transformation, GetIRContext(),
-                                      *GetFactManager()));
+  assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()));
 
   // Applying this transformation yields a pointer to the new instruction that
   // computes the result of the binary expression.
   auto binary_operator_instruction =
-      transformation::Apply(transformation, GetIRContext(), GetFactManager());
+      transformation.ApplyWithResult(GetIRContext(), GetFactManager());
 
   // Add this transformation to the sequence of transformations that have been
   // applied.
-  *GetTransformations()
-       ->add_transformation()
-       ->mutable_replace_boolean_constant_with_constant_binary() =
-      transformation;
+  *GetTransformations()->add_transformation() = transformation.ToMessage();
 
   // Having made a binary expression, there may now be opportunities to further
   // obfuscate the constants used as the LHS and RHS of the expression (e.g. by
@@ -331,17 +326,13 @@ void FuzzerPassObfuscateConstants::ObfuscateScalarConstant(
               static_cast<uint32_t>(uniform_descriptors.size()))];
   // Create, apply and record a transformation to replace the constant use with
   // the result of a load from the chosen uniform.
-  auto transformation =
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          constant_use, uniform_descriptor, GetFuzzerContext()->GetFreshId(),
-          GetFuzzerContext()->GetFreshId());
+  auto transformation = TransformationReplaceConstantWithUniform(
+      constant_use, uniform_descriptor, GetFuzzerContext()->GetFreshId(),
+      GetFuzzerContext()->GetFreshId());
   // Transformation should be applicable by construction.
-  assert(transformation::IsApplicable(transformation, GetIRContext(),
-                                      *GetFactManager()));
-  transformation::Apply(transformation, GetIRContext(), GetFactManager());
-  *GetTransformations()
-       ->add_transformation()
-       ->mutable_replace_constant_with_uniform() = transformation;
+  assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()));
+  transformation.Apply(GetIRContext(), GetFactManager());
+  *GetTransformations()->add_transformation() = transformation.ToMessage();
 }
 
 void FuzzerPassObfuscateConstants::ObfuscateConstant(

+ 5 - 8
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.cpp

@@ -65,14 +65,11 @@ void FuzzerPassPermuteBlocks::Apply() {
       // The loop is guaranteed to terminate because a block cannot be pushed
       // down indefinitely.
       while (true) {
-        protobufs::TransformationMoveBlockDown message;
-        message.set_block_id(*id);
-        if (transformation::IsApplicable(message, GetIRContext(),
-                                         *GetFactManager())) {
-          transformation::Apply(message, GetIRContext(), GetFactManager());
-          *GetTransformations()
-               ->add_transformation()
-               ->mutable_move_block_down() = message;
+        TransformationMoveBlockDown transformation(*id);
+        if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) {
+          transformation.Apply(GetIRContext(), GetFactManager());
+          *GetTransformations()->add_transformation() =
+              transformation.ToMessage();
         } else {
           break;
         }

+ 6 - 8
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp

@@ -80,17 +80,15 @@ void FuzzerPassSplitBlocks::Apply() {
     auto base_offset = base_offset_pairs
         [GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
             static_cast<uint32_t>(base_offset_pairs.size()))];
-    auto message = transformation::MakeTransformationSplitBlock(
-        base_offset.first, base_offset.second,
-        GetFuzzerContext()->GetFreshId());
+    auto transformation =
+        TransformationSplitBlock(base_offset.first, base_offset.second,
+                                 GetFuzzerContext()->GetFreshId());
     // If the position we have chosen turns out to be a valid place to split
     // the block, we apply the split. Otherwise the block just doesn't get
     // split.
-    if (transformation::IsApplicable(message, GetIRContext(),
-                                     *GetFactManager())) {
-      transformation::Apply(message, GetIRContext(), GetFactManager());
-      *GetTransformations()->add_transformation()->mutable_split_block() =
-          message;
+    if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) {
+      transformation.Apply(GetIRContext(), GetFactManager());
+      *GetTransformations()->add_transformation() = transformation.ToMessage();
     }
   }
 }

+ 8 - 122
3rdparty/spirv-tools/source/fuzz/replayer.cpp

@@ -18,6 +18,7 @@
 
 #include "source/fuzz/fact_manager.h"
 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
 #include "source/fuzz/transformation_add_constant_boolean.h"
 #include "source/fuzz/transformation_add_constant_scalar.h"
 #include "source/fuzz/transformation_add_dead_break.h"
@@ -35,121 +36,6 @@
 namespace spvtools {
 namespace fuzz {
 
-namespace {
-
-// Returns true if and only if the precondition for |transformation| holds, with
-// respect to the given |context| and |fact_manager|.
-bool IsApplicable(const protobufs::Transformation& transformation,
-                  opt::IRContext* context, const FactManager& fact_manager) {
-  switch (transformation.transformation_case()) {
-    case protobufs::Transformation::TransformationCase::kAddConstantBoolean:
-      return transformation::IsApplicable(transformation.add_constant_boolean(),
-                                          context, fact_manager);
-    case protobufs::Transformation::TransformationCase::kAddConstantScalar:
-      return transformation::IsApplicable(transformation.add_constant_scalar(),
-                                          context, fact_manager);
-    case protobufs::Transformation::TransformationCase::kAddDeadBreak:
-      return transformation::IsApplicable(transformation.add_dead_break(),
-                                          context, fact_manager);
-    case protobufs::Transformation::TransformationCase::kAddTypeBoolean:
-      return transformation::IsApplicable(transformation.add_type_boolean(),
-                                          context, fact_manager);
-    case protobufs::Transformation::TransformationCase::kAddTypeFloat:
-      return transformation::IsApplicable(transformation.add_type_float(),
-                                          context, fact_manager);
-    case protobufs::Transformation::TransformationCase::kAddTypeInt:
-      return transformation::IsApplicable(transformation.add_type_int(),
-                                          context, fact_manager);
-    case protobufs::Transformation::TransformationCase::kAddTypePointer:
-      return transformation::IsApplicable(transformation.add_type_pointer(),
-                                          context, fact_manager);
-    case protobufs::Transformation::TransformationCase::kMoveBlockDown:
-      return transformation::IsApplicable(transformation.move_block_down(),
-                                          context, fact_manager);
-    case protobufs::Transformation::TransformationCase::
-        kReplaceBooleanConstantWithConstantBinary:
-      return transformation::IsApplicable(
-          transformation.replace_boolean_constant_with_constant_binary(),
-          context, fact_manager);
-    case protobufs::Transformation::TransformationCase::
-        kReplaceConstantWithUniform:
-      return transformation::IsApplicable(
-          transformation.replace_constant_with_uniform(), context,
-          fact_manager);
-    case protobufs::Transformation::TransformationCase::kSplitBlock:
-      return transformation::IsApplicable(transformation.split_block(), context,
-                                          fact_manager);
-    default:
-      assert(transformation.transformation_case() ==
-                 protobufs::Transformation::TRANSFORMATION_NOT_SET &&
-             "Unhandled transformation type.");
-      assert(false && "An unset transformation was encountered.");
-      return false;
-  }
-}
-
-// Requires that IsApplicable holds.  Applies |transformation| to the given
-// |context| and |fact_manager|.
-void Apply(const protobufs::Transformation& transformation,
-           opt::IRContext* context, FactManager* fact_manager) {
-  switch (transformation.transformation_case()) {
-    case protobufs::Transformation::TransformationCase::kAddConstantBoolean:
-      transformation::Apply(transformation.add_constant_boolean(), context,
-                            fact_manager);
-      break;
-    case protobufs::Transformation::TransformationCase::kAddConstantScalar:
-      transformation::Apply(transformation.add_constant_scalar(), context,
-                            fact_manager);
-      break;
-    case protobufs::Transformation::TransformationCase::kAddDeadBreak:
-      transformation::Apply(transformation.add_dead_break(), context,
-                            fact_manager);
-      break;
-    case protobufs::Transformation::TransformationCase::kAddTypeBoolean:
-      transformation::Apply(transformation.add_type_boolean(), context,
-                            fact_manager);
-      break;
-    case protobufs::Transformation::TransformationCase::kAddTypeFloat:
-      transformation::Apply(transformation.add_type_float(), context,
-                            fact_manager);
-      break;
-    case protobufs::Transformation::TransformationCase::kAddTypeInt:
-      transformation::Apply(transformation.add_type_int(), context,
-                            fact_manager);
-      break;
-    case protobufs::Transformation::TransformationCase::kAddTypePointer:
-      transformation::Apply(transformation.add_type_pointer(), context,
-                            fact_manager);
-      break;
-    case protobufs::Transformation::TransformationCase::kMoveBlockDown:
-      transformation::Apply(transformation.move_block_down(), context,
-                            fact_manager);
-      break;
-    case protobufs::Transformation::TransformationCase::
-        kReplaceBooleanConstantWithConstantBinary:
-      transformation::Apply(
-          transformation.replace_boolean_constant_with_constant_binary(),
-          context, fact_manager);
-      break;
-    case protobufs::Transformation::TransformationCase::
-        kReplaceConstantWithUniform:
-      transformation::Apply(transformation.replace_constant_with_uniform(),
-                            context, fact_manager);
-      break;
-    case protobufs::Transformation::TransformationCase::kSplitBlock:
-      transformation::Apply(transformation.split_block(), context,
-                            fact_manager);
-      break;
-    default:
-      assert(transformation.transformation_case() ==
-                 protobufs::Transformation::TRANSFORMATION_NOT_SET &&
-             "Unhandled transformation type.");
-      assert(false && "An unset transformation was encountered.");
-  }
-}
-
-}  // namespace
-
 struct Replayer::Impl {
   explicit Impl(spv_target_env env) : target_env(env) {}
 
@@ -195,18 +81,18 @@ Replayer::ReplayerResultStatus Replayer::Run(
   assert(ir_context);
 
   FactManager fact_manager;
-  if (!fact_manager.AddFacts(initial_facts, ir_context.get())) {
-    return Replayer::ReplayerResultStatus::kInitialFactsInvalid;
-  }
+  fact_manager.AddFacts(impl_->consumer, initial_facts, ir_context.get());
 
   // Consider the transformation proto messages in turn.
-  for (auto& transformation : transformation_sequence_in.transformation()) {
+  for (auto& message : transformation_sequence_in.transformation()) {
+    auto transformation = Transformation::FromMessage(message);
+
     // Check whether the transformation can be applied.
-    if (IsApplicable(transformation, ir_context.get(), fact_manager)) {
+    if (transformation->IsApplicable(ir_context.get(), fact_manager)) {
       // The transformation is applicable, so apply it, and copy it to the
       // sequence of transformations that were applied.
-      Apply(transformation, ir_context.get(), &fact_manager);
-      *transformation_sequence_out->add_transformation() = transformation;
+      transformation->Apply(ir_context.get(), &fact_manager);
+      *transformation_sequence_out->add_transformation() = message;
     }
   }
 

+ 0 - 1
3rdparty/spirv-tools/source/fuzz/replayer.h

@@ -33,7 +33,6 @@ class Replayer {
     kComplete,
     kFailedToCreateSpirvToolsInterface,
     kInitialBinaryInvalid,
-    kInitialFactsInvalid,
   };
 
   // Constructs a replayer from the given target environment.

+ 80 - 0
3rdparty/spirv-tools/source/fuzz/transformation.cpp

@@ -0,0 +1,80 @@
+// Copyright (c) 2019 Google LLC
+//
+// 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.h"
+
+#include <cassert>
+
+#include "source/util/make_unique.h"
+#include "transformation_add_constant_boolean.h"
+#include "transformation_add_constant_scalar.h"
+#include "transformation_add_dead_break.h"
+#include "transformation_add_type_boolean.h"
+#include "transformation_add_type_float.h"
+#include "transformation_add_type_int.h"
+#include "transformation_add_type_pointer.h"
+#include "transformation_move_block_down.h"
+#include "transformation_replace_boolean_constant_with_constant_binary.h"
+#include "transformation_replace_constant_with_uniform.h"
+#include "transformation_split_block.h"
+
+namespace spvtools {
+namespace fuzz {
+
+Transformation::~Transformation() = default;
+
+std::unique_ptr<Transformation> Transformation::FromMessage(
+    const protobufs::Transformation& message) {
+  switch (message.transformation_case()) {
+    case protobufs::Transformation::TransformationCase::kAddConstantBoolean:
+      return MakeUnique<TransformationAddConstantBoolean>(
+          message.add_constant_boolean());
+    case protobufs::Transformation::TransformationCase::kAddConstantScalar:
+      return MakeUnique<TransformationAddConstantScalar>(
+          message.add_constant_scalar());
+    case protobufs::Transformation::TransformationCase::kAddDeadBreak:
+      return MakeUnique<TransformationAddDeadBreak>(message.add_dead_break());
+    case protobufs::Transformation::TransformationCase::kAddTypeBoolean:
+      return MakeUnique<TransformationAddTypeBoolean>(
+          message.add_type_boolean());
+    case protobufs::Transformation::TransformationCase::kAddTypeFloat:
+      return MakeUnique<TransformationAddTypeFloat>(message.add_type_float());
+    case protobufs::Transformation::TransformationCase::kAddTypeInt:
+      return MakeUnique<TransformationAddTypeInt>(message.add_type_int());
+    case protobufs::Transformation::TransformationCase::kAddTypePointer:
+      return MakeUnique<TransformationAddTypePointer>(
+          message.add_type_pointer());
+    case protobufs::Transformation::TransformationCase::kMoveBlockDown:
+      return MakeUnique<TransformationMoveBlockDown>(message.move_block_down());
+    case protobufs::Transformation::TransformationCase::
+        kReplaceBooleanConstantWithConstantBinary:
+      return MakeUnique<TransformationReplaceBooleanConstantWithConstantBinary>(
+          message.replace_boolean_constant_with_constant_binary());
+    case protobufs::Transformation::TransformationCase::
+        kReplaceConstantWithUniform:
+      return MakeUnique<TransformationReplaceConstantWithUniform>(
+          message.replace_constant_with_uniform());
+    case protobufs::Transformation::TransformationCase::kSplitBlock:
+      return MakeUnique<TransformationSplitBlock>(message.split_block());
+    default:
+      assert(message.transformation_case() ==
+                 protobufs::Transformation::TRANSFORMATION_NOT_SET &&
+             "Unhandled transformation type.");
+      assert(false && "An unset transformation was encountered.");
+      return nullptr;
+  }
+}
+
+}  // namespace fuzz
+}  // namespace spvtools

+ 91 - 0
3rdparty/spirv-tools/source/fuzz/transformation.h

@@ -0,0 +1,91 @@
+// Copyright (c) 2019 Google LLC
+//
+// 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.
+
+#ifndef SOURCE_FUZZ_TRANSFORMATION_H_
+#define SOURCE_FUZZ_TRANSFORMATION_H_
+
+#include <memory>
+
+#include "source/fuzz/fact_manager.h"
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// Rules for transformations
+// -------------------------
+//
+// - Immutability: a transformation must be immutable.
+// - Ability to copy and serialize: to ensure that a copy of a transformation,
+//     possibly saved out to disk and read back again, is indistinguishable
+//     from the original transformation, thus a transformation must depend
+//     only on well-defined pieces of state, such as instruction ids.  It must
+//     not rely on state such as pointers to instructions and blocks.
+// - Determinism: the effect of a transformation on a module be a deterministic
+//     function of the module and the transformation.  Any randomization should
+//     be applied before creating the transformation, not during its
+//     application.
+// - Well-defined and precondition: the 'IsApplicable' method should only
+//     return true if the transformation can be cleanly applied to the given
+//     module, to mutate it into a valid and semantically-equivalent module, as
+//     long as the module is initially valid.
+// - Ability to test precondition on any valid module: 'IsApplicable' should be
+//     designed so that it is safe to ask whether a transformation is
+//     applicable to an arbitrary valid module.  For example, if a
+//     transformation involves a block id, 'IsApplicable' should check whether
+//     the module indeed has a block with that id, and return false if not.  It
+//     must not assume that there is such a block.
+// - Documented precondition: while the implementation of 'IsApplicable' should
+//     should codify the precondition, the method should be commented in the
+//     header file for a transformation with a precise English description of
+//     the precondition.
+// - Documented effect: while the implementation of 'Apply' should codify the
+//     effect of the transformation, the method should be commented in the
+//     header file for a transformation with a precise English description of
+//     the effect.
+
+class Transformation {
+ public:
+  // A precondition that determines whether the transformation can be cleanly
+  // applied in a semantics-preserving manner to the SPIR-V module given by
+  // |context|, in the presence of facts captured by |fact_manager|.
+  // Preconditions for individual transformations must be documented in the
+  // associated header file using precise English. The fact manager is used to
+  // provide access to facts about the module that are known to be true, on
+  // which the precondition may depend.
+  virtual bool IsApplicable(opt::IRContext* context,
+                            const FactManager& fact_manager) const = 0;
+
+  // Requires that IsApplicable(context, fact_manager) holds.  Applies the
+  // transformation, mutating |context| and possibly updating |fact_manager|
+  // with new facts established by the transformation.
+  virtual void Apply(opt::IRContext* context,
+                     FactManager* fact_manager) const = 0;
+
+  // Turns the transformation into a protobuf message for serialization.
+  virtual protobufs::Transformation ToMessage() const = 0;
+
+  virtual ~Transformation();
+
+  // Factory method to obtain a transformation object from the protobuf
+  // representation of a transformation given by |message|.
+  static std::unique_ptr<Transformation> FromMessage(
+      const protobufs::Transformation& message);
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_TRANSFORMATION_H_

+ 21 - 17
3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.cpp

@@ -19,42 +19,46 @@
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-using opt::IRContext;
+TransformationAddConstantBoolean::TransformationAddConstantBoolean(
+    const protobufs::TransformationAddConstantBoolean& message)
+    : message_(message) {}
 
-bool IsApplicable(const protobufs::TransformationAddConstantBoolean& message,
-                  IRContext* context, const FactManager& /*unused*/) {
+TransformationAddConstantBoolean::TransformationAddConstantBoolean(
+    uint32_t fresh_id, bool is_true) {
+  message_.set_fresh_id(fresh_id);
+  message_.set_is_true(is_true);
+}
+
+bool TransformationAddConstantBoolean::IsApplicable(
+    opt::IRContext* context, const FactManager& /*unused*/) const {
   opt::analysis::Bool bool_type;
   if (!context->get_type_mgr()->GetId(&bool_type)) {
     // No OpTypeBool is present.
     return false;
   }
-  return fuzzerutil::IsFreshId(context, message.fresh_id());
+  return fuzzerutil::IsFreshId(context, message_.fresh_id());
 }
 
-void Apply(const protobufs::TransformationAddConstantBoolean& message,
-           IRContext* context, FactManager* /*unused*/) {
+void TransformationAddConstantBoolean::Apply(opt::IRContext* context,
+                                             FactManager* /*unused*/) const {
   opt::analysis::Bool bool_type;
   // Add the boolean constant to the module, ensuring the module's id bound is
   // high enough.
-  fuzzerutil::UpdateModuleIdBound(context, message.fresh_id());
+  fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
   context->module()->AddGlobalValue(
-      message.is_true() ? SpvOpConstantTrue : SpvOpConstantFalse,
-      message.fresh_id(), context->get_type_mgr()->GetId(&bool_type));
+      message_.is_true() ? SpvOpConstantTrue : SpvOpConstantFalse,
+      message_.fresh_id(), context->get_type_mgr()->GetId(&bool_type));
   // We have added an instruction to the module, so need to be careful about the
   // validity of existing analyses.
-  context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
+  context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
 }
 
-protobufs::TransformationAddConstantBoolean
-MakeTransformationAddConstantBoolean(uint32_t fresh_id, bool is_true) {
-  protobufs::TransformationAddConstantBoolean result;
-  result.set_fresh_id(fresh_id);
-  result.set_is_true(is_true);
+protobufs::Transformation TransformationAddConstantBoolean::ToMessage() const {
+  protobufs::Transformation result;
+  *result.mutable_add_constant_boolean() = message_;
   return result;
 }
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools

+ 20 - 13
3rdparty/spirv-tools/source/fuzz/transformation_add_constant_boolean.h

@@ -17,27 +17,34 @@
 
 #include "source/fuzz/fact_manager.h"
 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
 #include "source/opt/ir_context.h"
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-// - |fresh_id| must not be used by the module.
-// - The module must already contain OpTypeBool.
-bool IsApplicable(const protobufs::TransformationAddConstantBoolean& message,
-                  opt::IRContext* context, const FactManager& fact_manager);
+class TransformationAddConstantBoolean : public Transformation {
+ public:
+  explicit TransformationAddConstantBoolean(
+      const protobufs::TransformationAddConstantBoolean& message);
 
-// - Adds OpConstantTrue (OpConstantFalse) to the module with id |fresh_id|
-// if |is_true| holds (does not hold).
-void Apply(const protobufs::TransformationAddConstantBoolean& message,
-           opt::IRContext* context, FactManager* fact_manager);
+  TransformationAddConstantBoolean(uint32_t fresh_id, bool is_true);
 
-// Helper factory to create a transformation message.
-protobufs::TransformationAddConstantBoolean
-MakeTransformationAddConstantBoolean(uint32_t fresh_id, bool is_true);
+  // - |message_.fresh_id| must not be used by the module.
+  // - The module must already contain OpTypeBool.
+  bool IsApplicable(opt::IRContext* context,
+                    const FactManager& fact_manager) const override;
+
+  // - Adds OpConstantTrue (OpConstantFalse) to the module with id
+  //   |message_.fresh_id| if |message_.is_true| holds (does not hold).
+  void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+  protobufs::Transformation ToMessage() const override;
+
+ private:
+  protobufs::TransformationAddConstantBoolean message_;
+};
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools
 

+ 28 - 24
3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.cpp

@@ -18,19 +18,29 @@
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-using opt::IRContext;
+TransformationAddConstantScalar::TransformationAddConstantScalar(
+    const spvtools::fuzz::protobufs::TransformationAddConstantScalar& message)
+    : message_(message) {}
 
-bool IsApplicable(const protobufs::TransformationAddConstantScalar& message,
-                  IRContext* context,
-                  const spvtools::fuzz::FactManager& /*unused*/) {
+TransformationAddConstantScalar::TransformationAddConstantScalar(
+    uint32_t fresh_id, uint32_t type_id, std::vector<uint32_t> words) {
+  message_.set_fresh_id(fresh_id);
+  message_.set_type_id(type_id);
+  for (auto word : words) {
+    message_.add_word(word);
+  }
+}
+
+bool TransformationAddConstantScalar::IsApplicable(
+    opt::IRContext* context,
+    const spvtools::fuzz::FactManager& /*unused*/) const {
   // The id needs to be fresh.
-  if (!fuzzerutil::IsFreshId(context, message.fresh_id())) {
+  if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
     return false;
   }
   // The type id for the scalar must exist and be a type.
-  auto type = context->get_type_mgr()->GetType(message.type_id());
+  auto type = context->get_type_mgr()->GetType(message_.type_id());
   if (!type) {
     return false;
   }
@@ -47,37 +57,31 @@ bool IsApplicable(const protobufs::TransformationAddConstantScalar& message,
 
   // The number of words provided by the transformation needs to match the
   // width of the type.
-  return static_cast<uint32_t>(message.word().size()) == words;
+  return static_cast<uint32_t>(message_.word().size()) == words;
 }
 
-void Apply(const protobufs::TransformationAddConstantScalar& message,
-           IRContext* context, spvtools::fuzz::FactManager* /*unused*/) {
+void TransformationAddConstantScalar::Apply(
+    opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const {
   opt::Instruction::OperandList operand_list;
-  for (auto word : message.word()) {
+  for (auto word : message_.word()) {
     operand_list.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {word}});
   }
   context->module()->AddGlobalValue(
-      MakeUnique<opt::Instruction>(context, SpvOpConstant, message.type_id(),
-                                   message.fresh_id(), operand_list));
+      MakeUnique<opt::Instruction>(context, SpvOpConstant, message_.type_id(),
+                                   message_.fresh_id(), operand_list));
 
-  fuzzerutil::UpdateModuleIdBound(context, message.fresh_id());
+  fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
 
   // We have added an instruction to the module, so need to be careful about the
   // validity of existing analyses.
-  context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
+  context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
 }
 
-protobufs::TransformationAddConstantScalar MakeTransformationAddConstantScalar(
-    uint32_t fresh_id, uint32_t type_id, std::vector<uint32_t> words) {
-  protobufs::TransformationAddConstantScalar result;
-  result.set_fresh_id(fresh_id);
-  result.set_type_id(type_id);
-  for (auto word : words) {
-    result.add_word(word);
-  }
+protobufs::Transformation TransformationAddConstantScalar::ToMessage() const {
+  protobufs::Transformation result;
+  *result.mutable_add_constant_scalar() = message_;
   return result;
 }
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools

+ 22 - 13
3rdparty/spirv-tools/source/fuzz/transformation_add_constant_scalar.h

@@ -19,27 +19,36 @@
 
 #include "source/fuzz/fact_manager.h"
 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
 #include "source/opt/ir_context.h"
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-// - |message.fresh_id| must not be used by the module
-// - |message.type_id| must be the id of a floating-point or integer type
-// - The size of |message.word| must be compatible with the width of this type
-bool IsApplicable(const protobufs::TransformationAddConstantScalar& message,
-                  opt::IRContext* context, const FactManager& fact_manager);
+class TransformationAddConstantScalar : public Transformation {
+ public:
+  explicit TransformationAddConstantScalar(
+      const protobufs::TransformationAddConstantScalar& message);
 
-// Adds a new OpConstant instruction with the given type and words.
-void Apply(const protobufs::TransformationAddConstantScalar& message,
-           opt::IRContext* context, FactManager* fact_manager);
+  TransformationAddConstantScalar(uint32_t fresh_id, uint32_t type_id,
+                                  std::vector<uint32_t> words);
 
-// Helper factory to create a transformation message.
-protobufs::TransformationAddConstantScalar MakeTransformationAddConstantScalar(
-    uint32_t fresh_id, uint32_t type_id, std::vector<uint32_t> words);
+  // - |message_.fresh_id| must not be used by the module
+  // - |message_.type_id| must be the id of a floating-point or integer type
+  // - The size of |message_.word| must be compatible with the width of this
+  //   type
+  bool IsApplicable(opt::IRContext* context,
+                    const FactManager& fact_manager) const override;
+
+  // Adds a new OpConstant instruction with the given type and words.
+  void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+  protobufs::Transformation ToMessage() const override;
+
+ private:
+  protobufs::TransformationAddConstantScalar message_;
+};
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools
 

+ 60 - 63
3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.cpp

@@ -21,15 +21,24 @@
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-using opt::BasicBlock;
-using opt::IRContext;
-using opt::Instruction;
+TransformationAddDeadBreak::TransformationAddDeadBreak(
+    const spvtools::fuzz::protobufs::TransformationAddDeadBreak& message)
+    : message_(message) {}
 
-namespace {
+TransformationAddDeadBreak::TransformationAddDeadBreak(
+    uint32_t from_block, uint32_t to_block, bool break_condition_value,
+    std::vector<uint32_t> phi_id) {
+  message_.set_from_block(from_block);
+  message_.set_to_block(to_block);
+  message_.set_break_condition_value(break_condition_value);
+  for (auto id : phi_id) {
+    message_.add_phi_id(id);
+  }
+}
 
-BasicBlock* MaybeFindBlock(IRContext* context, uint32_t maybe_block_id) {
+opt::BasicBlock* TransformationAddDeadBreak::MaybeFindBlock(
+    opt::IRContext* context, uint32_t maybe_block_id) const {
   auto inst = context->get_def_use_mgr()->GetDef(maybe_block_id);
   if (inst == nullptr) {
     // No instruction defining this id was found.
@@ -43,14 +52,15 @@ BasicBlock* MaybeFindBlock(IRContext* context, uint32_t maybe_block_id) {
   return context->cfg()->block(maybe_block_id);
 }
 
-bool PhiIdsOk(const protobufs::TransformationAddDeadBreak& message,
-              IRContext* context, BasicBlock* bb_from, BasicBlock* bb_to) {
+bool TransformationAddDeadBreak::PhiIdsOk(opt::IRContext* context,
+                                          opt::BasicBlock* bb_from,
+                                          opt::BasicBlock* bb_to) const {
   if (bb_from->IsSuccessor(bb_to)) {
     // There is already an edge from |from_block| to |to_block|, so there is
     // no need to extend OpPhi instructions.  Do not allow phi ids to be
     // present. This might turn out to be too strict; perhaps it would be OK
     // just to ignore the ids in this case.
-    return message.phi_id().empty();
+    return message_.phi_id().empty();
   }
   // The break would add a previously non-existent edge from |from_block| to
   // |to_block|, so we go through the given phi ids and check that they exactly
@@ -65,14 +75,14 @@ bool PhiIdsOk(const protobufs::TransformationAddDeadBreak& message,
       // a non-OpPhi then we have seen them all.
       break;
     }
-    if (phi_index == static_cast<uint32_t>(message.phi_id().size())) {
+    if (phi_index == static_cast<uint32_t>(message_.phi_id().size())) {
       // Not enough phi ids have been provided to account for the OpPhi
       // instructions.
       return false;
     }
     // Look for an instruction defining the next phi id.
-    Instruction* phi_extension =
-        context->get_def_use_mgr()->GetDef(message.phi_id()[phi_index]);
+    opt::Instruction* phi_extension =
+        context->get_def_use_mgr()->GetDef(message_.phi_id()[phi_index]);
     if (!phi_extension) {
       // The id given to extend this OpPhi does not exist.
       return false;
@@ -101,28 +111,26 @@ bool PhiIdsOk(const protobufs::TransformationAddDeadBreak& message,
   // Reject the transformation if not all of the ids for extending OpPhi
   // instructions are needed. This might turn out to be stricter than necessary;
   // perhaps it would be OK just to not use the ids in this case.
-  return phi_index == static_cast<uint32_t>(message.phi_id().size());
+  return phi_index == static_cast<uint32_t>(message_.phi_id().size());
 }
 
-bool FromBlockIsInLoopContinueConstruct(
-    const protobufs::TransformationAddDeadBreak& message, IRContext* context,
-    uint32_t maybe_loop_header) {
+bool TransformationAddDeadBreak::FromBlockIsInLoopContinueConstruct(
+    opt::IRContext* context, uint32_t maybe_loop_header) const {
   // We deem a block to be part of a loop's continue construct if the loop's
   // continue target dominates the block.
   auto containing_construct_block = context->cfg()->block(maybe_loop_header);
   if (containing_construct_block->IsLoopHeader()) {
     auto continue_target = containing_construct_block->ContinueBlockId();
     if (context->GetDominatorAnalysis(containing_construct_block->GetParent())
-            ->Dominates(continue_target, message.from_block())) {
+            ->Dominates(continue_target, message_.from_block())) {
       return true;
     }
   }
   return false;
 }
 
-bool AddingBreakRespectsStructuredControlFlow(
-    const protobufs::TransformationAddDeadBreak& message, IRContext* context,
-    BasicBlock* bb_from) {
+bool TransformationAddDeadBreak::AddingBreakRespectsStructuredControlFlow(
+    opt::IRContext* context, opt::BasicBlock* bb_from) const {
   // Look at the structured control flow associated with |from_block| and
   // check whether it is contained in an appropriate construct with merge id
   // |to_block| such that a break from |from_block| to |to_block| is legal.
@@ -146,7 +154,7 @@ bool AddingBreakRespectsStructuredControlFlow(
   if (bb_from->IsLoopHeader()) {
     // Case (1) holds if |to_block| is the merge block for the loop;
     // otherwise no case holds
-    return bb_from->MergeBlockId() == message.to_block();
+    return bb_from->MergeBlockId() == message_.to_block();
   }
 
   // Both cases (2) and (3) require that |from_block| is inside some
@@ -154,14 +162,14 @@ bool AddingBreakRespectsStructuredControlFlow(
 
   auto containing_construct =
       context->GetStructuredCFGAnalysis()->ContainingConstruct(
-          message.from_block());
+          message_.from_block());
   if (!containing_construct) {
     // |from_block| is not in a construct from which we can break.
     return false;
   }
 
   // Consider case (2)
-  if (message.to_block() ==
+  if (message_.to_block() ==
       context->cfg()->block(containing_construct)->MergeBlockId()) {
     // This looks like an instance of case (2).
     // However, the structured CFG analysis regards the continue construct of a
@@ -172,27 +180,24 @@ bool AddingBreakRespectsStructuredControlFlow(
     // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2577): We do not
     //  currently allow a dead break from a back edge block, but we could and
     //  ultimately should.
-    return !FromBlockIsInLoopContinueConstruct(message, context,
-                                               containing_construct);
+    return !FromBlockIsInLoopContinueConstruct(context, containing_construct);
   }
 
   // Case (3) holds if and only if |to_block| is the merge block for this
   // innermost loop that contains |from_block|
   auto containing_loop_header =
-      context->GetStructuredCFGAnalysis()->ContainingLoop(message.from_block());
+      context->GetStructuredCFGAnalysis()->ContainingLoop(
+          message_.from_block());
   if (containing_loop_header &&
-      message.to_block() ==
+      message_.to_block() ==
           context->cfg()->block(containing_loop_header)->MergeBlockId()) {
-    return !FromBlockIsInLoopContinueConstruct(message, context,
-                                               containing_loop_header);
+    return !FromBlockIsInLoopContinueConstruct(context, containing_loop_header);
   }
   return false;
 }
 
-}  // namespace
-
-bool IsApplicable(const protobufs::TransformationAddDeadBreak& message,
-                  IRContext* context, const FactManager& /*unused*/) {
+bool TransformationAddDeadBreak::IsApplicable(
+    opt::IRContext* context, const FactManager& /*unused*/) const {
   // First, we check that a constant with the same value as
   // |break_condition_value| is present.
   opt::analysis::Bool bool_type;
@@ -202,7 +207,7 @@ bool IsApplicable(const protobufs::TransformationAddDeadBreak& message,
     return false;
   }
   opt::analysis::BoolConstant bool_constant(registered_bool_type->AsBool(),
-                                            message.break_condition_value());
+                                            message_.break_condition_value());
   if (!context->get_constant_mgr()->FindConstant(&bool_constant)) {
     // The required constant is not present, so the transformation cannot be
     // applied.
@@ -210,11 +215,11 @@ bool IsApplicable(const protobufs::TransformationAddDeadBreak& message,
   }
 
   // Check that |from_block| and |to_block| really are block ids
-  BasicBlock* bb_from = MaybeFindBlock(context, message.from_block());
+  opt::BasicBlock* bb_from = MaybeFindBlock(context, message_.from_block());
   if (bb_from == nullptr) {
     return false;
   }
-  BasicBlock* bb_to = MaybeFindBlock(context, message.to_block());
+  opt::BasicBlock* bb_to = MaybeFindBlock(context, message_.to_block());
   if (bb_to == nullptr) {
     return false;
   }
@@ -229,36 +234,36 @@ bool IsApplicable(const protobufs::TransformationAddDeadBreak& message,
   assert(bb_from != nullptr &&
          "We should have found a block if this line of code is reached.");
   assert(
-      bb_from->id() == message.from_block() &&
+      bb_from->id() == message_.from_block() &&
       "The id of the block we found should match the source id for the break.");
   assert(bb_to != nullptr &&
          "We should have found a block if this line of code is reached.");
   assert(
-      bb_to->id() == message.to_block() &&
+      bb_to->id() == message_.to_block() &&
       "The id of the block we found should match the target id for the break.");
 
   // Check whether the data passed to extend OpPhi instructions is appropriate.
-  if (!PhiIdsOk(message, context, bb_from, bb_to)) {
+  if (!PhiIdsOk(context, bb_from, bb_to)) {
     return false;
   }
 
   // Finally, check that adding the break would respect the rules of structured
   // control flow.
-  return AddingBreakRespectsStructuredControlFlow(message, context, bb_from);
+  return AddingBreakRespectsStructuredControlFlow(context, bb_from);
 }
 
-void Apply(const protobufs::TransformationAddDeadBreak& message,
-           IRContext* context, FactManager* /*unused*/) {
+void TransformationAddDeadBreak::Apply(opt::IRContext* context,
+                                       FactManager* /*unused*/) const {
   // Get the id of the boolean constant to be used as the break condition.
   opt::analysis::Bool bool_type;
   opt::analysis::BoolConstant bool_constant(
       context->get_type_mgr()->GetRegisteredType(&bool_type)->AsBool(),
-      message.break_condition_value());
+      message_.break_condition_value());
   uint32_t bool_id = context->get_constant_mgr()->FindDeclaredConstant(
       &bool_constant, context->get_type_mgr()->GetId(&bool_type));
 
-  auto bb_from = context->cfg()->block(message.from_block());
-  auto bb_to = context->cfg()->block(message.to_block());
+  auto bb_from = context->cfg()->block(message_.from_block());
+  auto bb_to = context->cfg()->block(message_.to_block());
   const bool from_to_edge_already_exists = bb_from->IsSuccessor(bb_to);
   auto successor = bb_from->terminator()->GetSingleWordInOperand(0);
   assert(bb_from->terminator()->opcode() == SpvOpBranch &&
@@ -272,9 +277,9 @@ void Apply(const protobufs::TransformationAddDeadBreak& message,
   bb_from->terminator()->SetInOperands(
       {{SPV_OPERAND_TYPE_ID, {bool_id}},
        {SPV_OPERAND_TYPE_ID,
-        {message.break_condition_value() ? successor : message.to_block()}},
+        {message_.break_condition_value() ? successor : message_.to_block()}},
        {SPV_OPERAND_TYPE_ID,
-        {message.break_condition_value() ? message.to_block() : successor}}});
+        {message_.break_condition_value() ? message_.to_block() : successor}}});
 
   // Update OpPhi instructions in the target block if this break adds a
   // previously non-existent edge from source to target.
@@ -284,33 +289,25 @@ void Apply(const protobufs::TransformationAddDeadBreak& message,
       if (inst.opcode() != SpvOpPhi) {
         break;
       }
-      assert(phi_index < static_cast<uint32_t>(message.phi_id().size()) &&
+      assert(phi_index < static_cast<uint32_t>(message_.phi_id().size()) &&
              "There should be exactly one phi id per OpPhi instruction.");
-      inst.AddOperand({SPV_OPERAND_TYPE_ID, {message.phi_id()[phi_index]}});
-      inst.AddOperand({SPV_OPERAND_TYPE_ID, {message.from_block()}});
+      inst.AddOperand({SPV_OPERAND_TYPE_ID, {message_.phi_id()[phi_index]}});
+      inst.AddOperand({SPV_OPERAND_TYPE_ID, {message_.from_block()}});
       phi_index++;
     }
-    assert(phi_index == static_cast<uint32_t>(message.phi_id().size()) &&
+    assert(phi_index == static_cast<uint32_t>(message_.phi_id().size()) &&
            "There should be exactly one phi id per OpPhi instruction.");
   }
 
   // Invalidate all analyses
-  context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
+  context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
 }
 
-protobufs::TransformationAddDeadBreak MakeTransformationAddDeadBreak(
-    uint32_t from_block, uint32_t to_block, bool break_condition_value,
-    std::vector<uint32_t> phi_id) {
-  protobufs::TransformationAddDeadBreak result;
-  result.set_from_block(from_block);
-  result.set_to_block(to_block);
-  result.set_break_condition_value(break_condition_value);
-  for (auto id : phi_id) {
-    result.add_phi_id(id);
-  }
+protobufs::Transformation TransformationAddDeadBreak::ToMessage() const {
+  protobufs::Transformation result;
+  *result.mutable_add_dead_break() = message_;
   return result;
 }
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools

+ 60 - 32
3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.h

@@ -19,42 +19,70 @@
 
 #include "source/fuzz/fact_manager.h"
 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
 #include "source/opt/ir_context.h"
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
-
-// - |message.from_block| must be the id of a block a in the given module.
-// - |message.to_block| must be the id of a block b in the given module.
-// - if |message.break_condition_value| holds (does not hold) then
-//   OpConstantTrue (OpConstantFalse) must be present in the module
-// - |message.phi_ids| must be a list of ids that are all available at
-//   |message.from_block|
-// - a and b must be in the same function.
-// - b must be a merge block.
-// - a must end with an unconditional branch to some block c.
-// - replacing this branch with a conditional branch to b or c, with
-//   the boolean constant associated with |message.break_condition_value| as
-//   the condition, and the ids in |message.phi_ids| used to extend
-//   any OpPhi instructions at b as a result of the edge from a, must
-//   maintain validity of the module.
-bool IsApplicable(const protobufs::TransformationAddDeadBreak& message,
-                  opt::IRContext* context, const FactManager& fact_manager);
-
-// Replaces the terminator of a with a conditional branch to b or c.
-// The boolean constant associated with |message.break_condition_value| is used
-// as the condition, and the order of b and c is arranged such that control is
-// guaranteed to jump to c.
-void Apply(const protobufs::TransformationAddDeadBreak& message,
-           opt::IRContext* context, FactManager* fact_manager);
-
-// Helper factory to create a transformation message.
-protobufs::TransformationAddDeadBreak MakeTransformationAddDeadBreak(
-    uint32_t from_block, uint32_t to_block, bool break_condition_value,
-    std::vector<uint32_t> phi_ids);
-
-}  // namespace transformation
+
+class TransformationAddDeadBreak : public Transformation {
+ public:
+  explicit TransformationAddDeadBreak(
+      const protobufs::TransformationAddDeadBreak& message);
+
+  TransformationAddDeadBreak(uint32_t from_block, uint32_t to_block,
+                             bool break_condition_value,
+                             std::vector<uint32_t> phi_id);
+
+  // - |message.from_block| must be the id of a block a in the given module.
+  // - |message.to_block| must be the id of a block b in the given module.
+  // - if |message.break_condition_value| holds (does not hold) then
+  //   OpConstantTrue (OpConstantFalse) must be present in the module
+  // - |message.phi_ids| must be a list of ids that are all available at
+  //   |message.from_block|
+  // - a and b must be in the same function.
+  // - b must be a merge block.
+  // - a must end with an unconditional branch to some block c.
+  // - replacing this branch with a conditional branch to b or c, with
+  //   the boolean constant associated with |message.break_condition_value| as
+  //   the condition, and the ids in |message.phi_ids| used to extend
+  //   any OpPhi instructions at b as a result of the edge from a, must
+  //   maintain validity of the module.
+  bool IsApplicable(opt::IRContext* context,
+                    const FactManager& fact_manager) const override;
+
+  // Replaces the terminator of a with a conditional branch to b or c.
+  // The boolean constant associated with |message.break_condition_value| is
+  // used as the condition, and the order of b and c is arranged such that
+  // control is guaranteed to jump to c.
+  void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+  protobufs::Transformation ToMessage() const override;
+
+ private:
+  // Return the block with id |maybe_block_id| if it exists, and nullptr
+  // otherwise.
+  opt::BasicBlock* MaybeFindBlock(opt::IRContext* context,
+                                  uint32_t maybe_block_id) const;
+
+  // Returns true if and only if the phi ids associated with |message_| are
+  // sufficient to allow an edge from |bb_from| to |bb_to| to be added.
+  bool PhiIdsOk(opt::IRContext* context, opt::BasicBlock* bb_from,
+                opt::BasicBlock* bb_to) const;
+
+  // Returns true if and only if |message_.from_block| is in the continue
+  // construct of a loop headed at |maybe_loop_header|.
+  bool FromBlockIsInLoopContinueConstruct(opt::IRContext* context,
+                                          uint32_t maybe_loop_header) const;
+
+  // Returns true if and only if adding an edge from |bb_from| to
+  // |message_.to_block| respects structured control flow.
+  bool AddingBreakRespectsStructuredControlFlow(opt::IRContext* context,
+                                                opt::BasicBlock* bb_from) const;
+
+  protobufs::TransformationAddDeadBreak message_;
+};
+
 }  // namespace fuzz
 }  // namespace spvtools
 

+ 19 - 16
3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.cpp

@@ -18,15 +18,20 @@
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-using opt::IRContext;
+TransformationAddTypeBoolean::TransformationAddTypeBoolean(
+    const spvtools::fuzz::protobufs::TransformationAddTypeBoolean& message)
+    : message_(message) {}
 
-bool IsApplicable(const protobufs::TransformationAddTypeBoolean& message,
-                  IRContext* context,
-                  const spvtools::fuzz::FactManager& /*unused*/) {
+TransformationAddTypeBoolean::TransformationAddTypeBoolean(uint32_t fresh_id) {
+  message_.set_fresh_id(fresh_id);
+}
+
+bool TransformationAddTypeBoolean::IsApplicable(
+    opt::IRContext* context,
+    const spvtools::fuzz::FactManager& /*unused*/) const {
   // The id must be fresh.
-  if (!fuzzerutil::IsFreshId(context, message.fresh_id())) {
+  if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
     return false;
   }
 
@@ -35,24 +40,22 @@ bool IsApplicable(const protobufs::TransformationAddTypeBoolean& message,
   return context->get_type_mgr()->GetId(&bool_type) == 0;
 }
 
-void Apply(const protobufs::TransformationAddTypeBoolean& message,
-           IRContext* context, spvtools::fuzz::FactManager* /*unused*/) {
+void TransformationAddTypeBoolean::Apply(
+    opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const {
   opt::Instruction::OperandList empty_operands;
   context->module()->AddType(MakeUnique<opt::Instruction>(
-      context, SpvOpTypeBool, 0, message.fresh_id(), empty_operands));
-  fuzzerutil::UpdateModuleIdBound(context, message.fresh_id());
+      context, SpvOpTypeBool, 0, message_.fresh_id(), empty_operands));
+  fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
   // We have added an instruction to the module, so need to be careful about the
   // validity of existing analyses.
-  context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
+  context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
 }
 
-protobufs::TransformationAddTypeBoolean MakeTransformationAddTypeBoolean(
-    uint32_t fresh_id) {
-  protobufs::TransformationAddTypeBoolean result;
-  result.set_fresh_id(fresh_id);
+protobufs::Transformation TransformationAddTypeBoolean::ToMessage() const {
+  protobufs::Transformation result;
+  *result.mutable_add_type_boolean() = message_;
   return result;
 }
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools

+ 19 - 12
3rdparty/spirv-tools/source/fuzz/transformation_add_type_boolean.h

@@ -17,26 +17,33 @@
 
 #include "source/fuzz/fact_manager.h"
 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
 #include "source/opt/ir_context.h"
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-// - |message.fresh_id| must not be used by the module.
-// - The module must not yet declare OpTypeBoolean
-bool IsApplicable(const protobufs::TransformationAddTypeBoolean& message,
-                  opt::IRContext* context, const FactManager& fact_manager);
+class TransformationAddTypeBoolean : public Transformation {
+ public:
+  explicit TransformationAddTypeBoolean(
+      const protobufs::TransformationAddTypeBoolean& message);
 
-// Adds OpTypeBoolean with |message.fresh_id| as result id.
-void Apply(const protobufs::TransformationAddTypeBoolean& message,
-           opt::IRContext* context, FactManager* fact_manager);
+  explicit TransformationAddTypeBoolean(uint32_t fresh_id);
 
-// Helper factory to create a transformation message.
-protobufs::TransformationAddTypeBoolean MakeTransformationAddTypeBoolean(
-    uint32_t fresh_id);
+  // - |message_.fresh_id| must not be used by the module.
+  // - The module must not yet declare OpTypeBoolean
+  bool IsApplicable(opt::IRContext* context,
+                    const FactManager& fact_manager) const override;
+
+  // Adds OpTypeBoolean with |message_.fresh_id| as result id.
+  void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+  protobufs::Transformation ToMessage() const override;
+
+ private:
+  protobufs::TransformationAddTypeBoolean message_;
+};
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools
 

+ 23 - 19
3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.cpp

@@ -18,44 +18,48 @@
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-using opt::IRContext;
+TransformationAddTypeFloat::TransformationAddTypeFloat(uint32_t fresh_id,
+                                                       uint32_t width) {
+  message_.set_fresh_id(fresh_id);
+  message_.set_width(width);
+}
+
+TransformationAddTypeFloat::TransformationAddTypeFloat(
+    const spvtools::fuzz::protobufs::TransformationAddTypeFloat& message)
+    : message_(message) {}
 
-bool IsApplicable(const protobufs::TransformationAddTypeFloat& message,
-                  IRContext* context,
-                  const spvtools::fuzz::FactManager& /*unused*/) {
+bool TransformationAddTypeFloat::IsApplicable(
+    opt::IRContext* context,
+    const spvtools::fuzz::FactManager& /*unused*/) const {
   // The id must be fresh.
-  if (!fuzzerutil::IsFreshId(context, message.fresh_id())) {
+  if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
     return false;
   }
 
   // Applicable if there is no float type with this width already declared in
   // the module.
-  opt::analysis::Float float_type(message.width());
+  opt::analysis::Float float_type(message_.width());
   return context->get_type_mgr()->GetId(&float_type) == 0;
 }
 
-void Apply(const protobufs::TransformationAddTypeFloat& message,
-           IRContext* context, spvtools::fuzz::FactManager* /*unused*/) {
+void TransformationAddTypeFloat::Apply(
+    opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const {
   opt::Instruction::OperandList width = {
-      {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message.width()}}};
+      {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.width()}}};
   context->module()->AddType(MakeUnique<opt::Instruction>(
-      context, SpvOpTypeFloat, 0, message.fresh_id(), width));
-  fuzzerutil::UpdateModuleIdBound(context, message.fresh_id());
+      context, SpvOpTypeFloat, 0, message_.fresh_id(), width));
+  fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
   // We have added an instruction to the module, so need to be careful about the
   // validity of existing analyses.
-  context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
+  context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
 }
 
-protobufs::TransformationAddTypeFloat MakeTransformationAddTypeFloat(
-    uint32_t fresh_id, uint32_t width) {
-  protobufs::TransformationAddTypeFloat result;
-  result.set_fresh_id(fresh_id);
-  result.set_width(width);
+protobufs::Transformation TransformationAddTypeFloat::ToMessage() const {
+  protobufs::Transformation result;
+  *result.mutable_add_type_float() = message_;
   return result;
 }
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools

+ 20 - 13
3rdparty/spirv-tools/source/fuzz/transformation_add_type_float.h

@@ -17,27 +17,34 @@
 
 #include "source/fuzz/fact_manager.h"
 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
 #include "source/opt/ir_context.h"
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-// - |message.fresh_id| must not be used by the module
-// - The module must not contain an OpTypeFloat instruction with width
-//   |message.width|
-bool IsApplicable(const protobufs::TransformationAddTypeFloat& message,
-                  opt::IRContext* context, const FactManager& fact_manager);
+class TransformationAddTypeFloat : public Transformation {
+ public:
+  explicit TransformationAddTypeFloat(
+      const protobufs::TransformationAddTypeFloat& message);
 
-// Adds an OpTypeFloat instruction to the module with the given width
-void Apply(const protobufs::TransformationAddTypeFloat& message,
-           opt::IRContext* context, FactManager* fact_manager);
+  TransformationAddTypeFloat(uint32_t fresh_id, uint32_t width);
 
-// Helper factory to create a transformation message.
-protobufs::TransformationAddTypeFloat MakeTransformationAddTypeFloat(
-    uint32_t fresh_id, uint32_t width);
+  // - |message_.fresh_id| must not be used by the module
+  // - The module must not contain an OpTypeFloat instruction with width
+  //   |message_.width|
+  bool IsApplicable(opt::IRContext* context,
+                    const FactManager& fact_manager) const override;
+
+  // Adds an OpTypeFloat instruction to the module with the given width
+  void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+  protobufs::Transformation ToMessage() const override;
+
+ private:
+  protobufs::TransformationAddTypeFloat message_;
+};
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools
 

+ 26 - 21
3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.cpp

@@ -18,46 +18,51 @@
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-using opt::IRContext;
+TransformationAddTypeInt::TransformationAddTypeInt(
+    const spvtools::fuzz::protobufs::TransformationAddTypeInt& message)
+    : message_(message) {}
 
-bool IsApplicable(const protobufs::TransformationAddTypeInt& message,
-                  IRContext* context,
-                  const spvtools::fuzz::FactManager& /*unused*/) {
+TransformationAddTypeInt::TransformationAddTypeInt(uint32_t fresh_id,
+                                                   uint32_t width,
+                                                   bool is_signed) {
+  message_.set_fresh_id(fresh_id);
+  message_.set_width(width);
+  message_.set_is_signed(is_signed);
+}
+
+bool TransformationAddTypeInt::IsApplicable(
+    opt::IRContext* context,
+    const spvtools::fuzz::FactManager& /*unused*/) const {
   // The id must be fresh.
-  if (!fuzzerutil::IsFreshId(context, message.fresh_id())) {
+  if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
     return false;
   }
 
   // Applicable if there is no int type with this width and signedness already
   // declared in the module.
-  opt::analysis::Integer int_type(message.width(), message.is_signed());
+  opt::analysis::Integer int_type(message_.width(), message_.is_signed());
   return context->get_type_mgr()->GetId(&int_type) == 0;
 }
 
-void Apply(const protobufs::TransformationAddTypeInt& message,
-           IRContext* context, spvtools::fuzz::FactManager* /*unused*/) {
+void TransformationAddTypeInt::Apply(
+    opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const {
   opt::Instruction::OperandList in_operands = {
-      {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message.width()}},
-      {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message.is_signed() ? 1u : 0u}}};
+      {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.width()}},
+      {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.is_signed() ? 1u : 0u}}};
   context->module()->AddType(MakeUnique<opt::Instruction>(
-      context, SpvOpTypeInt, 0, message.fresh_id(), in_operands));
-  fuzzerutil::UpdateModuleIdBound(context, message.fresh_id());
+      context, SpvOpTypeInt, 0, message_.fresh_id(), in_operands));
+  fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
   // We have added an instruction to the module, so need to be careful about the
   // validity of existing analyses.
-  context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
+  context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
 }
 
-protobufs::TransformationAddTypeInt MakeTransformationAddTypeInt(
-    uint32_t fresh_id, uint32_t width, bool is_signed) {
-  protobufs::TransformationAddTypeInt result;
-  result.set_fresh_id(fresh_id);
-  result.set_width(width);
-  result.set_is_signed(is_signed);
+protobufs::Transformation TransformationAddTypeInt::ToMessage() const {
+  protobufs::Transformation result;
+  *result.mutable_add_type_int() = message_;
   return result;
 }
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools

+ 21 - 14
3rdparty/spirv-tools/source/fuzz/transformation_add_type_int.h

@@ -17,28 +17,35 @@
 
 #include "source/fuzz/fact_manager.h"
 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
 #include "source/opt/ir_context.h"
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-// - |message.fresh_id| must not be used by the module
-// - The module must not contain an OpTypeInt instruction with width
-//   |message.width| and signedness |message.is_signed|
-bool IsApplicable(const protobufs::TransformationAddTypeInt& message,
-                  opt::IRContext* context, const FactManager& fact_manager);
+class TransformationAddTypeInt : public Transformation {
+ public:
+  explicit TransformationAddTypeInt(
+      const protobufs::TransformationAddTypeInt& message);
 
-// Adds an OpTypeInt instruction to the module with the given width and
-// signedness.
-void Apply(const protobufs::TransformationAddTypeInt& message,
-           opt::IRContext* context, FactManager* fact_manager);
+  TransformationAddTypeInt(uint32_t fresh_id, uint32_t width, bool is_signed);
 
-// Helper factory to create a transformation message.
-protobufs::TransformationAddTypeInt MakeTransformationAddTypeInt(
-    uint32_t fresh_id, uint32_t width, bool is_signed);
+  // - |message_.fresh_id| must not be used by the module
+  // - The module must not contain an OpTypeInt instruction with width
+  //   |message_.width| and signedness |message.is_signed|
+  bool IsApplicable(opt::IRContext* context,
+                    const FactManager& fact_manager) const override;
+
+  // Adds an OpTypeInt instruction to the module with the given width and
+  // signedness.
+  void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+  protobufs::Transformation ToMessage() const override;
+
+ private:
+  protobufs::TransformationAddTypeInt message_;
+};
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools
 

+ 25 - 21
3rdparty/spirv-tools/source/fuzz/transformation_add_type_pointer.cpp

@@ -18,44 +18,48 @@
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-using opt::IRContext;
+TransformationAddTypePointer::TransformationAddTypePointer(
+    const spvtools::fuzz::protobufs::TransformationAddTypePointer& message)
+    : message_(message) {}
 
-bool IsApplicable(const protobufs::TransformationAddTypePointer& message,
-                  IRContext* context,
-                  const spvtools::fuzz::FactManager& /*unused*/) {
+TransformationAddTypePointer::TransformationAddTypePointer(
+    uint32_t fresh_id, SpvStorageClass storage_class, uint32_t base_type_id) {
+  message_.set_fresh_id(fresh_id);
+  message_.set_storage_class(storage_class);
+  message_.set_base_type_id(base_type_id);
+}
+
+bool TransformationAddTypePointer::IsApplicable(
+    opt::IRContext* context,
+    const spvtools::fuzz::FactManager& /*unused*/) const {
   // The id must be fresh.
-  if (!fuzzerutil::IsFreshId(context, message.fresh_id())) {
+  if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
     return false;
   }
   // The base type must be known.
-  return context->get_type_mgr()->GetType(message.base_type_id()) != nullptr;
+  return context->get_type_mgr()->GetType(message_.base_type_id()) != nullptr;
 }
 
-void Apply(const protobufs::TransformationAddTypePointer& message,
-           IRContext* context, spvtools::fuzz::FactManager* /*unused*/) {
+void TransformationAddTypePointer::Apply(
+    opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const {
   // Add the pointer type.
   opt::Instruction::OperandList in_operands = {
-      {SPV_OPERAND_TYPE_STORAGE_CLASS, {message.storage_class()}},
-      {SPV_OPERAND_TYPE_ID, {message.base_type_id()}}};
+      {SPV_OPERAND_TYPE_STORAGE_CLASS, {message_.storage_class()}},
+      {SPV_OPERAND_TYPE_ID, {message_.base_type_id()}}};
   context->module()->AddType(MakeUnique<opt::Instruction>(
-      context, SpvOpTypePointer, 0, message.fresh_id(), in_operands));
-  fuzzerutil::UpdateModuleIdBound(context, message.fresh_id());
+      context, SpvOpTypePointer, 0, message_.fresh_id(), in_operands));
+  fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
   // We have added an instruction to the module, so need to be careful about the
   // validity of existing analyses.
-  context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
+  context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
 }
 
-protobufs::TransformationAddTypePointer MakeTransformationAddTypePointer(
-    uint32_t fresh_id, SpvStorageClass storage_class, uint32_t base_type_id) {
-  protobufs::TransformationAddTypePointer result;
-  result.set_fresh_id(fresh_id);
-  result.set_storage_class(storage_class);
-  result.set_base_type_id(base_type_id);
+protobufs::Transformation TransformationAddTypePointer::ToMessage() const {
+  protobufs::Transformation result;
+  *result.mutable_add_type_pointer() = message_;
   return result;
 }
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools

+ 22 - 13
3rdparty/spirv-tools/source/fuzz/transformation_add_type_pointer.h

@@ -17,27 +17,36 @@
 
 #include "source/fuzz/fact_manager.h"
 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
 #include "source/opt/ir_context.h"
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-// - |message.fresh_id| must not be used by the module
-// - |message.base_type_id| must be the result id of an OpType[...] instruction
-bool IsApplicable(const protobufs::TransformationAddTypePointer& message,
-                  opt::IRContext* context, const FactManager& fact_manager);
+class TransformationAddTypePointer : public Transformation {
+ public:
+  explicit TransformationAddTypePointer(
+      const protobufs::TransformationAddTypePointer& message);
 
-// Adds an OpTypePointer instruction with the given storage class and base type
-// to the module.
-void Apply(const protobufs::TransformationAddTypePointer& message,
-           opt::IRContext* context, FactManager* fact_manager);
+  TransformationAddTypePointer(uint32_t fresh_id, SpvStorageClass storage_class,
+                               uint32_t base_type_id);
 
-// Helper factory to create a transformation message.
-protobufs::TransformationAddTypePointer MakeTransformationAddTypePointer(
-    uint32_t fresh_id, SpvStorageClass storage_class, uint32_t base_type_id);
+  // - |message_.fresh_id| must not be used by the module
+  // - |message_.base_type_id| must be the result id of an OpType[...]
+  // instruction
+  bool IsApplicable(opt::IRContext* context,
+                    const FactManager& fact_manager) const override;
+
+  // Adds an OpTypePointer instruction with the given storage class and base
+  // type to the module.
+  void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+  protobufs::Transformation ToMessage() const override;
+
+ private:
+  protobufs::TransformationAddTypePointer message_;
+};
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools
 

+ 26 - 19
3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.cpp

@@ -18,19 +18,23 @@
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-using opt::BasicBlock;
-using opt::IRContext;
+TransformationMoveBlockDown::TransformationMoveBlockDown(
+    const spvtools::fuzz::protobufs::TransformationMoveBlockDown& message)
+    : message_(message) {}
 
-bool IsApplicable(const protobufs::TransformationMoveBlockDown& message,
-                  IRContext* context, const FactManager& /*unused*/) {
+TransformationMoveBlockDown::TransformationMoveBlockDown(uint32_t id) {
+  message_.set_block_id(id);
+}
+
+bool TransformationMoveBlockDown::IsApplicable(
+    opt::IRContext* context, const FactManager& /*unused*/) const {
   // Go through every block in every function, looking for a block whose id
   // matches that of the block we want to consider moving down.
   for (auto& function : *context->module()) {
     for (auto block_it = function.begin(); block_it != function.end();
          ++block_it) {
-      if (block_it->id() == message.block_id()) {
+      if (block_it->id() == message_.block_id()) {
         // We have found a match.
         if (block_it == function.begin()) {
           // The block is the first one appearing in the function.  We are not
@@ -38,7 +42,12 @@ bool IsApplicable(const protobufs::TransformationMoveBlockDown& message,
           return false;
         }
         // Record the block we would like to consider moving down.
-        BasicBlock* block_matching_id = &*block_it;
+        opt::BasicBlock* block_matching_id = &*block_it;
+        if (!context->GetDominatorAnalysis(&function)->IsReachable(
+                block_matching_id)) {
+          // The block is not reachable.  We are not allowed to move it down.
+          return false;
+        }
         // Now see whether there is some block following that block in program
         // order.
         ++block_it;
@@ -48,7 +57,7 @@ bool IsApplicable(const protobufs::TransformationMoveBlockDown& message,
           // apply.
           return false;
         }
-        BasicBlock* next_block_in_program_order = &*block_it;
+        opt::BasicBlock* next_block_in_program_order = &*block_it;
         // We can move the block of interest down if and only if it does not
         // dominate the block that comes next.
         return !context->GetDominatorAnalysis(&function)->Dominates(
@@ -62,26 +71,26 @@ bool IsApplicable(const protobufs::TransformationMoveBlockDown& message,
   return false;
 }
 
-void Apply(const protobufs::TransformationMoveBlockDown& message,
-           IRContext* context, FactManager* /*unused*/) {
+void TransformationMoveBlockDown::Apply(opt::IRContext* context,
+                                        FactManager* /*unused*/) const {
   // Go through every block in every function, looking for a block whose id
   // matches that of the block we want to move down.
   for (auto& function : *context->module()) {
     for (auto block_it = function.begin(); block_it != function.end();
          ++block_it) {
-      if (block_it->id() == message.block_id()) {
+      if (block_it->id() == message_.block_id()) {
         ++block_it;
         assert(block_it != function.end() &&
                "To be able to move a block down, it needs to have a "
                "program-order successor.");
-        function.MoveBasicBlockToAfter(message.block_id(), &*block_it);
+        function.MoveBasicBlockToAfter(message_.block_id(), &*block_it);
         // It is prudent to invalidate analyses after changing block ordering in
         // case any of them depend on it, but the ones that definitely do not
         // depend on ordering can be preserved. These include the following,
         // which can likely be extended.
         context->InvalidateAnalysesExceptFor(
-            IRContext::Analysis::kAnalysisDefUse |
-            IRContext::Analysis::kAnalysisDominatorAnalysis);
+            opt::IRContext::Analysis::kAnalysisDefUse |
+            opt::IRContext::Analysis::kAnalysisDominatorAnalysis);
 
         return;
       }
@@ -90,13 +99,11 @@ void Apply(const protobufs::TransformationMoveBlockDown& message,
   assert(false && "No block was found to move down.");
 }
 
-protobufs::TransformationMoveBlockDown MakeTransformationMoveBlockDown(
-    uint32_t id) {
-  protobufs::TransformationMoveBlockDown result;
-  result.set_block_id(id);
+protobufs::Transformation TransformationMoveBlockDown::ToMessage() const {
+  protobufs::Transformation result;
+  *result.mutable_move_block_down() = message_;
   return result;
 }
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools

+ 23 - 15
3rdparty/spirv-tools/source/fuzz/transformation_move_block_down.h

@@ -17,29 +17,37 @@
 
 #include "source/fuzz/fact_manager.h"
 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
 #include "source/opt/ir_context.h"
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-// - |block_id| must be the id of a block b in the given module.
-// - b must not be the first nor last block appearing, in program order,
-//   in a function.
-// - b must not dominate the block that follows it in program order.
-bool IsApplicable(const protobufs::TransformationMoveBlockDown& message,
-                  opt::IRContext* context, const FactManager& fact_manager);
+class TransformationMoveBlockDown : public Transformation {
+ public:
+  explicit TransformationMoveBlockDown(
+      const protobufs::TransformationMoveBlockDown& message);
 
-// The block with id |block_id| is moved down; i.e. the program order
-// between it and the block that follows it is swapped.
-void Apply(const protobufs::TransformationMoveBlockDown& message,
-           opt::IRContext* context, FactManager* fact_manager);
+  explicit TransformationMoveBlockDown(uint32_t id);
 
-// Creates a protobuf message to move down the block with id |id|.
-protobufs::TransformationMoveBlockDown MakeTransformationMoveBlockDown(
-    uint32_t id);
+  // - |message_.block_id| must be the id of a block b in the given module.
+  // - b must not be the first nor last block appearing, in program order,
+  //   in a function.
+  // - b must not dominate the block that follows it in program order.
+  // - b must be reachable.
+  bool IsApplicable(opt::IRContext* context,
+                    const FactManager& fact_manager) const override;
+
+  // The block with id |message_.block_id| is moved down; i.e. the program order
+  // between it and the block that follows it is swapped.
+  void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+  protobufs::Transformation ToMessage() const override;
+
+ private:
+  protobufs::TransformationMoveBlockDown message_;
+};
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools
 

+ 50 - 37
3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp

@@ -21,7 +21,6 @@
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
 namespace {
 
@@ -110,19 +109,35 @@ bool unsigned_int_binop_evaluates_to(T lhs, T rhs, SpvOp binop,
 
 }  // namespace
 
-bool IsApplicable(
-    const protobufs::TransformationReplaceBooleanConstantWithConstantBinary&
-        message,
-    opt::IRContext* context, const FactManager& /*unused*/) {
+TransformationReplaceBooleanConstantWithConstantBinary::
+    TransformationReplaceBooleanConstantWithConstantBinary(
+        const spvtools::fuzz::protobufs::
+            TransformationReplaceBooleanConstantWithConstantBinary& message)
+    : message_(message) {}
+
+TransformationReplaceBooleanConstantWithConstantBinary::
+    TransformationReplaceBooleanConstantWithConstantBinary(
+        const protobufs::IdUseDescriptor& id_use_descriptor, uint32_t lhs_id,
+        uint32_t rhs_id, SpvOp comparison_opcode,
+        uint32_t fresh_id_for_binary_operation) {
+  *message_.mutable_id_use_descriptor() = id_use_descriptor;
+  message_.set_lhs_id(lhs_id);
+  message_.set_rhs_id(rhs_id);
+  message_.set_opcode(comparison_opcode);
+  message_.set_fresh_id_for_binary_operation(fresh_id_for_binary_operation);
+}
+
+bool TransformationReplaceBooleanConstantWithConstantBinary::IsApplicable(
+    opt::IRContext* context, const FactManager& /*unused*/) const {
   // The id for the binary result must be fresh
   if (!fuzzerutil::IsFreshId(context,
-                             message.fresh_id_for_binary_operation())) {
+                             message_.fresh_id_for_binary_operation())) {
     return false;
   }
 
   // The used id must be for a boolean constant
   auto boolean_constant = context->get_def_use_mgr()->GetDef(
-      message.id_use_descriptor().id_of_interest());
+      message_.id_use_descriptor().id_of_interest());
   if (!boolean_constant) {
     return false;
   }
@@ -132,7 +147,8 @@ bool IsApplicable(
   }
 
   // The left-hand-side id must correspond to a constant instruction.
-  auto lhs_constant_inst = context->get_def_use_mgr()->GetDef(message.lhs_id());
+  auto lhs_constant_inst =
+      context->get_def_use_mgr()->GetDef(message_.lhs_id());
   if (!lhs_constant_inst) {
     return false;
   }
@@ -141,7 +157,8 @@ bool IsApplicable(
   }
 
   // The right-hand-side id must correspond to a constant instruction.
-  auto rhs_constant_inst = context->get_def_use_mgr()->GetDef(message.rhs_id());
+  auto rhs_constant_inst =
+      context->get_def_use_mgr()->GetDef(message_.rhs_id());
   if (!rhs_constant_inst) {
     return false;
   }
@@ -156,12 +173,12 @@ bool IsApplicable(
 
   // The expression 'LHS opcode RHS' must evaluate to the boolean constant.
   auto lhs_constant =
-      context->get_constant_mgr()->FindDeclaredConstant(message.lhs_id());
+      context->get_constant_mgr()->FindDeclaredConstant(message_.lhs_id());
   auto rhs_constant =
-      context->get_constant_mgr()->FindDeclaredConstant(message.rhs_id());
+      context->get_constant_mgr()->FindDeclaredConstant(message_.rhs_id());
   bool expected_result = (boolean_constant->opcode() == SpvOpConstantTrue);
 
-  const SpvOp binary_opcode = static_cast<SpvOp>(message.opcode());
+  const SpvOp binary_opcode = static_cast<SpvOp>(message_.opcode());
 
   // We consider the floating point, signed and unsigned integer cases
   // separately.  In each case the logic is very similar.
@@ -220,25 +237,29 @@ bool IsApplicable(
   }
 
   // The id use descriptor must identify some instruction
-  return transformation::FindInstruction(message.id_use_descriptor(),
+  return transformation::FindInstruction(message_.id_use_descriptor(),
                                          context) != nullptr;
 }
 
-opt::Instruction* Apply(
-    const protobufs::TransformationReplaceBooleanConstantWithConstantBinary&
-        message,
-    opt::IRContext* context, FactManager* /*unused*/) {
+void TransformationReplaceBooleanConstantWithConstantBinary::Apply(
+    opt::IRContext* context, FactManager* fact_manager) const {
+  ApplyWithResult(context, fact_manager);
+}
+
+opt::Instruction*
+TransformationReplaceBooleanConstantWithConstantBinary::ApplyWithResult(
+    opt::IRContext* context, FactManager* /*unused*/) const {
   opt::analysis::Bool bool_type;
   opt::Instruction::OperandList operands = {
-      {SPV_OPERAND_TYPE_ID, {message.lhs_id()}},
-      {SPV_OPERAND_TYPE_ID, {message.rhs_id()}}};
+      {SPV_OPERAND_TYPE_ID, {message_.lhs_id()}},
+      {SPV_OPERAND_TYPE_ID, {message_.rhs_id()}}};
   auto binary_instruction = MakeUnique<opt::Instruction>(
-      context, static_cast<SpvOp>(message.opcode()),
+      context, static_cast<SpvOp>(message_.opcode()),
       context->get_type_mgr()->GetId(&bool_type),
-      message.fresh_id_for_binary_operation(), operands);
+      message_.fresh_id_for_binary_operation(), operands);
   opt::Instruction* result = binary_instruction.get();
   auto instruction_containing_constant_use =
-      transformation::FindInstruction(message.id_use_descriptor(), context);
+      transformation::FindInstruction(message_.id_use_descriptor(), context);
 
   // We want to insert the new instruction before the instruction that contains
   // the use of the boolean, but we need to go backwards one more instruction if
@@ -255,28 +276,20 @@ opt::Instruction* Apply(
   instruction_before_which_to_insert->InsertBefore(
       std::move(binary_instruction));
   instruction_containing_constant_use->SetInOperand(
-      message.id_use_descriptor().in_operand_index(),
-      {message.fresh_id_for_binary_operation()});
+      message_.id_use_descriptor().in_operand_index(),
+      {message_.fresh_id_for_binary_operation()});
   fuzzerutil::UpdateModuleIdBound(context,
-                                  message.fresh_id_for_binary_operation());
+                                  message_.fresh_id_for_binary_operation());
   context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
   return result;
 }
 
-protobufs::TransformationReplaceBooleanConstantWithConstantBinary
-MakeTransformationReplaceBooleanConstantWithConstantBinary(
-    const protobufs::IdUseDescriptor& id_use_descriptor, uint32_t lhs_id,
-    uint32_t rhs_id, SpvOp comparison_opcode,
-    uint32_t fresh_id_for_binary_operation) {
-  protobufs::TransformationReplaceBooleanConstantWithConstantBinary result;
-  *result.mutable_id_use_descriptor() = id_use_descriptor;
-  result.set_lhs_id(lhs_id);
-  result.set_rhs_id(rhs_id);
-  result.set_opcode(comparison_opcode);
-  result.set_fresh_id_for_binary_operation(fresh_id_for_binary_operation);
+protobufs::Transformation
+TransformationReplaceBooleanConstantWithConstantBinary::ToMessage() const {
+  protobufs::Transformation result;
+  *result.mutable_replace_boolean_constant_with_constant_binary() = message_;
   return result;
 }
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools

+ 43 - 32
3rdparty/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h

@@ -17,42 +17,53 @@
 
 #include "source/fuzz/fact_manager.h"
 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
 #include "source/opt/ir_context.h"
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
-
-// - |message.fresh_id_for_binary_operation| must not already be used by the
-//   module.
-// - |message.id_use_descriptor| must identify a use of a boolean constant c.
-// - |message.lhs_id| and |message.rhs_id| must be the ids of constant
-//   instructions with the same type
-// - |message.opcode| must be suitable for applying to |message.lhs_id| and
-//   |message.rhs_id|, and the result must evaluate to the boolean constant c.
-bool IsApplicable(
-    const protobufs::TransformationReplaceBooleanConstantWithConstantBinary&
-        message,
-    opt::IRContext* context, const FactManager& fact_manager);
-
-// A new instruction is added before the boolean constant usage that computes
-// the result of applying |message.opcode| to |message.lhs_id| and
-// |message.rhs_id| is added, with result id
-// |message.fresh_id_for_binary_operation|.  The boolean constant usage is
-// replaced with this result id.
-opt::Instruction* Apply(
-    const protobufs::TransformationReplaceBooleanConstantWithConstantBinary&
-        message,
-    opt::IRContext* context, FactManager* fact_manager);
-
-// Helper factory to create a transformation message.
-protobufs::TransformationReplaceBooleanConstantWithConstantBinary
-MakeTransformationReplaceBooleanConstantWithConstantBinary(
-    const protobufs::IdUseDescriptor& id_use_descriptor, uint32_t lhs_id,
-    uint32_t rhs_id, SpvOp comparison_opcode,
-    uint32_t fresh_id_for_binary_operation);
-
-}  // namespace transformation
+
+class TransformationReplaceBooleanConstantWithConstantBinary
+    : public Transformation {
+ public:
+  explicit TransformationReplaceBooleanConstantWithConstantBinary(
+      const protobufs::TransformationReplaceBooleanConstantWithConstantBinary&
+          message);
+
+  TransformationReplaceBooleanConstantWithConstantBinary(
+      const protobufs::IdUseDescriptor& id_use_descriptor, uint32_t lhs_id,
+      uint32_t rhs_id, SpvOp comparison_opcode,
+      uint32_t fresh_id_for_binary_operation);
+
+  // - |message_.fresh_id_for_binary_operation| must not already be used by the
+  //   module.
+  // - |message_.id_use_descriptor| must identify a use of a boolean constant c.
+  // - |message_.lhs_id| and |message.rhs_id| must be the ids of constant
+  //   instructions with the same type
+  // - |message_.opcode| must be suitable for applying to |message.lhs_id| and
+  //   |message_.rhs_id|, and the result must evaluate to the boolean constant
+  //   c.
+  bool IsApplicable(opt::IRContext* context,
+                    const FactManager& fact_manager) const override;
+
+  // A new instruction is added before the boolean constant usage that computes
+  // the result of applying |message_.opcode| to |message_.lhs_id| and
+  // |message_.rhs_id| is added, with result id
+  // |message_.fresh_id_for_binary_operation|.  The boolean constant usage is
+  // replaced with this result id.
+  void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+  // The same as Apply, except that the newly-added binary instruction is
+  // returned.
+  opt::Instruction* ApplyWithResult(opt::IRContext* context,
+                                    FactManager* fact_manager) const;
+
+  protobufs::Transformation ToMessage() const override;
+
+ private:
+  protobufs::TransformationReplaceBooleanConstantWithConstantBinary message_;
+};
+
 }  // namespace fuzz
 }  // namespace spvtools
 

+ 55 - 50
3rdparty/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.cpp

@@ -19,18 +19,32 @@
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-namespace {
+TransformationReplaceConstantWithUniform::
+    TransformationReplaceConstantWithUniform(
+        const spvtools::fuzz::protobufs::
+            TransformationReplaceConstantWithUniform& message)
+    : message_(message) {}
+
+TransformationReplaceConstantWithUniform::
+    TransformationReplaceConstantWithUniform(
+        protobufs::IdUseDescriptor id_use,
+        protobufs::UniformBufferElementDescriptor uniform_descriptor,
+        uint32_t fresh_id_for_access_chain, uint32_t fresh_id_for_load) {
+  *message_.mutable_id_use_descriptor() = std::move(id_use);
+  *message_.mutable_uniform_descriptor() = std::move(uniform_descriptor);
+  message_.set_fresh_id_for_access_chain(fresh_id_for_access_chain);
+  message_.set_fresh_id_for_load(fresh_id_for_load);
+}
 
-std::unique_ptr<opt::Instruction> MakeAccessChainInstruction(
-    const protobufs::TransformationReplaceConstantWithUniform& message,
-    spvtools::opt::IRContext* context, uint32_t constant_type_id) {
+std::unique_ptr<opt::Instruction>
+TransformationReplaceConstantWithUniform::MakeAccessChainInstruction(
+    spvtools::opt::IRContext* context, uint32_t constant_type_id) const {
   // The input operands for the access chain.
   opt::Instruction::OperandList operands_for_access_chain;
 
   opt::Instruction* uniform_variable =
-      FindUniformVariable(message.uniform_descriptor(), context, false);
+      FindUniformVariable(message_.uniform_descriptor(), context, false);
 
   // The first input operand is the id of the uniform variable.
   operands_for_access_chain.push_back(
@@ -44,7 +58,7 @@ std::unique_ptr<opt::Instruction> MakeAccessChainInstruction(
   auto registered_int_type =
       context->get_type_mgr()->GetRegisteredType(&int_type)->AsInteger();
   auto int_type_id = context->get_type_mgr()->GetId(&int_type);
-  for (auto index : message.uniform_descriptor().index()) {
+  for (auto index : message_.uniform_descriptor().index()) {
     opt::analysis::IntConstant int_constant(registered_int_type, {index});
     auto constant_id = context->get_constant_mgr()->FindDeclaredConstant(
         &int_constant, int_type_id);
@@ -62,43 +76,40 @@ std::unique_ptr<opt::Instruction> MakeAccessChainInstruction(
 
   return MakeUnique<opt::Instruction>(
       context, SpvOpAccessChain, pointer_to_uniform_constant_type_id,
-      message.fresh_id_for_access_chain(), operands_for_access_chain);
+      message_.fresh_id_for_access_chain(), operands_for_access_chain);
 }
 
-std::unique_ptr<opt::Instruction> MakeLoadInstruction(
-    const protobufs::TransformationReplaceConstantWithUniform& message,
-    spvtools::opt::IRContext* context, uint32_t constant_type_id) {
+std::unique_ptr<opt::Instruction>
+TransformationReplaceConstantWithUniform::MakeLoadInstruction(
+    spvtools::opt::IRContext* context, uint32_t constant_type_id) const {
   opt::Instruction::OperandList operands_for_load = {
-      {SPV_OPERAND_TYPE_ID, {message.fresh_id_for_access_chain()}}};
+      {SPV_OPERAND_TYPE_ID, {message_.fresh_id_for_access_chain()}}};
   return MakeUnique<opt::Instruction>(context, SpvOpLoad, constant_type_id,
-                                      message.fresh_id_for_load(),
+                                      message_.fresh_id_for_load(),
                                       operands_for_load);
 }
 
-}  // namespace
-
-bool IsApplicable(
-    const protobufs::TransformationReplaceConstantWithUniform& message,
+bool TransformationReplaceConstantWithUniform::IsApplicable(
     spvtools::opt::IRContext* context,
-    const spvtools::fuzz::FactManager& fact_manager) {
+    const spvtools::fuzz::FactManager& fact_manager) const {
   // The following is really an invariant of the transformation rather than
   // merely a requirement of the precondition.  We check it here since we cannot
-  // check it in the message constructor.
-  assert(message.fresh_id_for_access_chain() != message.fresh_id_for_load() &&
+  // check it in the message_ constructor.
+  assert(message_.fresh_id_for_access_chain() != message_.fresh_id_for_load() &&
          "Fresh ids for access chain and load result cannot be the same.");
 
   // The ids for the access chain and load instructions must both be fresh.
-  if (!fuzzerutil::IsFreshId(context, message.fresh_id_for_access_chain())) {
+  if (!fuzzerutil::IsFreshId(context, message_.fresh_id_for_access_chain())) {
     return false;
   }
-  if (!fuzzerutil::IsFreshId(context, message.fresh_id_for_load())) {
+  if (!fuzzerutil::IsFreshId(context, message_.fresh_id_for_load())) {
     return false;
   }
 
   // The id specified in the id use descriptor must be that of a declared scalar
   // constant.
   auto declared_constant = context->get_constant_mgr()->FindDeclaredConstant(
-      message.id_use_descriptor().id_of_interest());
+      message_.id_use_descriptor().id_of_interest());
   if (!declared_constant) {
     return false;
   }
@@ -110,7 +121,7 @@ bool IsApplicable(
   // by the uniform buffer element descriptor will hold a scalar value.
   auto constant_id_associated_with_uniform =
       fact_manager.GetConstantFromUniformDescriptor(
-          context, message.uniform_descriptor());
+          context, message_.uniform_descriptor());
   if (!constant_id_associated_with_uniform) {
     return false;
   }
@@ -138,7 +149,7 @@ bool IsApplicable(
   // The id use descriptor must identify some instruction with respect to the
   // module.
   auto instruction_using_constant =
-      transformation::FindInstruction(message.id_use_descriptor(), context);
+      transformation::FindInstruction(message_.id_use_descriptor(), context);
   if (!instruction_using_constant) {
     return false;
   }
@@ -161,7 +172,7 @@ bool IsApplicable(
   auto registered_int_type =
       context->get_type_mgr()->GetRegisteredType(&int_type)->AsInteger();
   auto int_type_id = context->get_type_mgr()->GetId(&int_type);
-  for (auto index : message.uniform_descriptor().index()) {
+  for (auto index : message_.uniform_descriptor().index()) {
     opt::analysis::IntConstant int_constant(registered_int_type, {index});
     if (!context->get_constant_mgr()->FindDeclaredConstant(&int_constant,
                                                            int_type_id)) {
@@ -172,59 +183,53 @@ bool IsApplicable(
   return true;
 }
 
-void Apply(const protobufs::TransformationReplaceConstantWithUniform& message,
-           spvtools::opt::IRContext* context,
-           spvtools::fuzz::FactManager* /*unused*/) {
+void TransformationReplaceConstantWithUniform::Apply(
+    spvtools::opt::IRContext* context,
+    spvtools::fuzz::FactManager* /*unused*/) const {
   // Get the instruction that contains the id use we wish to replace.
   auto instruction_containing_constant_use =
-      transformation::FindInstruction(message.id_use_descriptor(), context);
+      transformation::FindInstruction(message_.id_use_descriptor(), context);
   assert(instruction_containing_constant_use &&
          "Precondition requires that the id use can be found.");
   assert(instruction_containing_constant_use->GetSingleWordInOperand(
-             message.id_use_descriptor().in_operand_index()) ==
-             message.id_use_descriptor().id_of_interest() &&
+             message_.id_use_descriptor().in_operand_index()) ==
+             message_.id_use_descriptor().id_of_interest() &&
          "Does not appear to be a usage of the desired id.");
 
   // The id of the type for the constant whose use we wish to replace.
   auto constant_type_id =
       context->get_def_use_mgr()
-          ->GetDef(message.id_use_descriptor().id_of_interest())
+          ->GetDef(message_.id_use_descriptor().id_of_interest())
           ->type_id();
 
   // Add an access chain instruction to target the uniform element.
   instruction_containing_constant_use->InsertBefore(
-      MakeAccessChainInstruction(message, context, constant_type_id));
+      MakeAccessChainInstruction(context, constant_type_id));
 
   // Add a load from this access chain.
   instruction_containing_constant_use->InsertBefore(
-      MakeLoadInstruction(message, context, constant_type_id));
+      MakeLoadInstruction(context, constant_type_id));
 
   // Adjust the instruction containing the usage of the constant so that this
   // usage refers instead to the result of the load.
   instruction_containing_constant_use->SetInOperand(
-      message.id_use_descriptor().in_operand_index(),
-      {message.fresh_id_for_load()});
+      message_.id_use_descriptor().in_operand_index(),
+      {message_.fresh_id_for_load()});
 
   // Update the module id bound to reflect the new instructions.
-  fuzzerutil::UpdateModuleIdBound(context, message.fresh_id_for_load());
-  fuzzerutil::UpdateModuleIdBound(context, message.fresh_id_for_access_chain());
+  fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id_for_load());
+  fuzzerutil::UpdateModuleIdBound(context,
+                                  message_.fresh_id_for_access_chain());
 
   context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
 }
 
-protobufs::TransformationReplaceConstantWithUniform
-MakeTransformationReplaceConstantWithUniform(
-    protobufs::IdUseDescriptor id_use,
-    protobufs::UniformBufferElementDescriptor uniform_descriptor,
-    uint32_t fresh_id_for_access_chain, uint32_t fresh_id_for_load) {
-  protobufs::TransformationReplaceConstantWithUniform result;
-  *result.mutable_id_use_descriptor() = std::move(id_use);
-  *result.mutable_uniform_descriptor() = std::move(uniform_descriptor);
-  result.set_fresh_id_for_access_chain(fresh_id_for_access_chain);
-  result.set_fresh_id_for_load(fresh_id_for_load);
+protobufs::Transformation TransformationReplaceConstantWithUniform::ToMessage()
+    const {
+  protobufs::Transformation result;
+  *result.mutable_replace_constant_with_uniform() = message_;
   return result;
 }
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools

+ 57 - 39
3rdparty/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.h

@@ -20,53 +20,71 @@
 #include "source/fuzz/fact_manager.h"
 #include "source/fuzz/id_use_descriptor.h"
 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
 #include "source/opt/ir_context.h"
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-// - |fresh_id_for_access_chain| and |fresh_id_for_load| must be distinct fresh
-//   ids.
-// - |uniform_descriptor| specifies a result id and a list of integer literal
-//   indices.
-//   As an example, suppose |uniform_descriptor| is (18, [0, 1, 0])
-//   It is required that:
-//     - the result id (18 in our example) is the id of some uniform variable
-//     - the module contains an integer constant instruction corresponding to
-//       each of the literal indices; in our example there must thus be
-//       OpConstant instructions %A and %B say for each of 0 and 1
-//     - it is legitimate to index into the uniform variable using the
-//       sequence of indices; in our example this means indexing into %18 using
-//       the sequence %A %B %A
-//     - the module contains a uniform pointer type corresponding to the type
-//       of the uniform data element obtained by following these indices
-// - |id_use_descriptor| identifies the use of some id %C.  It is required that:
-//     - this use does indeed exist in the module
-//     - %C is an OpConstant
-//     - According to the fact manager, the uniform data element specified by
-//       |uniform_descriptor| holds a value with the same type and value as %C
-bool IsApplicable(
-    const protobufs::TransformationReplaceConstantWithUniform& message,
-    opt::IRContext* context, const FactManager& fact_manager);
+class TransformationReplaceConstantWithUniform : public Transformation {
+ public:
+  explicit TransformationReplaceConstantWithUniform(
+      const protobufs::TransformationReplaceConstantWithUniform& message);
 
-// - Introduces two new instructions:
-//   - An access chain targeting the uniform data element specified by
-//     |uniform_descriptor|, with result id |fresh_id_for_access_chain|
-//   - A load from this access chain, with id |fresh_id_for_load|
-// - Replaces the id use specified by |id_use_descriptor| with
-//   |fresh_id_for_load|
-void Apply(const protobufs::TransformationReplaceConstantWithUniform& message,
-           opt::IRContext* context, FactManager* fact_manager);
+  TransformationReplaceConstantWithUniform(
+      protobufs::IdUseDescriptor id_use,
+      protobufs::UniformBufferElementDescriptor uniform_descriptor,
+      uint32_t fresh_id_for_access_chain, uint32_t fresh_id_for_load);
 
-// Helper factory to create a transformation message.
-protobufs::TransformationReplaceConstantWithUniform
-MakeTransformationReplaceConstantWithUniform(
-    protobufs::IdUseDescriptor id_use,
-    protobufs::UniformBufferElementDescriptor uniform_descriptor,
-    uint32_t fresh_id_for_access_chain, uint32_t fresh_id_for_load);
+  // - |message_.fresh_id_for_access_chain| and |message_.fresh_id_for_load|
+  //   must be distinct fresh ids.
+  // - |message_.uniform_descriptor| specifies a result id and a list of integer
+  //   literal indices.
+  //   As an example, suppose |message_.uniform_descriptor| is (18, [0, 1, 0])
+  //   It is required that:
+  //     - the result id (18 in our example) is the id of some uniform variable
+  //     - the module contains an integer constant instruction corresponding to
+  //       each of the literal indices; in our example there must thus be
+  //       OpConstant instructions %A and %B say for each of 0 and 1
+  //     - it is legitimate to index into the uniform variable using the
+  //       sequence of indices; in our example this means indexing into %18
+  //       using the sequence %A %B %A
+  //     - the module contains a uniform pointer type corresponding to the type
+  //       of the uniform data element obtained by following these indices
+  // - |message_.id_use_descriptor| identifies the use of some id %C.  It is
+  //   required that:
+  //     - this use does indeed exist in the module
+  //     - %C is an OpConstant
+  //     - According to the fact manager, the uniform data element specified by
+  //       |message_.uniform_descriptor| holds a value with the same type and
+  //       value as %C
+  bool IsApplicable(opt::IRContext* context,
+                    const FactManager& fact_manager) const override;
+
+  // - Introduces two new instructions:
+  //   - An access chain targeting the uniform data element specified by
+  //     |message_.uniform_descriptor|, with result id
+  //     |message_.fresh_id_for_access_chain|
+  //   - A load from this access chain, with id |message_.fresh_id_for_load|
+  // - Replaces the id use specified by |message_.id_use_descriptor| with
+  //   |message_.fresh_id_for_load|
+  void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+  protobufs::Transformation ToMessage() const override;
+
+ private:
+  // Helper method to create an access chain for the uniform element associated
+  // with the transformation.
+  std::unique_ptr<opt::Instruction> MakeAccessChainInstruction(
+      spvtools::opt::IRContext* context, uint32_t constant_type_id) const;
+
+  // Helper to create a load instruction.
+  std::unique_ptr<opt::Instruction> MakeLoadInstruction(
+      spvtools::opt::IRContext* context, uint32_t constant_type_id) const;
+
+  protobufs::TransformationReplaceConstantWithUniform message_;
+};
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools
 

+ 38 - 42
3rdparty/spirv-tools/source/fuzz/transformation_split_block.cpp

@@ -21,32 +21,31 @@
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
 
-using opt::BasicBlock;
-using opt::IRContext;
-using opt::Instruction;
-using opt::Operand;
+TransformationSplitBlock::TransformationSplitBlock(
+    const spvtools::fuzz::protobufs::TransformationSplitBlock& message)
+    : message_(message) {}
 
-namespace {
+TransformationSplitBlock::TransformationSplitBlock(uint32_t result_id,
+                                                   uint32_t offset,
+                                                   uint32_t fresh_id) {
+  message_.set_result_id(result_id);
+  message_.set_offset(offset);
+  message_.set_fresh_id(fresh_id);
+}
 
-// Returns:
-// - (true, block->end()) if the relevant instruction is in this block
-//      but inapplicable
-// - (true, it) if 'it' is an iterator for the relevant instruction
-// - (false, _) otherwise.
-std::pair<bool, BasicBlock::iterator> FindInstToSplitBefore(
-    const protobufs::TransformationSplitBlock& message, BasicBlock* block) {
+std::pair<bool, opt::BasicBlock::iterator>
+TransformationSplitBlock::FindInstToSplitBefore(opt::BasicBlock* block) const {
   // There are three possibilities:
   // (1) the transformation wants to split at some offset from the block's
   //     label.
   // (2) the transformation wants to split at some offset from a
   //     non-label instruction inside the block.
-  // (3) the split associated with this transformation has nothing to do with
+  // (3) the split assocaiated with this transformation has nothing to do with
   //     this block
-  if (message.result_id() == block->id()) {
+  if (message_.result_id() == block->id()) {
     // Case (1).
-    if (message.offset() == 0) {
+    if (message_.offset() == 0) {
       // The offset is not allowed to be 0: this would mean splitting before the
       // block's label.
       // By returning (true, block->end()), we indicate that we did find the
@@ -57,16 +56,17 @@ std::pair<bool, BasicBlock::iterator> FindInstToSplitBefore(
     // Conceptually, the first instruction in the block is [label + 1].
     // We thus start from 1 when applying the offset.
     auto inst_it = block->begin();
-    for (uint32_t i = 1; i < message.offset() && inst_it != block->end(); i++) {
+    for (uint32_t i = 1; i < message_.offset() && inst_it != block->end();
+         i++) {
       ++inst_it;
     }
     // This is either the desired instruction, or the end of the block.
     return {true, inst_it};
   }
   for (auto inst_it = block->begin(); inst_it != block->end(); ++inst_it) {
-    if (message.result_id() == inst_it->result_id()) {
+    if (message_.result_id() == inst_it->result_id()) {
       // Case (2): we have found the base instruction; we now apply the offset.
-      for (uint32_t i = 0; i < message.offset() && inst_it != block->end();
+      for (uint32_t i = 0; i < message_.offset() && inst_it != block->end();
            i++) {
         ++inst_it;
       }
@@ -78,18 +78,16 @@ std::pair<bool, BasicBlock::iterator> FindInstToSplitBefore(
   return {false, block->end()};
 }
 
-}  // namespace
-
-bool IsApplicable(const protobufs::TransformationSplitBlock& message,
-                  IRContext* context, const FactManager& /*unused*/) {
-  if (!fuzzerutil::IsFreshId(context, message.fresh_id())) {
+bool TransformationSplitBlock::IsApplicable(
+    opt::IRContext* context, const FactManager& /*unused*/) const {
+  if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
     // We require the id for the new block to be unused.
     return false;
   }
   // Consider every block in every function.
   for (auto& function : *context->module()) {
     for (auto& block : function) {
-      auto maybe_split_before = FindInstToSplitBefore(message, &block);
+      auto maybe_split_before = FindInstToSplitBefore(&block);
       if (!maybe_split_before.first) {
         continue;
       }
@@ -125,11 +123,11 @@ bool IsApplicable(const protobufs::TransformationSplitBlock& message,
   return false;
 }
 
-void Apply(const protobufs::TransformationSplitBlock& message,
-           IRContext* context, FactManager* /*unused*/) {
+void TransformationSplitBlock::Apply(opt::IRContext* context,
+                                     FactManager* /*unused*/) const {
   for (auto& function : *context->module()) {
     for (auto& block : function) {
-      auto maybe_split_before = FindInstToSplitBefore(message, &block);
+      auto maybe_split_before = FindInstToSplitBefore(&block);
       if (!maybe_split_before.first) {
         continue;
       }
@@ -138,20 +136,21 @@ void Apply(const protobufs::TransformationSplitBlock& message,
              "instruction to split on.");
       // We need to make sure the module's id bound is large enough to add the
       // fresh id.
-      fuzzerutil::UpdateModuleIdBound(context, message.fresh_id());
+      fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
       // Split the block.
-      auto new_bb = block.SplitBasicBlock(context, message.fresh_id(),
+      auto new_bb = block.SplitBasicBlock(context, message_.fresh_id(),
                                           maybe_split_before.second);
       // The split does not automatically add a branch between the two parts of
       // the original block, so we add one.
-      block.AddInstruction(MakeUnique<Instruction>(
+      block.AddInstruction(MakeUnique<opt::Instruction>(
           context, SpvOpBranch, 0, 0,
-          std::initializer_list<Operand>{Operand(
-              spv_operand_type_t::SPV_OPERAND_TYPE_ID, {message.fresh_id()})}));
+          std::initializer_list<opt::Operand>{
+              opt::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID,
+                           {message_.fresh_id()})}));
       // If we split before OpPhi instructions, we need to update their
       // predecessor operand so that the block they used to be inside is now the
       // predecessor.
-      new_bb->ForEachPhiInst([&block](Instruction* phi_inst) {
+      new_bb->ForEachPhiInst([&block](opt::Instruction* phi_inst) {
         // The following assertion is a sanity check.  It is guaranteed to hold
         // if IsApplicable holds.
         assert(phi_inst->NumInOperands() == 2 &&
@@ -160,7 +159,8 @@ void Apply(const protobufs::TransformationSplitBlock& message,
         phi_inst->SetInOperand(1, {block.id()});
       });
       // Invalidate all analyses
-      context->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
+      context->InvalidateAnalysesExceptFor(
+          opt::IRContext::Analysis::kAnalysisNone);
       return;
     }
   }
@@ -169,15 +169,11 @@ void Apply(const protobufs::TransformationSplitBlock& message,
          "transformation.");
 }
 
-protobufs::TransformationSplitBlock MakeTransformationSplitBlock(
-    uint32_t result_id, uint32_t offset, uint32_t fresh_id) {
-  protobufs::TransformationSplitBlock result;
-  result.set_result_id(result_id);
-  result.set_offset(offset);
-  result.set_fresh_id(fresh_id);
+protobufs::Transformation TransformationSplitBlock::ToMessage() const {
+  protobufs::Transformation result;
+  *result.mutable_split_block() = message_;
   return result;
 }
 
-}  // namespace transformation
 }  // namespace fuzz
 }  // namespace spvtools

+ 42 - 25
3rdparty/spirv-tools/source/fuzz/transformation_split_block.h

@@ -17,35 +17,52 @@
 
 #include "source/fuzz/fact_manager.h"
 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
 #include "source/opt/ir_context.h"
 
 namespace spvtools {
 namespace fuzz {
-namespace transformation {
-
-// - |result_id| must be the result id of an instruction 'base' in some
-//   block 'blk'.
-// - 'blk' must contain an instruction 'inst' located |offset| instructions
-//   after 'inst' (if |offset| = 0 then 'inst' = 'base').
-// - Splitting 'blk' at 'inst', so that all instructions from 'inst' onwards
-//   appear in a new block that 'blk' directly jumps to must be valid.
-// - |fresh_id| must not be used by the module.
-bool IsApplicable(const protobufs::TransformationSplitBlock& message,
-                  opt::IRContext* context, const FactManager& fact_manager);
-
-// - A new block with label |fresh_id| is inserted right after 'blk' in
-//   program order.
-// - All instructions of 'blk' from 'inst' onwards are moved into the new
-//   block.
-// - 'blk' is made to jump unconditionally to the new block.
-void Apply(const protobufs::TransformationSplitBlock& message,
-           opt::IRContext* context, FactManager* fact_manager);
-
-// Creates a protobuf message representing a block-splitting transformation.
-protobufs::TransformationSplitBlock MakeTransformationSplitBlock(
-    uint32_t result_id, uint32_t offset, uint32_t fresh_id);
-
-}  // namespace transformation
+
+class TransformationSplitBlock : public Transformation {
+ public:
+  explicit TransformationSplitBlock(
+      const protobufs::TransformationSplitBlock& message);
+
+  TransformationSplitBlock(uint32_t result_id, uint32_t offset,
+                           uint32_t fresh_id);
+
+  // - |message_.result_id| must be the result id of an instruction 'base' in
+  //   some block 'blk'.
+  // - 'blk' must contain an instruction 'inst' located |message_.offset|
+  //   instructions after 'inst' (if |message_.offset| = 0 then 'inst' =
+  //   'base').
+  // - Splitting 'blk' at 'inst', so that all instructions from 'inst' onwards
+  //   appear in a new block that 'blk' directly jumps to must be valid.
+  // - |message_.fresh_id| must not be used by the module.
+  bool IsApplicable(opt::IRContext* context,
+                    const FactManager& fact_manager) const override;
+
+  // - A new block with label |message_.fresh_id| is inserted right after 'blk'
+  //   in program order.
+  // - All instructions of 'blk' from 'inst' onwards are moved into the new
+  //   block.
+  // - 'blk' is made to jump unconditionally to the new block.
+  void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+  protobufs::Transformation ToMessage() const override;
+
+ private:
+  // Returns:
+  // - (true, block->end()) if the relevant instruction is in this block
+  //      but inapplicable
+  // - (true, it) if 'it' is an iterator for the relevant instruction
+  // - (false, _) otherwise.
+  std::pair<bool, opt::BasicBlock::iterator> FindInstToSplitBefore(
+      opt::BasicBlock* block) const;
+
+  protobufs::TransformationSplitBlock message_;
+};
+
 }  // namespace fuzz
 }  // namespace spvtools
 

+ 8 - 2
3rdparty/spirv-tools/source/opt/ir_context.cpp

@@ -678,12 +678,18 @@ uint32_t IRContext::GetBuiltinInputVarId(uint32_t builtin) {
       case SpvBuiltInVertexIndex:
       case SpvBuiltInInstanceIndex:
       case SpvBuiltInPrimitiveId:
-      case SpvBuiltInInvocationId:
-      case SpvBuiltInGlobalInvocationId: {
+      case SpvBuiltInInvocationId: {
         analysis::Integer uint_ty(32, false);
         reg_type = type_mgr->GetRegisteredType(&uint_ty);
         break;
       }
+      case SpvBuiltInGlobalInvocationId: {
+        analysis::Integer uint_ty(32, false);
+        analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
+        analysis::Vector v3uint_ty(reg_uint_ty, 3);
+        reg_type = type_mgr->GetRegisteredType(&v3uint_ty);
+        break;
+      }
       default: {
         assert(false && "unhandled builtin");
         return 0;

+ 30 - 0
3rdparty/spirv-tools/source/spirv_target_env.cpp

@@ -234,6 +234,36 @@ bool spvIsWebGPUEnv(spv_target_env env) {
   return false;
 }
 
+bool spvIsOpenGLEnv(spv_target_env env) {
+  switch (env) {
+    case SPV_ENV_UNIVERSAL_1_0:
+    case SPV_ENV_VULKAN_1_0:
+    case SPV_ENV_UNIVERSAL_1_1:
+    case SPV_ENV_UNIVERSAL_1_2:
+    case SPV_ENV_UNIVERSAL_1_3:
+    case SPV_ENV_VULKAN_1_1:
+    case SPV_ENV_OPENCL_1_2:
+    case SPV_ENV_OPENCL_EMBEDDED_1_2:
+    case SPV_ENV_OPENCL_2_0:
+    case SPV_ENV_OPENCL_EMBEDDED_2_0:
+    case SPV_ENV_OPENCL_EMBEDDED_2_1:
+    case SPV_ENV_OPENCL_EMBEDDED_2_2:
+    case SPV_ENV_OPENCL_2_1:
+    case SPV_ENV_OPENCL_2_2:
+    case SPV_ENV_WEBGPU_0:
+    case SPV_ENV_UNIVERSAL_1_4:
+    case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
+      return false;
+    case SPV_ENV_OPENGL_4_0:
+    case SPV_ENV_OPENGL_4_1:
+    case SPV_ENV_OPENGL_4_2:
+    case SPV_ENV_OPENGL_4_3:
+    case SPV_ENV_OPENGL_4_5:
+      return true;
+  }
+  return false;
+}
+
 bool spvIsVulkanOrWebGPUEnv(spv_target_env env) {
   return spvIsVulkanEnv(env) || spvIsWebGPUEnv(env);
 }

+ 3 - 0
3rdparty/spirv-tools/source/spirv_target_env.h

@@ -28,6 +28,9 @@ bool spvIsOpenCLEnv(spv_target_env env);
 // Returns true if |env| is an WEBGPU environment, false otherwise.
 bool spvIsWebGPUEnv(spv_target_env env);
 
+// Returns true if |env| is an OPENGL environment, false otherwise.
+bool spvIsOpenGLEnv(spv_target_env env);
+
 // Returns true if |env| is a VULKAN or WEBGPU environment, false otherwise.
 bool spvIsVulkanOrWebGPUEnv(spv_target_env env);
 

+ 24 - 0
3rdparty/spirv-tools/source/val/validate_decorations.cpp

@@ -910,6 +910,25 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
         }
       }
 
+      if (spvIsOpenGLEnv(vstate.context()->target_env)) {
+        bool has_block = hasDecoration(var_id, SpvDecorationBlock, vstate);
+        bool has_buffer_block =
+            hasDecoration(var_id, SpvDecorationBufferBlock, vstate);
+        if ((uniform && (has_block || has_buffer_block)) ||
+            (storage_buffer && has_block)) {
+          auto entry_points = vstate.EntryPointReferences(var_id);
+          if (!entry_points.empty() &&
+              !hasDecoration(var_id, SpvDecorationBinding, vstate)) {
+            return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
+                   << (uniform ? "Uniform" : "Storage Buffer") << " id '"
+                   << var_id << "' is missing Binding decoration.\n"
+                   << "From ARB_gl_spirv extension:\n"
+                   << "Uniform and shader storage block variables must "
+                   << "also be decorated with a *Binding*.";
+          }
+        }
+      }
+
       const bool phys_storage_buffer =
           storageClass == SpvStorageClassPhysicalStorageBufferEXT;
       if (uniform || push_constant || storage_buffer || phys_storage_buffer) {
@@ -1440,6 +1459,11 @@ spv_result_t CheckComponentDecoration(ValidationState_t& vstate,
   }
 
   if (spvIsVulkanEnv(vstate.context()->target_env)) {
+    // Strip the array, if present.
+    if (vstate.GetIdOpcode(type_id) == SpvOpTypeArray) {
+      type_id = vstate.FindDef(type_id)->word(2u);
+    }
+
     if (!vstate.IsIntScalarOrVectorType(type_id) &&
         !vstate.IsFloatScalarOrVectorType(type_id)) {
       return vstate.diag(SPV_ERROR_INVALID_ID, &inst)

+ 19 - 33
3rdparty/spirv-tools/test/fuzz/transformation_add_constant_boolean_test.cpp

@@ -45,52 +45,40 @@ TEST(TransformationAddConstantBooleanTest, NeitherPresentInitiallyAddBoth) {
   FactManager fact_manager;
 
   // True and false can both be added as neither is present.
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddConstantBoolean(7, true),
+  ASSERT_TRUE(TransformationAddConstantBoolean(7, true).IsApplicable(
       context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddConstantBoolean(7, false),
+  ASSERT_TRUE(TransformationAddConstantBoolean(7, false).IsApplicable(
       context.get(), fact_manager));
 
   // Id 5 is already taken.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddConstantBoolean(5, true),
+  ASSERT_FALSE(TransformationAddConstantBoolean(5, true).IsApplicable(
       context.get(), fact_manager));
 
-  auto add_true = transformation::MakeTransformationAddConstantBoolean(7, true);
-  auto add_false =
-      transformation::MakeTransformationAddConstantBoolean(8, false);
+  auto add_true = TransformationAddConstantBoolean(7, true);
+  auto add_false = TransformationAddConstantBoolean(8, false);
 
-  ASSERT_TRUE(
-      transformation::IsApplicable(add_true, context.get(), fact_manager));
-  transformation::Apply(add_true, context.get(), &fact_manager);
+  ASSERT_TRUE(add_true.IsApplicable(context.get(), fact_manager));
+  add_true.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   // Having added true, we cannot add it again with the same id.
-  ASSERT_FALSE(
-      transformation::IsApplicable(add_true, context.get(), fact_manager));
+  ASSERT_FALSE(add_true.IsApplicable(context.get(), fact_manager));
   // But we can add it with a different id.
-  auto add_true_again =
-      transformation::MakeTransformationAddConstantBoolean(100, true);
-  ASSERT_TRUE(transformation::IsApplicable(add_true_again, context.get(),
-                                           fact_manager));
-  transformation::Apply(add_true_again, context.get(), &fact_manager);
+  auto add_true_again = TransformationAddConstantBoolean(100, true);
+  ASSERT_TRUE(add_true_again.IsApplicable(context.get(), fact_manager));
+  add_true_again.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(
-      transformation::IsApplicable(add_false, context.get(), fact_manager));
-  transformation::Apply(add_false, context.get(), &fact_manager);
+  ASSERT_TRUE(add_false.IsApplicable(context.get(), fact_manager));
+  add_false.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   // Having added false, we cannot add it again with the same id.
-  ASSERT_FALSE(
-      transformation::IsApplicable(add_false, context.get(), fact_manager));
+  ASSERT_FALSE(add_false.IsApplicable(context.get(), fact_manager));
   // But we can add it with a different id.
-  auto add_false_again =
-      transformation::MakeTransformationAddConstantBoolean(101, false);
-  ASSERT_TRUE(transformation::IsApplicable(add_false_again, context.get(),
-                                           fact_manager));
-  transformation::Apply(add_false_again, context.get(), &fact_manager);
+  auto add_false_again = TransformationAddConstantBoolean(101, false);
+  ASSERT_TRUE(add_false_again.IsApplicable(context.get(), fact_manager));
+  add_false_again.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after_transformation = R"(
@@ -142,11 +130,9 @@ TEST(TransformationAddConstantBooleanTest, NoOpTypeBoolPresent) {
   FactManager fact_manager;
 
   // Neither true nor false can be added as OpTypeBool is not present.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddConstantBoolean(6, true),
+  ASSERT_FALSE(TransformationAddConstantBoolean(6, true).IsApplicable(
       context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddConstantBoolean(6, false),
+  ASSERT_FALSE(TransformationAddConstantBoolean(6, false).IsApplicable(
       context.get(), fact_manager));
 }
 

+ 40 - 62
3rdparty/spirv-tools/test/fuzz/transformation_add_constant_scalar_test.cpp

@@ -67,97 +67,75 @@ TEST(TransformationAddConstantScalarTest, BasicTest) {
   uint32_t uint_for_float[2];
   memcpy(uint_for_float, float_values, sizeof(float_values));
 
-  auto add_signed_int_1 =
-      transformation::MakeTransformationAddConstantScalar(100, 6, {1});
-  auto add_signed_int_10 =
-      transformation::MakeTransformationAddConstantScalar(101, 6, {10});
-  auto add_unsigned_int_2 =
-      transformation::MakeTransformationAddConstantScalar(102, 10, {2});
-  auto add_unsigned_int_20 =
-      transformation::MakeTransformationAddConstantScalar(103, 10, {20});
-  auto add_float_3 = transformation::MakeTransformationAddConstantScalar(
-      104, 14, {uint_for_float[0]});
-  auto add_float_30 = transformation::MakeTransformationAddConstantScalar(
-      105, 14, {uint_for_float[1]});
+  auto add_signed_int_1 = TransformationAddConstantScalar(100, 6, {1});
+  auto add_signed_int_10 = TransformationAddConstantScalar(101, 6, {10});
+  auto add_unsigned_int_2 = TransformationAddConstantScalar(102, 10, {2});
+  auto add_unsigned_int_20 = TransformationAddConstantScalar(103, 10, {20});
+  auto add_float_3 =
+      TransformationAddConstantScalar(104, 14, {uint_for_float[0]});
+  auto add_float_30 =
+      TransformationAddConstantScalar(105, 14, {uint_for_float[1]});
   auto bad_add_float_30_id_already_used =
-      transformation::MakeTransformationAddConstantScalar(104, 14,
-                                                          {uint_for_float[1]});
-  auto bad_id_already_used =
-      transformation::MakeTransformationAddConstantScalar(1, 6, {1});
-  auto bad_no_data =
-      transformation::MakeTransformationAddConstantScalar(100, 6, {});
-  auto bad_too_much_data =
-      transformation::MakeTransformationAddConstantScalar(100, 6, {1, 2});
+      TransformationAddConstantScalar(104, 14, {uint_for_float[1]});
+  auto bad_id_already_used = TransformationAddConstantScalar(1, 6, {1});
+  auto bad_no_data = TransformationAddConstantScalar(100, 6, {});
+  auto bad_too_much_data = TransformationAddConstantScalar(100, 6, {1, 2});
   auto bad_type_id_does_not_exist =
-      transformation::MakeTransformationAddConstantScalar(108, 2020,
-                                                          {uint_for_float[0]});
-  auto bad_type_id_is_not_a_type =
-      transformation::MakeTransformationAddConstantScalar(109, 9, {0});
-  auto bad_type_id_is_void =
-      transformation::MakeTransformationAddConstantScalar(110, 2, {0});
-  auto bad_type_id_is_pointer =
-      transformation::MakeTransformationAddConstantScalar(111, 11, {0});
+      TransformationAddConstantScalar(108, 2020, {uint_for_float[0]});
+  auto bad_type_id_is_not_a_type = TransformationAddConstantScalar(109, 9, {0});
+  auto bad_type_id_is_void = TransformationAddConstantScalar(110, 2, {0});
+  auto bad_type_id_is_pointer = TransformationAddConstantScalar(111, 11, {0});
 
   // Id is already in use.
-  ASSERT_FALSE(transformation::IsApplicable(bad_id_already_used, context.get(),
-                                            fact_manager));
+  ASSERT_FALSE(bad_id_already_used.IsApplicable(context.get(), fact_manager));
 
   // At least one word of data must be provided.
-  ASSERT_FALSE(
-      transformation::IsApplicable(bad_no_data, context.get(), fact_manager));
+  ASSERT_FALSE(bad_no_data.IsApplicable(context.get(), fact_manager));
 
   // Cannot give two data words for a 32-bit type.
-  ASSERT_FALSE(transformation::IsApplicable(bad_too_much_data, context.get(),
-                                            fact_manager));
+  ASSERT_FALSE(bad_too_much_data.IsApplicable(context.get(), fact_manager));
 
   // Type id does not exist
-  ASSERT_FALSE(transformation::IsApplicable(bad_type_id_does_not_exist,
-                                            context.get(), fact_manager));
+  ASSERT_FALSE(
+      bad_type_id_does_not_exist.IsApplicable(context.get(), fact_manager));
 
   // Type id is not a type
-  ASSERT_FALSE(transformation::IsApplicable(bad_type_id_is_not_a_type,
-                                            context.get(), fact_manager));
+  ASSERT_FALSE(
+      bad_type_id_is_not_a_type.IsApplicable(context.get(), fact_manager));
 
   // Type id is void
-  ASSERT_FALSE(transformation::IsApplicable(bad_type_id_is_void, context.get(),
-                                            fact_manager));
+  ASSERT_FALSE(bad_type_id_is_void.IsApplicable(context.get(), fact_manager));
 
   // Type id is pointer
-  ASSERT_FALSE(transformation::IsApplicable(bad_type_id_is_pointer,
-                                            context.get(), fact_manager));
+  ASSERT_FALSE(
+      bad_type_id_is_pointer.IsApplicable(context.get(), fact_manager));
 
-  ASSERT_TRUE(transformation::IsApplicable(add_signed_int_1, context.get(),
-                                           fact_manager));
-  transformation::Apply(add_signed_int_1, context.get(), &fact_manager);
+  ASSERT_TRUE(add_signed_int_1.IsApplicable(context.get(), fact_manager));
+  add_signed_int_1.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(add_signed_int_10, context.get(),
-                                           fact_manager));
-  transformation::Apply(add_signed_int_10, context.get(), &fact_manager);
+  ASSERT_TRUE(add_signed_int_10.IsApplicable(context.get(), fact_manager));
+  add_signed_int_10.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(add_unsigned_int_2, context.get(),
-                                           fact_manager));
-  transformation::Apply(add_unsigned_int_2, context.get(), &fact_manager);
+  ASSERT_TRUE(add_unsigned_int_2.IsApplicable(context.get(), fact_manager));
+  add_unsigned_int_2.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(add_unsigned_int_20, context.get(),
-                                           fact_manager));
-  transformation::Apply(add_unsigned_int_20, context.get(), &fact_manager);
+  ASSERT_TRUE(add_unsigned_int_20.IsApplicable(context.get(), fact_manager));
+  add_unsigned_int_20.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(
-      transformation::IsApplicable(add_float_3, context.get(), fact_manager));
-  transformation::Apply(add_float_3, context.get(), &fact_manager);
+  ASSERT_TRUE(add_float_3.IsApplicable(context.get(), fact_manager));
+  add_float_3.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(
-      transformation::IsApplicable(add_float_30, context.get(), fact_manager));
-  transformation::Apply(add_float_30, context.get(), &fact_manager);
+  ASSERT_TRUE(add_float_30.IsApplicable(context.get(), fact_manager));
+  add_float_30.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_FALSE(transformation::IsApplicable(bad_add_float_30_id_already_used,
-                                            context.get(), fact_manager));
+  ASSERT_FALSE(bad_add_float_30_id_already_used.IsApplicable(context.get(),
+                                                             fact_manager));
 
   std::string after_transformation = R"(
                OpCapability Shader

+ 376 - 552
3rdparty/spirv-tools/test/fuzz/transformation_add_dead_break_test.cpp

@@ -104,105 +104,71 @@ TEST(TransformationAddDeadBreakTest, BreaksOutOfSimpleIf) {
   const uint32_t merge_block = 16;
 
   // These are all possibilities.
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(15, merge_block, true, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(15, merge_block, false,
-                                                     {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(21, merge_block, true, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(21, merge_block, false,
-                                                     {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(22, merge_block, true, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(22, merge_block, false,
-                                                     {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(19, merge_block, true, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(19, merge_block, false,
-                                                     {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(23, merge_block, true, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(23, merge_block, false,
-                                                     {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(24, merge_block, true, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(24, merge_block, false,
-                                                     {}),
-      context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(15, merge_block, true, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(15, merge_block, false, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(21, merge_block, true, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(21, merge_block, false, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(22, merge_block, true, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(22, merge_block, false, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(19, merge_block, true, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(19, merge_block, false, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(23, merge_block, true, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(23, merge_block, false, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(24, merge_block, true, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(24, merge_block, false, {})
+                  .IsApplicable(context.get(), fact_manager));
 
   // Inapplicable: 100 is not a block id.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(100, merge_block, true,
-                                                     {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(15, 100, true, {}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(100, merge_block, true, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(15, 100, true, {})
+                   .IsApplicable(context.get(), fact_manager));
 
   // Inapplicable: 24 is not a merge block.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(15, 24, true, {}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(15, 24, true, {})
+                   .IsApplicable(context.get(), fact_manager));
 
   // These are the transformations we will apply.
-  auto transformation1 =
-      transformation::MakeTransformationAddDeadBreak(15, merge_block, true, {});
-  auto transformation2 = transformation::MakeTransformationAddDeadBreak(
-      21, merge_block, false, {});
-  auto transformation3 =
-      transformation::MakeTransformationAddDeadBreak(22, merge_block, true, {});
-  auto transformation4 = transformation::MakeTransformationAddDeadBreak(
-      19, merge_block, false, {});
-  auto transformation5 =
-      transformation::MakeTransformationAddDeadBreak(23, merge_block, true, {});
-  auto transformation6 = transformation::MakeTransformationAddDeadBreak(
-      24, merge_block, false, {});
-
-  ASSERT_TRUE(transformation::IsApplicable(transformation1, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation1, context.get(), &fact_manager);
+  auto transformation1 = TransformationAddDeadBreak(15, merge_block, true, {});
+  auto transformation2 = TransformationAddDeadBreak(21, merge_block, false, {});
+  auto transformation3 = TransformationAddDeadBreak(22, merge_block, true, {});
+  auto transformation4 = TransformationAddDeadBreak(19, merge_block, false, {});
+  auto transformation5 = TransformationAddDeadBreak(23, merge_block, true, {});
+  auto transformation6 = TransformationAddDeadBreak(24, merge_block, false, {});
+
+  ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
+  transformation1.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation2, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation2, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
+  transformation2.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation3, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation3, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
+  transformation3.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation4, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation4, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager));
+  transformation4.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation5, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation5, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager));
+  transformation5.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation6, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation6, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation6.IsApplicable(context.get(), fact_manager));
+  transformation6.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after_transformation = R"(
@@ -387,148 +353,102 @@ TEST(TransformationAddDeadBreakTest, BreakOutOfNestedIfs) {
   const uint32_t after_block_2 = 38;
 
   // Fine to break from a construct to its merge
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(inner_block_1, merge_inner,
-                                                     true, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(inner_block_2, merge_inner,
-                                                     false, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(outer_block_1, merge_outer,
-                                                     true, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(outer_block_2, merge_outer,
-                                                     false, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(outer_block_3, merge_outer,
-                                                     true, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(outer_block_4, merge_outer,
-                                                     false, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(after_block_1, merge_after,
-                                                     true, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(after_block_2, merge_after,
-                                                     false, {}),
-      context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(inner_block_1, merge_inner, true, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(inner_block_2, merge_inner, false, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(outer_block_1, merge_outer, true, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(outer_block_2, merge_outer, false, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(outer_block_3, merge_outer, true, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(outer_block_4, merge_outer, false, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(after_block_1, merge_after, true, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(after_block_2, merge_after, false, {})
+                  .IsApplicable(context.get(), fact_manager));
 
   // Not OK to break to the wrong merge (whether enclosing or not)
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(inner_block_1, merge_outer,
-                                                     true, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(inner_block_2, merge_after,
-                                                     false, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(outer_block_1, merge_inner,
-                                                     true, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(outer_block_2, merge_after,
-                                                     false, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(after_block_1, merge_inner,
-                                                     true, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(after_block_2, merge_outer,
-                                                     false, {}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(inner_block_1, merge_outer, true, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(inner_block_2, merge_after, false, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(outer_block_1, merge_inner, true, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(outer_block_2, merge_after, false, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(after_block_1, merge_inner, true, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(after_block_2, merge_outer, false, {})
+                   .IsApplicable(context.get(), fact_manager));
 
   // Not OK to break from header (as it does not branch unconditionally)
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(header_inner, merge_inner,
-                                                     true, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(header_outer, merge_outer,
-                                                     false, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(header_after, merge_after,
-                                                     true, {}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(header_inner, merge_inner, true, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(header_outer, merge_outer, false, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(header_after, merge_after, true, {})
+                   .IsApplicable(context.get(), fact_manager));
 
   // Not OK to break to non-merge
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(inner_block_1,
-                                                     inner_block_2, true, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(outer_block_2,
-                                                     after_block_1, false, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(outer_block_1,
-                                                     header_after, true, {}),
-      context.get(), fact_manager));
-
-  auto transformation1 = transformation::MakeTransformationAddDeadBreak(
-      inner_block_1, merge_inner, true, {});
-  auto transformation2 = transformation::MakeTransformationAddDeadBreak(
-      inner_block_2, merge_inner, false, {});
-  auto transformation3 = transformation::MakeTransformationAddDeadBreak(
-      outer_block_1, merge_outer, true, {});
-  auto transformation4 = transformation::MakeTransformationAddDeadBreak(
-      outer_block_2, merge_outer, false, {});
-  auto transformation5 = transformation::MakeTransformationAddDeadBreak(
-      outer_block_3, merge_outer, true, {});
-  auto transformation6 = transformation::MakeTransformationAddDeadBreak(
-      outer_block_4, merge_outer, false, {});
-  auto transformation7 = transformation::MakeTransformationAddDeadBreak(
-      after_block_1, merge_after, true, {});
-  auto transformation8 = transformation::MakeTransformationAddDeadBreak(
-      after_block_2, merge_after, false, {});
-
-  ASSERT_TRUE(transformation::IsApplicable(transformation1, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation1, context.get(), &fact_manager);
+  ASSERT_FALSE(
+      TransformationAddDeadBreak(inner_block_1, inner_block_2, true, {})
+          .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(
+      TransformationAddDeadBreak(outer_block_2, after_block_1, false, {})
+          .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(outer_block_1, header_after, true, {})
+                   .IsApplicable(context.get(), fact_manager));
+
+  auto transformation1 =
+      TransformationAddDeadBreak(inner_block_1, merge_inner, true, {});
+  auto transformation2 =
+      TransformationAddDeadBreak(inner_block_2, merge_inner, false, {});
+  auto transformation3 =
+      TransformationAddDeadBreak(outer_block_1, merge_outer, true, {});
+  auto transformation4 =
+      TransformationAddDeadBreak(outer_block_2, merge_outer, false, {});
+  auto transformation5 =
+      TransformationAddDeadBreak(outer_block_3, merge_outer, true, {});
+  auto transformation6 =
+      TransformationAddDeadBreak(outer_block_4, merge_outer, false, {});
+  auto transformation7 =
+      TransformationAddDeadBreak(after_block_1, merge_after, true, {});
+  auto transformation8 =
+      TransformationAddDeadBreak(after_block_2, merge_after, false, {});
+
+  ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
+  transformation1.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation2, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation2, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
+  transformation2.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation3, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation3, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
+  transformation3.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation4, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation4, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager));
+  transformation4.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation5, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation5, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager));
+  transformation5.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation6, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation6, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation6.IsApplicable(context.get(), fact_manager));
+  transformation6.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation7, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation7, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation7.IsApplicable(context.get(), fact_manager));
+  transformation7.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation8, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation8, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation8.IsApplicable(context.get(), fact_manager));
+  transformation8.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after_transformation = R"(
@@ -793,153 +713,125 @@ TEST(TransformationAddDeadBreakTest, BreakOutOfNestedSwitches) {
   const uint32_t inner_if_2_block_1 = 26;
 
   // Fine to branch straight to direct merge block for a construct
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          then_outer_switch_block_1, merge_then_outer_switch, true, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          then_inner_switch_block_1, merge_then_inner_switch, false, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          then_inner_switch_block_2, merge_then_inner_switch, true, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          then_inner_switch_block_3, merge_then_inner_switch, true, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          else_switch_block_1, merge_else_switch, false, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          else_switch_block_2, merge_else_switch, true, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          else_switch_block_3, merge_else_switch, false, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          inner_if_1_block_1, merge_inner_if_1, true, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          inner_if_1_block_2, merge_inner_if_1, false, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          inner_if_2_block_1, merge_inner_if_2, true, {}),
-      context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(then_outer_switch_block_1,
+                                         merge_then_outer_switch, true, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(then_inner_switch_block_1,
+                                         merge_then_inner_switch, false, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(then_inner_switch_block_2,
+                                         merge_then_inner_switch, true, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(then_inner_switch_block_3,
+                                         merge_then_inner_switch, true, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(else_switch_block_1, merge_else_switch,
+                                         false, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(else_switch_block_2, merge_else_switch,
+                                         true, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(else_switch_block_3, merge_else_switch,
+                                         false, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(
+      TransformationAddDeadBreak(inner_if_1_block_1, merge_inner_if_1, true, {})
+          .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(inner_if_1_block_2, merge_inner_if_1,
+                                         false, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(
+      TransformationAddDeadBreak(inner_if_2_block_1, merge_inner_if_2, true, {})
+          .IsApplicable(context.get(), fact_manager));
 
   // Not OK to break out of a switch from a selection construct inside the
   // switch.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          inner_if_1_block_1, merge_then_outer_switch, true, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          inner_if_1_block_2, merge_then_outer_switch, false, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          inner_if_2_block_1, merge_then_outer_switch, true, {}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(inner_if_1_block_1,
+                                          merge_then_outer_switch, true, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(inner_if_1_block_2,
+                                          merge_then_outer_switch, false, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(inner_if_2_block_1,
+                                          merge_then_outer_switch, true, {})
+                   .IsApplicable(context.get(), fact_manager));
 
   // Some miscellaneous inapplicable cases.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(header_outer_if,
-                                                     merge_outer_if, true, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          header_inner_if_1, inner_if_1_block_2, false, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          header_then_inner_switch, header_then_outer_switch, false, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          header_else_switch, then_inner_switch_block_3, false, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          header_inner_if_2, header_inner_if_2, false, {}),
-      context.get(), fact_manager));
-
-  auto transformation1 = transformation::MakeTransformationAddDeadBreak(
+  ASSERT_FALSE(
+      TransformationAddDeadBreak(header_outer_if, merge_outer_if, true, {})
+          .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(header_inner_if_1, inner_if_1_block_2,
+                                          false, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(header_then_inner_switch,
+                                          header_then_outer_switch, false, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(header_else_switch,
+                                          then_inner_switch_block_3, false, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(header_inner_if_2, header_inner_if_2,
+                                          false, {})
+                   .IsApplicable(context.get(), fact_manager));
+
+  auto transformation1 = TransformationAddDeadBreak(
       then_outer_switch_block_1, merge_then_outer_switch, true, {});
-  auto transformation2 = transformation::MakeTransformationAddDeadBreak(
+  auto transformation2 = TransformationAddDeadBreak(
       then_inner_switch_block_1, merge_then_inner_switch, false, {});
-  auto transformation3 = transformation::MakeTransformationAddDeadBreak(
+  auto transformation3 = TransformationAddDeadBreak(
       then_inner_switch_block_2, merge_then_inner_switch, true, {});
-  auto transformation4 = transformation::MakeTransformationAddDeadBreak(
+  auto transformation4 = TransformationAddDeadBreak(
       then_inner_switch_block_3, merge_then_inner_switch, true, {});
-  auto transformation5 = transformation::MakeTransformationAddDeadBreak(
+  auto transformation5 = TransformationAddDeadBreak(
       else_switch_block_1, merge_else_switch, false, {});
-  auto transformation6 = transformation::MakeTransformationAddDeadBreak(
+  auto transformation6 = TransformationAddDeadBreak(
       else_switch_block_2, merge_else_switch, true, {});
-  auto transformation7 = transformation::MakeTransformationAddDeadBreak(
+  auto transformation7 = TransformationAddDeadBreak(
       else_switch_block_3, merge_else_switch, false, {});
-  auto transformation8 = transformation::MakeTransformationAddDeadBreak(
-      inner_if_1_block_1, merge_inner_if_1, true, {});
-  auto transformation9 = transformation::MakeTransformationAddDeadBreak(
+  auto transformation8 = TransformationAddDeadBreak(inner_if_1_block_1,
+                                                    merge_inner_if_1, true, {});
+  auto transformation9 = TransformationAddDeadBreak(
       inner_if_1_block_2, merge_inner_if_1, false, {});
-  auto transformation10 = transformation::MakeTransformationAddDeadBreak(
+  auto transformation10 = TransformationAddDeadBreak(
       inner_if_2_block_1, merge_inner_if_2, true, {});
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation1, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation1, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
+  transformation1.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation2, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation2, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
+  transformation2.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation3, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation3, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
+  transformation3.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation4, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation4, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager));
+  transformation4.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation5, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation5, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager));
+  transformation5.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation6, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation6, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation6.IsApplicable(context.get(), fact_manager));
+  transformation6.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation7, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation7, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation7.IsApplicable(context.get(), fact_manager));
+  transformation7.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation8, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation8, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation8.IsApplicable(context.get(), fact_manager));
+  transformation8.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation9, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation9, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation9.IsApplicable(context.get(), fact_manager));
+  transformation9.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation10, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation10, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation10.IsApplicable(context.get(), fact_manager));
+  transformation10.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after_transformation = R"(
@@ -1229,149 +1121,119 @@ TEST(TransformationAddDeadBreakTest, BreakOutOfLoopNest) {
   const uint32_t block_in_for_i_loop = 57;
 
   // Fine to break from any loop header to its merge
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(header_do_while,
-                                                     merge_do_while, true, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(header_for_i, merge_for_i,
-                                                     false, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(header_for_j, merge_for_j,
-                                                     true, {}),
-      context.get(), fact_manager));
+  ASSERT_TRUE(
+      TransformationAddDeadBreak(header_do_while, merge_do_while, true, {})
+          .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(header_for_i, merge_for_i, false, {})
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationAddDeadBreak(header_for_j, merge_for_j, true, {})
+                  .IsApplicable(context.get(), fact_manager));
 
   // Fine to break from any of the blocks in constructs in the "for j" loop to
   // that loop's merge
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(block_in_inner_if,
-                                                     merge_for_j, false, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(block_switch_case,
-                                                     merge_for_j, true, {}),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(block_switch_default,
-                                                     merge_for_j, false, {}),
-      context.get(), fact_manager));
+  ASSERT_TRUE(
+      TransformationAddDeadBreak(block_in_inner_if, merge_for_j, false, {})
+          .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(
+      TransformationAddDeadBreak(block_switch_case, merge_for_j, true, {})
+          .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(
+      TransformationAddDeadBreak(block_switch_default, merge_for_j, false, {})
+          .IsApplicable(context.get(), fact_manager));
 
   // Fine to break from the body of the "for i" loop to that loop's merge
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(block_in_for_i_loop,
-                                                     merge_for_i, true, {}),
-      context.get(), fact_manager));
+  ASSERT_TRUE(
+      TransformationAddDeadBreak(block_in_for_i_loop, merge_for_i, true, {})
+          .IsApplicable(context.get(), fact_manager));
 
   // Not OK to break from multiple loops
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(block_in_inner_if,
-                                                     merge_do_while, false, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(block_switch_case,
-                                                     merge_do_while, true, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(block_switch_default,
-                                                     merge_do_while, false, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(header_for_j,
-                                                     merge_do_while, true, {}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(
+      TransformationAddDeadBreak(block_in_inner_if, merge_do_while, false, {})
+          .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(
+      TransformationAddDeadBreak(block_switch_case, merge_do_while, true, {})
+          .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(block_switch_default, merge_do_while,
+                                          false, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(
+      TransformationAddDeadBreak(header_for_j, merge_do_while, true, {})
+          .IsApplicable(context.get(), fact_manager));
 
   // Not OK to break loop from its continue construct
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(continue_do_while,
-                                                     merge_do_while, true, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(continue_for_j,
-                                                     merge_for_j, false, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(continue_for_i,
-                                                     merge_for_i, true, {}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(
+      TransformationAddDeadBreak(continue_do_while, merge_do_while, true, {})
+          .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(
+      TransformationAddDeadBreak(continue_for_j, merge_for_j, false, {})
+          .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(continue_for_i, merge_for_i, true, {})
+                   .IsApplicable(context.get(), fact_manager));
 
   // Not OK to break out of multiple non-loop constructs if not breaking to a
   // loop merge
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          block_in_inner_if, merge_if_x_eq_y, false, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(block_switch_case,
-                                                     merge_if_x_eq_y, true, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          block_switch_default, merge_if_x_eq_y, false, {}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(
+      TransformationAddDeadBreak(block_in_inner_if, merge_if_x_eq_y, false, {})
+          .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(
+      TransformationAddDeadBreak(block_switch_case, merge_if_x_eq_y, true, {})
+          .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(block_switch_default, merge_if_x_eq_y,
+                                          false, {})
+                   .IsApplicable(context.get(), fact_manager));
 
   // Some miscellaneous inapplicable transformations
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          header_if_x_eq_2, header_if_x_eq_y, false, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(merge_if_x_eq_2,
-                                                     merge_switch, false, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(header_switch,
-                                                     header_switch, false, {}),
-      context.get(), fact_manager));
-
-  auto transformation1 = transformation::MakeTransformationAddDeadBreak(
-      header_do_while, merge_do_while, true, {});
-  auto transformation2 = transformation::MakeTransformationAddDeadBreak(
-      header_for_i, merge_for_i, false, {});
-  auto transformation3 = transformation::MakeTransformationAddDeadBreak(
-      header_for_j, merge_for_j, true, {});
-  auto transformation4 = transformation::MakeTransformationAddDeadBreak(
-      block_in_inner_if, merge_for_j, false, {});
-  auto transformation5 = transformation::MakeTransformationAddDeadBreak(
-      block_switch_case, merge_for_j, true, {});
-  auto transformation6 = transformation::MakeTransformationAddDeadBreak(
-      block_switch_default, merge_for_j, false, {});
-  auto transformation7 = transformation::MakeTransformationAddDeadBreak(
-      block_in_for_i_loop, merge_for_i, true, {});
-
-  ASSERT_TRUE(transformation::IsApplicable(transformation1, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation1, context.get(), &fact_manager);
+  ASSERT_FALSE(
+      TransformationAddDeadBreak(header_if_x_eq_2, header_if_x_eq_y, false, {})
+          .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(
+      TransformationAddDeadBreak(merge_if_x_eq_2, merge_switch, false, {})
+          .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(
+      TransformationAddDeadBreak(header_switch, header_switch, false, {})
+          .IsApplicable(context.get(), fact_manager));
+
+  auto transformation1 =
+      TransformationAddDeadBreak(header_do_while, merge_do_while, true, {});
+  auto transformation2 =
+      TransformationAddDeadBreak(header_for_i, merge_for_i, false, {});
+  auto transformation3 =
+      TransformationAddDeadBreak(header_for_j, merge_for_j, true, {});
+  auto transformation4 =
+      TransformationAddDeadBreak(block_in_inner_if, merge_for_j, false, {});
+  auto transformation5 =
+      TransformationAddDeadBreak(block_switch_case, merge_for_j, true, {});
+  auto transformation6 =
+      TransformationAddDeadBreak(block_switch_default, merge_for_j, false, {});
+  auto transformation7 =
+      TransformationAddDeadBreak(block_in_for_i_loop, merge_for_i, true, {});
+
+  ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
+  transformation1.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation2, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation2, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
+  transformation2.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation3, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation3, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
+  transformation3.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation4, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation4, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager));
+  transformation4.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation5, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation5, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager));
+  transformation5.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation6, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation6, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation6.IsApplicable(context.get(), fact_manager));
+  transformation6.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation7, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation7, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation7.IsApplicable(context.get(), fact_manager));
+  transformation7.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after_transformation = R"(
@@ -1561,12 +1423,10 @@ TEST(TransformationAddDeadBreakTest, NoBreakFromContinueConstruct) {
   FactManager fact_manager;
 
   // Not OK to break loop from its continue construct
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(13, 12, true, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(23, 12, true, {}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(13, 12, true, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(23, 12, true, {})
+                   .IsApplicable(context.get(), fact_manager));
 }
 
 TEST(TransformationAddDeadBreakTest, SelectionInContinueConstruct) {
@@ -1659,52 +1519,40 @@ TEST(TransformationAddDeadBreakTest, SelectionInContinueConstruct) {
 
   // Not OK to jump from the selection to the loop merge, as this would break
   // from the loop's continue construct.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(in_selection_1, loop_merge,
-                                                     true, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(in_selection_2, loop_merge,
-                                                     true, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(in_selection_3, loop_merge,
-                                                     true, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(in_selection_4, loop_merge,
-                                                     true, {}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(in_selection_1, loop_merge, true, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(in_selection_2, loop_merge, true, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(in_selection_3, loop_merge, true, {})
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(in_selection_4, loop_merge, true, {})
+                   .IsApplicable(context.get(), fact_manager));
 
   // But fine to jump from the selection to its merge.
 
-  auto transformation1 = transformation::MakeTransformationAddDeadBreak(
-      in_selection_1, selection_merge, true, {});
-  auto transformation2 = transformation::MakeTransformationAddDeadBreak(
-      in_selection_2, selection_merge, true, {});
-  auto transformation3 = transformation::MakeTransformationAddDeadBreak(
-      in_selection_3, selection_merge, true, {});
-  auto transformation4 = transformation::MakeTransformationAddDeadBreak(
-      in_selection_4, selection_merge, true, {});
-
-  ASSERT_TRUE(transformation::IsApplicable(transformation1, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation1, context.get(), &fact_manager);
+  auto transformation1 =
+      TransformationAddDeadBreak(in_selection_1, selection_merge, true, {});
+  auto transformation2 =
+      TransformationAddDeadBreak(in_selection_2, selection_merge, true, {});
+  auto transformation3 =
+      TransformationAddDeadBreak(in_selection_3, selection_merge, true, {});
+  auto transformation4 =
+      TransformationAddDeadBreak(in_selection_4, selection_merge, true, {});
+
+  ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
+  transformation1.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation2, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation2, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
+  transformation2.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation3, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation3, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
+  transformation3.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation4, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation4, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager));
+  transformation4.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after_transformation = R"(
@@ -1879,28 +1727,24 @@ TEST(TransformationAddDeadBreakTest, LoopInContinueConstruct) {
   const uint32_t inner_loop_block = 52;
 
   // Some inapplicable cases
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          inner_loop_block, outer_loop_merge, true, {}),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(
-          outer_loop_block, inner_loop_merge, true, {}),
-      context.get(), fact_manager));
-
-  auto transformation1 = transformation::MakeTransformationAddDeadBreak(
-      inner_loop_block, inner_loop_merge, true, {});
-  auto transformation2 = transformation::MakeTransformationAddDeadBreak(
-      outer_loop_block, outer_loop_merge, true, {});
-
-  ASSERT_TRUE(transformation::IsApplicable(transformation1, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation1, context.get(), &fact_manager);
+  ASSERT_FALSE(
+      TransformationAddDeadBreak(inner_loop_block, outer_loop_merge, true, {})
+          .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(
+      TransformationAddDeadBreak(outer_loop_block, inner_loop_merge, true, {})
+          .IsApplicable(context.get(), fact_manager));
+
+  auto transformation1 =
+      TransformationAddDeadBreak(inner_loop_block, inner_loop_merge, true, {});
+  auto transformation2 =
+      TransformationAddDeadBreak(outer_loop_block, outer_loop_merge, true, {});
+
+  ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
+  transformation1.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation2, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation2, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
+  transformation2.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after_transformation = R"(
@@ -2096,80 +1940,60 @@ TEST(TransformationAddDeadBreakTest, PhiInstructions) {
   // Some inapplicable transformations
   // Not applicable because there is already an edge 19->20, so the OpPhis at 20
   // do not need to be updated
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(19, 20, true, {13, 21}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(19, 20, true, {13, 21})
+                   .IsApplicable(context.get(), fact_manager));
   // Not applicable because two OpPhis (not zero) need to be updated at 20
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(23, 20, true, {}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {})
+                   .IsApplicable(context.get(), fact_manager));
   // Not applicable because two OpPhis (not just one) need to be updated at 20
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(23, 20, true, {13}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {13})
+                   .IsApplicable(context.get(), fact_manager));
   // Not applicable because only two OpPhis (not three) need to be updated at 20
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(23, 20, true,
-                                                     {13, 21, 22}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {13, 21, 22})
+                   .IsApplicable(context.get(), fact_manager));
   // Not applicable because the given ids do not have types that match the
   // OpPhis at 20, in order
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(23, 20, true, {21, 13}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {21, 13})
+                   .IsApplicable(context.get(), fact_manager));
   // Not applicable because id 23 is a label
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(23, 20, true, {21, 23}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {21, 23})
+                   .IsApplicable(context.get(), fact_manager));
   // Not applicable because 101 is not an id
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(23, 20, true, {21, 101}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {21, 101})
+                   .IsApplicable(context.get(), fact_manager));
   // Not applicable because ids 51 and 47 are not available at the end of block
   // 23
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(23, 20, true, {51, 47}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {51, 47})
+                   .IsApplicable(context.get(), fact_manager));
 
   // Not applicable because OpConstantFalse is not present in the module
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddDeadBreak(19, 20, false, {}),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationAddDeadBreak(19, 20, false, {})
+                   .IsApplicable(context.get(), fact_manager));
 
-  auto transformation1 =
-      transformation::MakeTransformationAddDeadBreak(19, 20, true, {});
-  auto transformation2 =
-      transformation::MakeTransformationAddDeadBreak(23, 20, true, {13, 21});
-  auto transformation3 =
-      transformation::MakeTransformationAddDeadBreak(70, 20, true, {});
-  auto transformation4 =
-      transformation::MakeTransformationAddDeadBreak(30, 31, true, {21, 13});
-  auto transformation5 =
-      transformation::MakeTransformationAddDeadBreak(75, 31, true, {47, 51});
+  auto transformation1 = TransformationAddDeadBreak(19, 20, true, {});
+  auto transformation2 = TransformationAddDeadBreak(23, 20, true, {13, 21});
+  auto transformation3 = TransformationAddDeadBreak(70, 20, true, {});
+  auto transformation4 = TransformationAddDeadBreak(30, 31, true, {21, 13});
+  auto transformation5 = TransformationAddDeadBreak(75, 31, true, {47, 51});
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation1, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation1, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
+  transformation1.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation2, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation2, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
+  transformation2.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation3, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation3, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
+  transformation3.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation4, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation4, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager));
+  transformation4.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation5, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation5, context.get(), &fact_manager);
+  ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager));
+  transformation5.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after_transformation = R"(

+ 7 - 10
3rdparty/spirv-tools/test/fuzz/transformation_add_type_boolean_test.cpp

@@ -44,20 +44,17 @@ TEST(TransformationAddTypeBooleanTest, BasicTest) {
   FactManager fact_manager;
 
   // Not applicable because id 1 is already in use.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddTypeBoolean(1), context.get(),
-      fact_manager));
+  ASSERT_FALSE(TransformationAddTypeBoolean(1).IsApplicable(context.get(),
+                                                            fact_manager));
 
-  auto add_type_bool = transformation::MakeTransformationAddTypeBoolean(100);
-  ASSERT_TRUE(
-      transformation::IsApplicable(add_type_bool, context.get(), fact_manager));
-  transformation::Apply(add_type_bool, context.get(), &fact_manager);
+  auto add_type_bool = TransformationAddTypeBoolean(100);
+  ASSERT_TRUE(add_type_bool.IsApplicable(context.get(), fact_manager));
+  add_type_bool.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   // Not applicable as we already have this type now.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddTypeBoolean(101), context.get(),
-      fact_manager));
+  ASSERT_FALSE(TransformationAddTypeBoolean(101).IsApplicable(context.get(),
+                                                              fact_manager));
 
   std::string after_transformation = R"(
                OpCapability Shader

+ 7 - 11
3rdparty/spirv-tools/test/fuzz/transformation_add_type_float_test.cpp

@@ -44,21 +44,17 @@ TEST(TransformationAddTypeFloatTest, BasicTest) {
   FactManager fact_manager;
 
   // Not applicable because id 1 is already in use.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddTypeFloat(1, 32), context.get(),
-      fact_manager));
+  ASSERT_FALSE(TransformationAddTypeFloat(1, 32).IsApplicable(context.get(),
+                                                              fact_manager));
 
-  auto add_type_float_32 =
-      transformation::MakeTransformationAddTypeFloat(100, 32);
-  ASSERT_TRUE(transformation::IsApplicable(add_type_float_32, context.get(),
-                                           fact_manager));
-  transformation::Apply(add_type_float_32, context.get(), &fact_manager);
+  auto add_type_float_32 = TransformationAddTypeFloat(100, 32);
+  ASSERT_TRUE(add_type_float_32.IsApplicable(context.get(), fact_manager));
+  add_type_float_32.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   // Not applicable as we already have this type now.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddTypeFloat(101, 32), context.get(),
-      fact_manager));
+  ASSERT_FALSE(TransformationAddTypeFloat(101, 32).IsApplicable(context.get(),
+                                                                fact_manager));
 
   std::string after_transformation = R"(
                OpCapability Shader

+ 15 - 20
3rdparty/spirv-tools/test/fuzz/transformation_add_type_int_test.cpp

@@ -44,34 +44,29 @@ TEST(TransformationAddTypeIntTest, BasicTest) {
   FactManager fact_manager;
 
   // Not applicable because id 1 is already in use.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationAddTypeInt(1, 32, false), context.get(),
-      fact_manager));
+  ASSERT_FALSE(TransformationAddTypeInt(1, 32, false)
+                   .IsApplicable(context.get(), fact_manager));
 
-  auto add_type_signed_int_32 =
-      transformation::MakeTransformationAddTypeInt(100, 32, true);
-  auto add_type_unsigned_int_32 =
-      transformation::MakeTransformationAddTypeInt(101, 32, false);
-  auto add_type_signed_int_32_again =
-      transformation::MakeTransformationAddTypeInt(102, 32, true);
+  auto add_type_signed_int_32 = TransformationAddTypeInt(100, 32, true);
+  auto add_type_unsigned_int_32 = TransformationAddTypeInt(101, 32, false);
+  auto add_type_signed_int_32_again = TransformationAddTypeInt(102, 32, true);
   auto add_type_unsigned_int_32_again =
-      transformation::MakeTransformationAddTypeInt(103, 32, false);
+      TransformationAddTypeInt(103, 32, false);
 
-  ASSERT_TRUE(transformation::IsApplicable(add_type_signed_int_32,
-                                           context.get(), fact_manager));
-  transformation::Apply(add_type_signed_int_32, context.get(), &fact_manager);
+  ASSERT_TRUE(add_type_signed_int_32.IsApplicable(context.get(), fact_manager));
+  add_type_signed_int_32.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(add_type_unsigned_int_32,
-                                           context.get(), fact_manager));
-  transformation::Apply(add_type_unsigned_int_32, context.get(), &fact_manager);
+  ASSERT_TRUE(
+      add_type_unsigned_int_32.IsApplicable(context.get(), fact_manager));
+  add_type_unsigned_int_32.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   // Not applicable as we already have these types now.
-  ASSERT_FALSE(transformation::IsApplicable(add_type_signed_int_32_again,
-                                            context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(add_type_unsigned_int_32_again,
-                                            context.get(), fact_manager));
+  ASSERT_FALSE(
+      add_type_signed_int_32_again.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(
+      add_type_unsigned_int_32_again.IsApplicable(context.get(), fact_manager));
 
   std::string after_transformation = R"(
                OpCapability Shader

+ 19 - 31
3rdparty/spirv-tools/test/fuzz/transformation_add_type_pointer_test.cpp

@@ -99,46 +99,35 @@ TEST(TransformationAddTypePointerTest, BasicTest) {
   FactManager fact_manager;
 
   auto bad_type_id_does_not_exist =
-      transformation::MakeTransformationAddTypePointer(
-          100, SpvStorageClassFunction, 101);
+      TransformationAddTypePointer(100, SpvStorageClassFunction, 101);
   auto bad_type_id_is_not_type =
-      transformation::MakeTransformationAddTypePointer(
-          100, SpvStorageClassFunction, 23);
+      TransformationAddTypePointer(100, SpvStorageClassFunction, 23);
   auto bad_result_id_is_not_fresh =
-      transformation::MakeTransformationAddTypePointer(
-          17, SpvStorageClassFunction, 21);
+      TransformationAddTypePointer(17, SpvStorageClassFunction, 21);
 
   auto good_new_private_pointer_to_t =
-      transformation::MakeTransformationAddTypePointer(
-          101, SpvStorageClassPrivate, 7);
+      TransformationAddTypePointer(101, SpvStorageClassPrivate, 7);
   auto good_new_uniform_pointer_to_t =
-      transformation::MakeTransformationAddTypePointer(
-          102, SpvStorageClassUniform, 7);
+      TransformationAddTypePointer(102, SpvStorageClassUniform, 7);
   auto good_another_function_pointer_to_s =
-      transformation::MakeTransformationAddTypePointer(
-          103, SpvStorageClassFunction, 8);
+      TransformationAddTypePointer(103, SpvStorageClassFunction, 8);
   auto good_new_uniform_pointer_to_s =
-      transformation::MakeTransformationAddTypePointer(
-          104, SpvStorageClassUniform, 8);
+      TransformationAddTypePointer(104, SpvStorageClassUniform, 8);
   auto good_another_private_pointer_to_float =
-      transformation::MakeTransformationAddTypePointer(
-          105, SpvStorageClassPrivate, 21);
+      TransformationAddTypePointer(105, SpvStorageClassPrivate, 21);
   auto good_new_private_pointer_to_private_pointer_to_float =
-      transformation::MakeTransformationAddTypePointer(
-          106, SpvStorageClassPrivate, 105);
+      TransformationAddTypePointer(106, SpvStorageClassPrivate, 105);
   auto good_new_uniform_pointer_to_vec2 =
-      transformation::MakeTransformationAddTypePointer(
-          107, SpvStorageClassUniform, 24);
+      TransformationAddTypePointer(107, SpvStorageClassUniform, 24);
   auto good_new_private_pointer_to_uniform_pointer_to_vec2 =
-      transformation::MakeTransformationAddTypePointer(
-          108, SpvStorageClassPrivate, 107);
+      TransformationAddTypePointer(108, SpvStorageClassPrivate, 107);
 
-  ASSERT_FALSE(transformation::IsApplicable(bad_type_id_does_not_exist,
-                                            context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(bad_type_id_is_not_type,
-                                            context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(bad_result_id_is_not_fresh,
-                                            context.get(), fact_manager));
+  ASSERT_FALSE(
+      bad_type_id_does_not_exist.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(
+      bad_type_id_is_not_type.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(
+      bad_result_id_is_not_fresh.IsApplicable(context.get(), fact_manager));
 
   for (auto& transformation :
        {good_new_private_pointer_to_t, good_new_uniform_pointer_to_t,
@@ -147,9 +136,8 @@ TEST(TransformationAddTypePointerTest, BasicTest) {
         good_new_private_pointer_to_private_pointer_to_float,
         good_new_uniform_pointer_to_vec2,
         good_new_private_pointer_to_uniform_pointer_to_vec2}) {
-    ASSERT_TRUE(transformation::IsApplicable(transformation, context.get(),
-                                             fact_manager));
-    transformation::Apply(transformation, context.get(), &fact_manager);
+    ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
+    transformation.Apply(context.get(), &fact_manager);
     ASSERT_TRUE(IsValid(env, context.get()));
   }
 

+ 196 - 356
3rdparty/spirv-tools/test/fuzz/transformation_move_block_down_test.cpp

@@ -54,9 +54,8 @@ TEST(TransformationMoveBlockDownTest, NoMovePossible1) {
 
   FactManager fact_manager;
 
-  auto transformation = transformation::MakeTransformationMoveBlockDown(11);
-  ASSERT_FALSE(transformation::IsApplicable(transformation, context.get(),
-                                            fact_manager));
+  auto transformation = TransformationMoveBlockDown(11);
+  ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager));
 }
 
 TEST(TransformationMoveBlockDownTest, NoMovePossible2) {
@@ -92,9 +91,8 @@ TEST(TransformationMoveBlockDownTest, NoMovePossible2) {
 
   FactManager fact_manager;
 
-  auto transformation = transformation::MakeTransformationMoveBlockDown(5);
-  ASSERT_FALSE(transformation::IsApplicable(transformation, context.get(),
-                                            fact_manager));
+  auto transformation = TransformationMoveBlockDown(5);
+  ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager));
 }
 
 TEST(TransformationMoveBlockDownTest, NoMovePossible3) {
@@ -132,9 +130,8 @@ TEST(TransformationMoveBlockDownTest, NoMovePossible3) {
 
   FactManager fact_manager;
 
-  auto transformation = transformation::MakeTransformationMoveBlockDown(100);
-  ASSERT_FALSE(transformation::IsApplicable(transformation, context.get(),
-                                            fact_manager));
+  auto transformation = TransformationMoveBlockDown(100);
+  ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager));
 }
 
 TEST(TransformationMoveBlockDownTest, NoMovePossible4) {
@@ -176,81 +173,8 @@ TEST(TransformationMoveBlockDownTest, NoMovePossible4) {
 
   FactManager fact_manager;
 
-  auto transformation = transformation::MakeTransformationMoveBlockDown(12);
-  ASSERT_FALSE(transformation::IsApplicable(transformation, context.get(),
-                                            fact_manager));
-}
-
-TEST(TransformationMoveBlockDownTest, MovePossible) {
-  // Block 11 can be moved down as it does not dominate block 12 (both are
-  // unreachable).
-  std::string before_transformation = R"(
-               OpCapability Shader
-          %1 = OpExtInstImport "GLSL.std.450"
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %4 "main"
-               OpExecutionMode %4 OriginUpperLeft
-               OpSource ESSL 310
-               OpDecorate %8 RelaxedPrecision
-          %2 = OpTypeVoid
-          %3 = OpTypeFunction %2
-          %6 = OpTypeInt 32 1
-          %7 = OpTypePointer Function %6
-          %9 = OpConstant %6 1
-         %10 = OpConstant %6 2
-          %4 = OpFunction %2 None %3
-          %5 = OpLabel
-          %8 = OpVariable %7 Function
-               OpStore %8 %9
-               OpStore %8 %10
-               OpReturn
-         %11 = OpLabel
-               OpReturn
-         %12 = OpLabel
-               OpReturn
-               OpFunctionEnd
-  )";
-
-  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
-               OpDecorate %8 RelaxedPrecision
-          %2 = OpTypeVoid
-          %3 = OpTypeFunction %2
-          %6 = OpTypeInt 32 1
-          %7 = OpTypePointer Function %6
-          %9 = OpConstant %6 1
-         %10 = OpConstant %6 2
-          %4 = OpFunction %2 None %3
-          %5 = OpLabel
-          %8 = OpVariable %7 Function
-               OpStore %8 %9
-               OpStore %8 %10
-               OpReturn
-         %12 = OpLabel
-               OpReturn
-         %11 = OpLabel
-               OpReturn
-               OpFunctionEnd
-  )";
-
-  const auto env = SPV_ENV_UNIVERSAL_1_3;
-  const auto consumer = nullptr;
-  const auto context =
-      BuildModule(env, consumer, before_transformation, kFuzzAssembleOption);
-
-  FactManager fact_manager;
-
-  auto transformation = transformation::MakeTransformationMoveBlockDown(11);
-  ASSERT_TRUE(transformation::IsApplicable(transformation, context.get(),
-                                           fact_manager));
-  transformation::Apply(transformation, context.get(), &fact_manager);
-  ASSERT_TRUE(IsValid(env, context.get()));
-  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+  auto transformation = TransformationMoveBlockDown(12);
+  ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager));
 }
 
 TEST(TransformationMoveBlockDownTest, ManyMovesPossible) {
@@ -357,17 +281,17 @@ TEST(TransformationMoveBlockDownTest, ManyMovesPossible) {
   // The block ids are: 5 14 20 23 21 25 29 32 30 15
   // We make a transformation to move each of them down, plus a transformation
   // to move a non-block, 27, down.
-  auto move_down_5 = transformation::MakeTransformationMoveBlockDown(5);
-  auto move_down_14 = transformation::MakeTransformationMoveBlockDown(14);
-  auto move_down_20 = transformation::MakeTransformationMoveBlockDown(20);
-  auto move_down_23 = transformation::MakeTransformationMoveBlockDown(23);
-  auto move_down_21 = transformation::MakeTransformationMoveBlockDown(21);
-  auto move_down_25 = transformation::MakeTransformationMoveBlockDown(25);
-  auto move_down_29 = transformation::MakeTransformationMoveBlockDown(29);
-  auto move_down_32 = transformation::MakeTransformationMoveBlockDown(32);
-  auto move_down_30 = transformation::MakeTransformationMoveBlockDown(30);
-  auto move_down_15 = transformation::MakeTransformationMoveBlockDown(15);
-  auto move_down_27 = transformation::MakeTransformationMoveBlockDown(27);
+  auto move_down_5 = TransformationMoveBlockDown(5);
+  auto move_down_14 = TransformationMoveBlockDown(14);
+  auto move_down_20 = TransformationMoveBlockDown(20);
+  auto move_down_23 = TransformationMoveBlockDown(23);
+  auto move_down_21 = TransformationMoveBlockDown(21);
+  auto move_down_25 = TransformationMoveBlockDown(25);
+  auto move_down_29 = TransformationMoveBlockDown(29);
+  auto move_down_32 = TransformationMoveBlockDown(32);
+  auto move_down_30 = TransformationMoveBlockDown(30);
+  auto move_down_15 = TransformationMoveBlockDown(15);
+  auto move_down_27 = TransformationMoveBlockDown(27);
 
   // Dominance is as follows:
   //  5 dominates everything else
@@ -382,180 +306,110 @@ TEST(TransformationMoveBlockDownTest, ManyMovesPossible) {
   // 15 dominates nothing
 
   // Current ordering: 5 14 20 23 21 25 29 32 30 15
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_5, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_14, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_20, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_23, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_21, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_25, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_29, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_32, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_30, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_15, context.get(), fact_manager));
+  ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
 
   // Let's bubble 20 all the way down.
 
-  transformation::Apply(move_down_20, context.get(), &fact_manager);
+  move_down_20.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   // Current ordering: 5 14 23 20 21 25 29 32 30 15
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_5, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_14, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_23, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_20, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_21, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_25, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_29, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_32, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_30, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_15, context.get(), fact_manager));
-
-  transformation::Apply(move_down_20, context.get(), &fact_manager);
+  ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
+
+  move_down_20.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   // Current ordering: 5 14 23 21 20 25 29 32 30 15
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_5, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_14, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_23, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_21, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_20, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_25, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_29, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_32, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_30, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_15, context.get(), fact_manager));
-
-  transformation::Apply(move_down_20, context.get(), &fact_manager);
+  ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
+
+  move_down_20.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   // Current ordering: 5 14 23 21 25 20 29 32 30 15
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_5, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_14, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_23, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_21, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_25, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_20, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_29, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_32, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_30, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_15, context.get(), fact_manager));
-
-  transformation::Apply(move_down_20, context.get(), &fact_manager);
+  ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_25.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
+
+  move_down_20.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   // Current ordering: 5 14 23 21 25 29 20 32 30 15
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_5, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_14, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_23, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_21, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_25, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_29, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_20, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_32, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_30, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_15, context.get(), fact_manager));
-
-  transformation::Apply(move_down_20, context.get(), &fact_manager);
+  ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
+
+  move_down_20.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   // Current ordering: 5 14 23 21 25 29 32 20 30 15
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_5, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_14, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_23, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_21, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_25, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_29, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_32, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_20, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_30, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_15, context.get(), fact_manager));
-
-  transformation::Apply(move_down_20, context.get(), &fact_manager);
+  ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
+
+  move_down_20.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   // Current ordering: 5 14 23 21 25 29 32 30 20 15
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_5, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_14, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_23, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_21, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_25, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_29, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_32, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_30, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_20, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_15, context.get(), fact_manager));
-
-  transformation::Apply(move_down_20, context.get(), &fact_manager);
+  ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
+
+  move_down_20.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after_bubbling_20_down = R"(
@@ -631,103 +485,63 @@ TEST(TransformationMoveBlockDownTest, ManyMovesPossible) {
   ASSERT_TRUE(IsEqual(env, after_bubbling_20_down, context.get()));
 
   // Current ordering: 5 14 23 21 25 29 32 30 15 20
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_5, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_14, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_23, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_21, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_25, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_29, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_32, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_30, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_15, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_20, context.get(), fact_manager));
-
-  transformation::Apply(move_down_23, context.get(), &fact_manager);
+  ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager));
+
+  move_down_23.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   // Current ordering: 5 14 21 23 25 29 32 30 15 20
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_5, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_14, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_21, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_23, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_25, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_29, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_32, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_30, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_15, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_20, context.get(), fact_manager));
-
-  transformation::Apply(move_down_23, context.get(), &fact_manager);
+  ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager));
+
+  move_down_23.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   // Current ordering: 5 14 21 25 23 29 32 30 15 20
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_5, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_14, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_21, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_25, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_23, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_29, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_32, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_30, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_15, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_20, context.get(), fact_manager));
-
-  transformation::Apply(move_down_21, context.get(), &fact_manager);
+  ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_25.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager));
+
+  move_down_21.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   // Current ordering: 5 14 25 21 23 29 32 30 15 20
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_5, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_14, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_21, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_25, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_23, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_29, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_32, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_30, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_15, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_20, context.get(), fact_manager));
-
-  transformation::Apply(move_down_14, context.get(), &fact_manager);
+  ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_14.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_25.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager));
+
+  move_down_14.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after_more_shuffling = R"(
@@ -803,26 +617,52 @@ TEST(TransformationMoveBlockDownTest, ManyMovesPossible) {
   ASSERT_TRUE(IsEqual(env, after_more_shuffling, context.get()));
 
   // Final ordering: 5 25 14 21 23 29 32 30 15 20
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_5, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_25, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_14, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_21, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_23, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_29, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_32, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_30, context.get(), fact_manager));
-  ASSERT_TRUE(
-      transformation::IsApplicable(move_down_15, context.get(), fact_manager));
-  ASSERT_FALSE(
-      transformation::IsApplicable(move_down_20, context.get(), fact_manager));
+  ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_25.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager));
+}
+
+TEST(TransformationMoveBlockDownTest, DoNotMoveUnreachable) {
+  // Block 6 is unreachable, so cannot be moved down.
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+         %10 = OpTypeInt 32 1
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+               OpReturn
+          %6 = OpLabel
+          %7 = OpUndef %10
+               OpBranch %8
+          %8 = OpLabel
+          %9 = OpCopyObject %10 %7
+               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;
+
+  auto transformation = TransformationMoveBlockDown(6);
+  ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager));
 }
 
 }  // namespace

+ 59 - 87
3rdparty/spirv-tools/test/fuzz/transformation_replace_boolean_constant_with_constant_binary_test.cpp

@@ -192,16 +192,12 @@ TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,
   std::vector<SpvOp> uint_lt_opcodes = {SpvOpULessThan, SpvOpULessThanEqual};
 
 #define CHECK_OPERATOR(USE_DESCRIPTOR, LHS_ID, RHS_ID, OPCODE, FRESH_ID) \
-  ASSERT_TRUE(transformation::IsApplicable(                              \
-      transformation::                                                   \
-          MakeTransformationReplaceBooleanConstantWithConstantBinary(    \
-              USE_DESCRIPTOR, LHS_ID, RHS_ID, OPCODE, FRESH_ID),         \
-      context.get(), fact_manager));                                     \
-  ASSERT_FALSE(transformation::IsApplicable(                             \
-      transformation::                                                   \
-          MakeTransformationReplaceBooleanConstantWithConstantBinary(    \
-              USE_DESCRIPTOR, RHS_ID, LHS_ID, OPCODE, FRESH_ID),         \
-      context.get(), fact_manager));
+  ASSERT_TRUE(TransformationReplaceBooleanConstantWithConstantBinary(    \
+                  USE_DESCRIPTOR, LHS_ID, RHS_ID, OPCODE, FRESH_ID)      \
+                  .IsApplicable(context.get(), fact_manager));           \
+  ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(   \
+                   USE_DESCRIPTOR, RHS_ID, LHS_ID, OPCODE, FRESH_ID)     \
+                   .IsApplicable(context.get(), fact_manager));
 
 #define CHECK_TRANSFORMATION_APPLICABILITY(GT_OPCODES, LT_OPCODES, SMALL_ID, \
                                            LARGE_ID)                         \
@@ -251,72 +247,58 @@ TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,
   }
 
   // Target id is not fresh
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::
-          MakeTransformationReplaceBooleanConstantWithConstantBinary(
-              uses_of_true[0], 15, 17, SpvOpFOrdLessThan, 15),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
+                   uses_of_true[0], 15, 17, SpvOpFOrdLessThan, 15)
+                   .IsApplicable(context.get(), fact_manager));
 
   // LHS id does not exist
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::
-          MakeTransformationReplaceBooleanConstantWithConstantBinary(
-              uses_of_true[0], 300, 17, SpvOpFOrdLessThan, 200),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
+                   uses_of_true[0], 300, 17, SpvOpFOrdLessThan, 200)
+                   .IsApplicable(context.get(), fact_manager));
 
   // RHS id does not exist
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::
-          MakeTransformationReplaceBooleanConstantWithConstantBinary(
-              uses_of_true[0], 15, 300, SpvOpFOrdLessThan, 200),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
+                   uses_of_true[0], 15, 300, SpvOpFOrdLessThan, 200)
+                   .IsApplicable(context.get(), fact_manager));
 
   // LHS and RHS ids do not match type
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::
-          MakeTransformationReplaceBooleanConstantWithConstantBinary(
-              uses_of_true[0], 11, 17, SpvOpFOrdLessThan, 200),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
+                   uses_of_true[0], 11, 17, SpvOpFOrdLessThan, 200)
+                   .IsApplicable(context.get(), fact_manager));
 
   // Opcode not appropriate
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::
-          MakeTransformationReplaceBooleanConstantWithConstantBinary(
-              uses_of_true[0], 15, 17, SpvOpFDiv, 200),
-      context.get(), fact_manager));
-
-  auto replace_true_with_double_comparison = transformation::
-      MakeTransformationReplaceBooleanConstantWithConstantBinary(
+  ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
+                   uses_of_true[0], 15, 17, SpvOpFDiv, 200)
+                   .IsApplicable(context.get(), fact_manager));
+
+  auto replace_true_with_double_comparison =
+      TransformationReplaceBooleanConstantWithConstantBinary(
           uses_of_true[0], 11, 9, SpvOpFUnordGreaterThan, 100);
-  auto replace_true_with_uint32_comparison = transformation::
-      MakeTransformationReplaceBooleanConstantWithConstantBinary(
+  auto replace_true_with_uint32_comparison =
+      TransformationReplaceBooleanConstantWithConstantBinary(
           uses_of_true[1], 27, 29, SpvOpULessThanEqual, 101);
-  auto replace_false_with_float_comparison = transformation::
-      MakeTransformationReplaceBooleanConstantWithConstantBinary(
+  auto replace_false_with_float_comparison =
+      TransformationReplaceBooleanConstantWithConstantBinary(
           uses_of_false[0], 17, 15, SpvOpFOrdLessThan, 102);
-  auto replace_false_with_sint64_comparison = transformation::
-      MakeTransformationReplaceBooleanConstantWithConstantBinary(
+  auto replace_false_with_sint64_comparison =
+      TransformationReplaceBooleanConstantWithConstantBinary(
           uses_of_false[1], 33, 31, SpvOpSLessThan, 103);
 
-  ASSERT_TRUE(transformation::IsApplicable(replace_true_with_double_comparison,
-                                           context.get(), fact_manager));
-  transformation::Apply(replace_true_with_double_comparison, context.get(),
-                        &fact_manager);
+  ASSERT_TRUE(replace_true_with_double_comparison.IsApplicable(context.get(),
+                                                               fact_manager));
+  replace_true_with_double_comparison.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
-  ASSERT_TRUE(transformation::IsApplicable(replace_true_with_uint32_comparison,
-                                           context.get(), fact_manager));
-  transformation::Apply(replace_true_with_uint32_comparison, context.get(),
-                        &fact_manager);
+  ASSERT_TRUE(replace_true_with_uint32_comparison.IsApplicable(context.get(),
+                                                               fact_manager));
+  replace_true_with_uint32_comparison.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
-  ASSERT_TRUE(transformation::IsApplicable(replace_false_with_float_comparison,
-                                           context.get(), fact_manager));
-  transformation::Apply(replace_false_with_float_comparison, context.get(),
-                        &fact_manager);
+  ASSERT_TRUE(replace_false_with_float_comparison.IsApplicable(context.get(),
+                                                               fact_manager));
+  replace_false_with_float_comparison.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
-  ASSERT_TRUE(transformation::IsApplicable(replace_false_with_sint64_comparison,
-                                           context.get(), fact_manager));
-  transformation::Apply(replace_false_with_sint64_comparison, context.get(),
-                        &fact_manager);
+  ASSERT_TRUE(replace_false_with_sint64_comparison.IsApplicable(context.get(),
+                                                                fact_manager));
+  replace_false_with_sint64_comparison.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after = R"(
@@ -432,11 +414,9 @@ TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,
     fuzzerutil::UpdateModuleIdBound(context.get(), 200);
     ASSERT_TRUE(IsValid(env, context.get()));
     // The transformation is not applicable because %200 is NaN.
-    ASSERT_FALSE(transformation::IsApplicable(
-        transformation::
-            MakeTransformationReplaceBooleanConstantWithConstantBinary(
-                uses_of_true[0], 11, 200, SpvOpFOrdLessThan, 300),
-        context.get(), fact_manager));
+    ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
+                     uses_of_true[0], 11, 200, SpvOpFOrdLessThan, 300)
+                     .IsApplicable(context.get(), fact_manager));
   }
   if (std::numeric_limits<double>::has_infinity) {
     double positive_infinity_double = std::numeric_limits<double>::infinity();
@@ -451,11 +431,9 @@ TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,
     ASSERT_TRUE(IsValid(env, context.get()));
     // Even though the double constant %11 is less than the infinity %201, the
     // transformation is restricted to only apply to finite values.
-    ASSERT_FALSE(transformation::IsApplicable(
-        transformation::
-            MakeTransformationReplaceBooleanConstantWithConstantBinary(
-                uses_of_true[0], 11, 201, SpvOpFOrdLessThan, 300),
-        context.get(), fact_manager));
+    ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
+                     uses_of_true[0], 11, 201, SpvOpFOrdLessThan, 300)
+                     .IsApplicable(context.get(), fact_manager));
   }
   if (std::numeric_limits<float>::has_infinity) {
     float positive_infinity_float = std::numeric_limits<float>::infinity();
@@ -478,11 +456,9 @@ TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,
     // Even though the negative infinity at %203 is less than the positive
     // infinity %202, the transformation is restricted to only apply to finite
     // values.
-    ASSERT_FALSE(transformation::IsApplicable(
-        transformation::
-            MakeTransformationReplaceBooleanConstantWithConstantBinary(
-                uses_of_true[0], 203, 202, SpvOpFOrdLessThan, 300),
-        context.get(), fact_manager));
+    ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
+                     uses_of_true[0], 203, 202, SpvOpFOrdLessThan, 300)
+                     .IsApplicable(context.get(), fact_manager));
   }
 }
 
@@ -558,21 +534,17 @@ TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,
   auto use_of_false_in_while =
       transformation::MakeIdUseDescriptor(21, SpvOpBranchConditional, 0, 16, 0);
 
-  auto replacement_1 = transformation::
-      MakeTransformationReplaceBooleanConstantWithConstantBinary(
-          use_of_true_in_if, 9, 11, SpvOpSLessThan, 100);
-  auto replacement_2 = transformation::
-      MakeTransformationReplaceBooleanConstantWithConstantBinary(
-          use_of_false_in_while, 9, 11, SpvOpSGreaterThanEqual, 101);
+  auto replacement_1 = TransformationReplaceBooleanConstantWithConstantBinary(
+      use_of_true_in_if, 9, 11, SpvOpSLessThan, 100);
+  auto replacement_2 = TransformationReplaceBooleanConstantWithConstantBinary(
+      use_of_false_in_while, 9, 11, SpvOpSGreaterThanEqual, 101);
 
-  ASSERT_TRUE(
-      transformation::IsApplicable(replacement_1, context.get(), fact_manager));
-  transformation::Apply(replacement_1, context.get(), &fact_manager);
+  ASSERT_TRUE(replacement_1.IsApplicable(context.get(), fact_manager));
+  replacement_1.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  ASSERT_TRUE(
-      transformation::IsApplicable(replacement_2, context.get(), fact_manager));
-  transformation::Apply(replacement_2, context.get(), &fact_manager);
+  ASSERT_TRUE(replacement_2.IsApplicable(context.get(), fact_manager));
+  replacement_2.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after = R"(

+ 186 - 226
3rdparty/spirv-tools/test/fuzz/transformation_replace_constant_with_uniform_test.cpp

@@ -124,35 +124,32 @@ TEST(TransformationReplaceConstantWithUniformTest, BasicReplacements) {
 
   // These transformations work: they match the facts.
   auto transformation_use_of_9_in_store =
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_9_in_store, blockname_a, 100, 101);
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_9_in_store,
-                                           context.get(), fact_manager));
+      TransformationReplaceConstantWithUniform(use_of_9_in_store, blockname_a,
+                                               100, 101);
+  ASSERT_TRUE(transformation_use_of_9_in_store.IsApplicable(context.get(),
+                                                            fact_manager));
   auto transformation_use_of_11_in_add =
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_11_in_add, blockname_b, 102, 103);
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_11_in_add,
-                                           context.get(), fact_manager));
+      TransformationReplaceConstantWithUniform(use_of_11_in_add, blockname_b,
+                                               102, 103);
+  ASSERT_TRUE(transformation_use_of_11_in_add.IsApplicable(context.get(),
+                                                           fact_manager));
   auto transformation_use_of_14_in_add =
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_14_in_add, blockname_c, 104, 105);
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_14_in_add,
-                                           context.get(), fact_manager));
+      TransformationReplaceConstantWithUniform(use_of_14_in_add, blockname_c,
+                                               104, 105);
+  ASSERT_TRUE(transformation_use_of_14_in_add.IsApplicable(context.get(),
+                                                           fact_manager));
 
   // The transformations are not applicable if we change which uniforms are
   // applied to which constants.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_9_in_store, blockname_b, 101, 102),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_11_in_add, blockname_c, 101, 102),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_14_in_add, blockname_a, 101, 102),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
+                                                        blockname_b, 101, 102)
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_11_in_add,
+                                                        blockname_c, 101, 102)
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_14_in_add,
+                                                        blockname_a, 101, 102)
+                   .IsApplicable(context.get(), fact_manager));
 
   // The following transformations do not apply because the uniform descriptors
   // are not sensible.
@@ -160,37 +157,31 @@ TEST(TransformationReplaceConstantWithUniformTest, BasicReplacements) {
       MakeUniformBufferElementDescriptor(1, 2, {0});
   protobufs::UniformBufferElementDescriptor nonsense_uniform_descriptor2 =
       MakeUniformBufferElementDescriptor(0, 0, {5});
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_9_in_store, nonsense_uniform_descriptor1, 101, 102),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_9_in_store, nonsense_uniform_descriptor2, 101, 102),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationReplaceConstantWithUniform(
+                   use_of_9_in_store, nonsense_uniform_descriptor1, 101, 102)
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationReplaceConstantWithUniform(
+                   use_of_9_in_store, nonsense_uniform_descriptor2, 101, 102)
+                   .IsApplicable(context.get(), fact_manager));
 
   // The following transformation does not apply because the id descriptor is
   // not sensible.
   protobufs::IdUseDescriptor nonsense_id_use_descriptor =
       transformation::MakeIdUseDescriptor(9, SpvOpIAdd, 0, 15, 0);
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          nonsense_id_use_descriptor, blockname_a, 101, 102),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationReplaceConstantWithUniform(
+                   nonsense_id_use_descriptor, blockname_a, 101, 102)
+                   .IsApplicable(context.get(), fact_manager));
 
   // The following transformations do not apply because the ids are not fresh.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_11_in_add, blockname_b, 15, 103),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_11_in_add, blockname_b, 102, 15),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_11_in_add,
+                                                        blockname_b, 15, 103)
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_11_in_add,
+                                                        blockname_b, 102, 15)
+                   .IsApplicable(context.get(), fact_manager));
 
   // Apply the use of 9 in a store.
-  transformation::Apply(transformation_use_of_9_in_store, context.get(),
-                        &fact_manager);
+  transformation_use_of_9_in_store.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
   std::string after_replacing_use_of_9_in_store = R"(
                OpCapability Shader
@@ -241,11 +232,10 @@ TEST(TransformationReplaceConstantWithUniformTest, BasicReplacements) {
   )";
   ASSERT_TRUE(IsEqual(env, after_replacing_use_of_9_in_store, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_11_in_add,
-                                           context.get(), fact_manager));
+  ASSERT_TRUE(transformation_use_of_11_in_add.IsApplicable(context.get(),
+                                                           fact_manager));
   // Apply the use of 11 in an add.
-  transformation::Apply(transformation_use_of_11_in_add, context.get(),
-                        &fact_manager);
+  transformation_use_of_11_in_add.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
   std::string after_replacing_use_of_11_in_add = R"(
                OpCapability Shader
@@ -298,11 +288,10 @@ TEST(TransformationReplaceConstantWithUniformTest, BasicReplacements) {
   )";
   ASSERT_TRUE(IsEqual(env, after_replacing_use_of_11_in_add, context.get()));
 
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_14_in_add,
-                                           context.get(), fact_manager));
+  ASSERT_TRUE(transformation_use_of_14_in_add.IsApplicable(context.get(),
+                                                           fact_manager));
   // Apply the use of 15 in an add.
-  transformation::Apply(transformation_use_of_14_in_add, context.get(),
-                        &fact_manager);
+  transformation_use_of_14_in_add.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
   std::string after_replacing_use_of_14_in_add = R"(
                OpCapability Shader
@@ -498,82 +487,78 @@ TEST(TransformationReplaceConstantWithUniformTest, NestedStruct) {
 
   // These transformations work: they match the facts.
   auto transformation_use_of_13_in_store =
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_13_in_store, blockname_1, 100, 101);
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_13_in_store,
-                                           context.get(), fact_manager));
+      TransformationReplaceConstantWithUniform(use_of_13_in_store, blockname_1,
+                                               100, 101);
+  ASSERT_TRUE(transformation_use_of_13_in_store.IsApplicable(context.get(),
+                                                             fact_manager));
   auto transformation_use_of_15_in_add =
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_15_in_add, blockname_2, 102, 103);
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_15_in_add,
-                                           context.get(), fact_manager));
+      TransformationReplaceConstantWithUniform(use_of_15_in_add, blockname_2,
+                                               102, 103);
+  ASSERT_TRUE(transformation_use_of_15_in_add.IsApplicable(context.get(),
+                                                           fact_manager));
   auto transformation_use_of_17_in_add =
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_17_in_add, blockname_3, 104, 105);
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_17_in_add,
-                                           context.get(), fact_manager));
+      TransformationReplaceConstantWithUniform(use_of_17_in_add, blockname_3,
+                                               104, 105);
+  ASSERT_TRUE(transformation_use_of_17_in_add.IsApplicable(context.get(),
+                                                           fact_manager));
   auto transformation_use_of_20_in_store =
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_20_in_store, blockname_4, 106, 107);
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_20_in_store,
-                                           context.get(), fact_manager));
-
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_13_in_store,
-                                           context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_15_in_add,
-                                           context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_17_in_add,
-                                           context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_20_in_store,
-                                           context.get(), fact_manager));
-
-  transformation::Apply(transformation_use_of_13_in_store, context.get(),
-                        &fact_manager);
+      TransformationReplaceConstantWithUniform(use_of_20_in_store, blockname_4,
+                                               106, 107);
+  ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(context.get(),
+                                                             fact_manager));
+
+  ASSERT_TRUE(transformation_use_of_13_in_store.IsApplicable(context.get(),
+                                                             fact_manager));
+  ASSERT_TRUE(transformation_use_of_15_in_add.IsApplicable(context.get(),
+                                                           fact_manager));
+  ASSERT_TRUE(transformation_use_of_17_in_add.IsApplicable(context.get(),
+                                                           fact_manager));
+  ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(context.get(),
+                                                             fact_manager));
+
+  transformation_use_of_13_in_store.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
-  ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_13_in_store,
-                                            context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_15_in_add,
-                                           context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_17_in_add,
-                                           context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_20_in_store,
-                                           context.get(), fact_manager));
-
-  transformation::Apply(transformation_use_of_15_in_add, context.get(),
-                        &fact_manager);
+  ASSERT_FALSE(transformation_use_of_13_in_store.IsApplicable(context.get(),
+                                                              fact_manager));
+  ASSERT_TRUE(transformation_use_of_15_in_add.IsApplicable(context.get(),
+                                                           fact_manager));
+  ASSERT_TRUE(transformation_use_of_17_in_add.IsApplicable(context.get(),
+                                                           fact_manager));
+  ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(context.get(),
+                                                             fact_manager));
+
+  transformation_use_of_15_in_add.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
-  ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_13_in_store,
-                                            context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_15_in_add,
-                                            context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_17_in_add,
-                                           context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_20_in_store,
-                                           context.get(), fact_manager));
-
-  transformation::Apply(transformation_use_of_17_in_add, context.get(),
-                        &fact_manager);
+  ASSERT_FALSE(transformation_use_of_13_in_store.IsApplicable(context.get(),
+                                                              fact_manager));
+  ASSERT_FALSE(transformation_use_of_15_in_add.IsApplicable(context.get(),
+                                                            fact_manager));
+  ASSERT_TRUE(transformation_use_of_17_in_add.IsApplicable(context.get(),
+                                                           fact_manager));
+  ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(context.get(),
+                                                             fact_manager));
+
+  transformation_use_of_17_in_add.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
-  ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_13_in_store,
-                                            context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_15_in_add,
-                                            context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_17_in_add,
-                                            context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(transformation_use_of_20_in_store,
-                                           context.get(), fact_manager));
-
-  transformation::Apply(transformation_use_of_20_in_store, context.get(),
-                        &fact_manager);
+  ASSERT_FALSE(transformation_use_of_13_in_store.IsApplicable(context.get(),
+                                                              fact_manager));
+  ASSERT_FALSE(transformation_use_of_15_in_add.IsApplicable(context.get(),
+                                                            fact_manager));
+  ASSERT_FALSE(transformation_use_of_17_in_add.IsApplicable(context.get(),
+                                                            fact_manager));
+  ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(context.get(),
+                                                             fact_manager));
+
+  transformation_use_of_20_in_store.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
-  ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_13_in_store,
-                                            context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_15_in_add,
-                                            context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_17_in_add,
-                                            context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(transformation_use_of_20_in_store,
-                                            context.get(), fact_manager));
+  ASSERT_FALSE(transformation_use_of_13_in_store.IsApplicable(context.get(),
+                                                              fact_manager));
+  ASSERT_FALSE(transformation_use_of_15_in_add.IsApplicable(context.get(),
+                                                            fact_manager));
+  ASSERT_FALSE(transformation_use_of_17_in_add.IsApplicable(context.get(),
+                                                            fact_manager));
+  ASSERT_FALSE(transformation_use_of_20_in_store.IsApplicable(context.get(),
+                                                              fact_manager));
 
   std::string after = R"(
                OpCapability Shader
@@ -722,10 +707,9 @@ TEST(TransformationReplaceConstantWithUniformTest, NoUniformIntPointerPresent) {
 
   // This transformation is not available because no uniform pointer to integer
   // type is present:
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_9_in_store, blockname_0, 100, 101),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
+                                                        blockname_0, 100, 101)
+                   .IsApplicable(context.get(), fact_manager));
 }
 
 TEST(TransformationReplaceConstantWithUniformTest, NoConstantPresentForIndex) {
@@ -798,10 +782,9 @@ TEST(TransformationReplaceConstantWithUniformTest, NoConstantPresentForIndex) {
 
   // This transformation is not available because no constant is present for the
   // index 1 required to index into the uniform buffer:
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_9_in_store, blockname_9, 100, 101),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
+                                                        blockname_9, 100, 101)
+                   .IsApplicable(context.get(), fact_manager));
 }
 
 TEST(TransformationReplaceConstantWithUniformTest,
@@ -873,10 +856,9 @@ TEST(TransformationReplaceConstantWithUniformTest,
 
   // This transformation is not available because no integer type is present to
   // allow a constant index to be expressed:
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_9_in_store, blockname_3, 100, 101),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
+                                                        blockname_3, 100, 101)
+                   .IsApplicable(context.get(), fact_manager));
 }
 
 TEST(TransformationReplaceConstantWithUniformTest,
@@ -960,25 +942,21 @@ TEST(TransformationReplaceConstantWithUniformTest,
       transformation::MakeIdUseDescriptor(11, SpvOpStore, 1, 10, 1);
 
   // These are right:
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_9_in_store, blockname_9, 100, 101),
-      context.get(), fact_manager));
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_11_in_store, blockname_10, 102, 103),
-      context.get(), fact_manager));
+  ASSERT_TRUE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
+                                                       blockname_9, 100, 101)
+                  .IsApplicable(context.get(), fact_manager));
+  ASSERT_TRUE(TransformationReplaceConstantWithUniform(use_of_11_in_store,
+                                                       blockname_10, 102, 103)
+                  .IsApplicable(context.get(), fact_manager));
 
   // These are wrong because the constants do not match the facts about
   // uniforms.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_11_in_store, blockname_9, 100, 101),
-      context.get(), fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          use_of_9_in_store, blockname_10, 102, 103),
-      context.get(), fact_manager));
+  ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_11_in_store,
+                                                        blockname_9, 100, 101)
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
+                                                        blockname_10, 102, 103)
+                   .IsApplicable(context.get(), fact_manager));
 }
 
 TEST(TransformationReplaceConstantWithUniformTest, ComplexReplacements) {
@@ -1239,83 +1217,65 @@ TEST(TransformationReplaceConstantWithUniformTest, ComplexReplacements) {
   ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 100, uniform_h_x));
   ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 200, uniform_h_y));
 
-  std::vector<protobufs::TransformationReplaceConstantWithUniform>
-      transformations;
-
-  transformations.emplace_back(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          transformation::MakeIdUseDescriptor(18, SpvOpStore, 1, 20, 0),
-          uniform_f_a_4, 200, 201));
-  transformations.emplace_back(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          transformation::MakeIdUseDescriptor(22, SpvOpStore, 1, 23, 0),
-          uniform_f_a_3, 202, 203));
-  transformations.emplace_back(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          transformation::MakeIdUseDescriptor(25, SpvOpStore, 1, 26, 0),
-          uniform_f_a_2, 204, 205));
-  transformations.emplace_back(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          transformation::MakeIdUseDescriptor(28, SpvOpStore, 1, 29, 0),
-          uniform_f_a_1, 206, 207));
-  transformations.emplace_back(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          transformation::MakeIdUseDescriptor(31, SpvOpStore, 1, 32, 0),
-          uniform_f_a_0, 208, 209));
-
-  transformations.emplace_back(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          transformation::MakeIdUseDescriptor(30, SpvOpStore, 1, 35, 0),
-          uniform_f_b_w, 210, 211));
-  transformations.emplace_back(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          transformation::MakeIdUseDescriptor(27, SpvOpStore, 1, 37, 0),
-          uniform_f_b_z, 212, 213));
-  transformations.emplace_back(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          transformation::MakeIdUseDescriptor(24, SpvOpStore, 1, 39, 0),
-          uniform_f_b_y, 214, 215));
-  transformations.emplace_back(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          transformation::MakeIdUseDescriptor(21, SpvOpStore, 1, 41, 0),
-          uniform_f_b_x, 216, 217));
-
-  transformations.emplace_back(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          transformation::MakeIdUseDescriptor(44, SpvOpStore, 1, 45, 0),
-          uniform_f_c_z, 220, 221));
-  transformations.emplace_back(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          transformation::MakeIdUseDescriptor(46, SpvOpStore, 1, 47, 0),
-          uniform_f_c_y, 222, 223));
-  transformations.emplace_back(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          transformation::MakeIdUseDescriptor(48, SpvOpStore, 1, 49, 0),
-          uniform_f_c_x, 224, 225));
-
-  transformations.emplace_back(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          transformation::MakeIdUseDescriptor(50, SpvOpStore, 1, 52, 0),
-          uniform_f_d, 226, 227));
-
-  transformations.emplace_back(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          transformation::MakeIdUseDescriptor(53, SpvOpStore, 1, 54, 0),
-          uniform_h_x, 228, 229));
-  transformations.emplace_back(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          transformation::MakeIdUseDescriptor(55, SpvOpStore, 1, 56, 0),
-          uniform_h_y, 230, 231));
-
-  transformations.emplace_back(
-      transformation::MakeTransformationReplaceConstantWithUniform(
-          transformation::MakeIdUseDescriptor(42, SpvOpStore, 1, 43, 0),
-          uniform_g, 218, 219));
+  std::vector<TransformationReplaceConstantWithUniform> transformations;
+
+  transformations.emplace_back(TransformationReplaceConstantWithUniform(
+      transformation::MakeIdUseDescriptor(18, SpvOpStore, 1, 20, 0),
+      uniform_f_a_4, 200, 201));
+  transformations.emplace_back(TransformationReplaceConstantWithUniform(
+      transformation::MakeIdUseDescriptor(22, SpvOpStore, 1, 23, 0),
+      uniform_f_a_3, 202, 203));
+  transformations.emplace_back(TransformationReplaceConstantWithUniform(
+      transformation::MakeIdUseDescriptor(25, SpvOpStore, 1, 26, 0),
+      uniform_f_a_2, 204, 205));
+  transformations.emplace_back(TransformationReplaceConstantWithUniform(
+      transformation::MakeIdUseDescriptor(28, SpvOpStore, 1, 29, 0),
+      uniform_f_a_1, 206, 207));
+  transformations.emplace_back(TransformationReplaceConstantWithUniform(
+      transformation::MakeIdUseDescriptor(31, SpvOpStore, 1, 32, 0),
+      uniform_f_a_0, 208, 209));
+
+  transformations.emplace_back(TransformationReplaceConstantWithUniform(
+      transformation::MakeIdUseDescriptor(30, SpvOpStore, 1, 35, 0),
+      uniform_f_b_w, 210, 211));
+  transformations.emplace_back(TransformationReplaceConstantWithUniform(
+      transformation::MakeIdUseDescriptor(27, SpvOpStore, 1, 37, 0),
+      uniform_f_b_z, 212, 213));
+  transformations.emplace_back(TransformationReplaceConstantWithUniform(
+      transformation::MakeIdUseDescriptor(24, SpvOpStore, 1, 39, 0),
+      uniform_f_b_y, 214, 215));
+  transformations.emplace_back(TransformationReplaceConstantWithUniform(
+      transformation::MakeIdUseDescriptor(21, SpvOpStore, 1, 41, 0),
+      uniform_f_b_x, 216, 217));
+
+  transformations.emplace_back(TransformationReplaceConstantWithUniform(
+      transformation::MakeIdUseDescriptor(44, SpvOpStore, 1, 45, 0),
+      uniform_f_c_z, 220, 221));
+  transformations.emplace_back(TransformationReplaceConstantWithUniform(
+      transformation::MakeIdUseDescriptor(46, SpvOpStore, 1, 47, 0),
+      uniform_f_c_y, 222, 223));
+  transformations.emplace_back(TransformationReplaceConstantWithUniform(
+      transformation::MakeIdUseDescriptor(48, SpvOpStore, 1, 49, 0),
+      uniform_f_c_x, 224, 225));
+
+  transformations.emplace_back(TransformationReplaceConstantWithUniform(
+      transformation::MakeIdUseDescriptor(50, SpvOpStore, 1, 52, 0),
+      uniform_f_d, 226, 227));
+
+  transformations.emplace_back(TransformationReplaceConstantWithUniform(
+      transformation::MakeIdUseDescriptor(53, SpvOpStore, 1, 54, 0),
+      uniform_h_x, 228, 229));
+  transformations.emplace_back(TransformationReplaceConstantWithUniform(
+      transformation::MakeIdUseDescriptor(55, SpvOpStore, 1, 56, 0),
+      uniform_h_y, 230, 231));
+
+  transformations.emplace_back(TransformationReplaceConstantWithUniform(
+      transformation::MakeIdUseDescriptor(42, SpvOpStore, 1, 43, 0), uniform_g,
+      218, 219));
 
   for (auto& transformation : transformations) {
-    ASSERT_TRUE(transformation::IsApplicable(transformation, context.get(),
-                                             fact_manager));
-    transformation::Apply(transformation, context.get(), &fact_manager);
+    ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
+    transformation.Apply(context.get(), &fact_manager);
     ASSERT_TRUE(IsValid(env, context.get()));
   }
 

+ 62 - 86
3rdparty/spirv-tools/test/fuzz/transformation_split_block_test.cpp

@@ -90,57 +90,44 @@ TEST(TransformationSplitBlockTest, NotApplicable) {
   FactManager fact_manager;
 
   // No split before OpVariable
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(8, 0, 100), context.get(),
-      fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(8, 1, 100), context.get(),
-      fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(8, 0, 100).IsApplicable(context.get(),
+                                                                fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(8, 1, 100).IsApplicable(context.get(),
+                                                                fact_manager));
 
   // No split before OpLabel
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(14, 0, 100), context.get(),
-      fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(14, 0, 100)
+                   .IsApplicable(context.get(), fact_manager));
 
   // No split if base instruction is outside a function
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(1, 0, 100), context.get(),
-      fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(1, 4, 100), context.get(),
-      fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(1, 35, 100), context.get(),
-      fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(1, 0, 100).IsApplicable(context.get(),
+                                                                fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(1, 4, 100).IsApplicable(context.get(),
+                                                                fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(1, 35, 100)
+                   .IsApplicable(context.get(), fact_manager));
 
   // No split if block is loop header
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(27, 0, 100), context.get(),
-      fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(27, 1, 100), context.get(),
-      fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(27, 0, 100)
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(27, 1, 100)
+                   .IsApplicable(context.get(), fact_manager));
 
   // No split if base instruction does not exist
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(88, 0, 100), context.get(),
-      fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(88, 22, 100), context.get(),
-      fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(88, 0, 100)
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(88, 22, 100)
+                   .IsApplicable(context.get(), fact_manager));
 
   // No split if offset is too large (goes into another block)
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(18, 3, 100), context.get(),
-      fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(18, 3, 100)
+                   .IsApplicable(context.get(), fact_manager));
 
   // No split if id in use
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(18, 0, 27), context.get(),
-      fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(18, 0, 14), context.get(),
-      fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(18, 0, 27).IsApplicable(context.get(),
+                                                                fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(18, 0, 14).IsApplicable(context.get(),
+                                                                fact_manager));
 }
 
 TEST(TransformationSplitBlockTest, SplitBlockSeveralTimes) {
@@ -201,10 +188,9 @@ TEST(TransformationSplitBlockTest, SplitBlockSeveralTimes) {
 
   FactManager fact_manager;
 
-  auto split_1 = transformation::MakeTransformationSplitBlock(5, 3, 100);
-  ASSERT_TRUE(
-      transformation::IsApplicable(split_1, context.get(), fact_manager));
-  transformation::Apply(split_1, context.get(), &fact_manager);
+  auto split_1 = TransformationSplitBlock(5, 3, 100);
+  ASSERT_TRUE(split_1.IsApplicable(context.get(), fact_manager));
+  split_1.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after_split_1 = R"(
@@ -249,10 +235,9 @@ TEST(TransformationSplitBlockTest, SplitBlockSeveralTimes) {
   )";
   ASSERT_TRUE(IsEqual(env, after_split_1, context.get()));
 
-  auto split_2 = transformation::MakeTransformationSplitBlock(11, 1, 101);
-  ASSERT_TRUE(
-      transformation::IsApplicable(split_2, context.get(), fact_manager));
-  transformation::Apply(split_2, context.get(), &fact_manager);
+  auto split_2 = TransformationSplitBlock(11, 1, 101);
+  ASSERT_TRUE(split_2.IsApplicable(context.get(), fact_manager));
+  split_2.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after_split_2 = R"(
@@ -299,10 +284,9 @@ TEST(TransformationSplitBlockTest, SplitBlockSeveralTimes) {
   )";
   ASSERT_TRUE(IsEqual(env, after_split_2, context.get()));
 
-  auto split_3 = transformation::MakeTransformationSplitBlock(14, 0, 102);
-  ASSERT_TRUE(
-      transformation::IsApplicable(split_3, context.get(), fact_manager));
-  transformation::Apply(split_3, context.get(), &fact_manager);
+  auto split_3 = TransformationSplitBlock(14, 0, 102);
+  ASSERT_TRUE(split_3.IsApplicable(context.get(), fact_manager));
+  split_3.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after_split_3 = R"(
@@ -415,16 +399,14 @@ TEST(TransformationSplitBlockTest, SplitBlockBeforeSelectBranch) {
   FactManager fact_manager;
 
   // Illegal to split between the merge and the conditional branch.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(14, 2, 100), context.get(),
-      fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(12, 3, 100), context.get(),
-      fact_manager));
-
-  auto split = transformation::MakeTransformationSplitBlock(14, 1, 100);
-  ASSERT_TRUE(transformation::IsApplicable(split, context.get(), fact_manager));
-  transformation::Apply(split, context.get(), &fact_manager);
+  ASSERT_FALSE(TransformationSplitBlock(14, 2, 100)
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(12, 3, 100)
+                   .IsApplicable(context.get(), fact_manager));
+
+  auto split = TransformationSplitBlock(14, 1, 100);
+  ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager));
+  split.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after_split = R"(
@@ -541,16 +523,14 @@ TEST(TransformationSplitBlockTest, SplitBlockBeforeSwitchBranch) {
   FactManager fact_manager;
 
   // Illegal to split between the merge and the conditional branch.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(9, 2, 100), context.get(),
-      fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(15, 3, 100), context.get(),
-      fact_manager));
-
-  auto split = transformation::MakeTransformationSplitBlock(9, 1, 100);
-  ASSERT_TRUE(transformation::IsApplicable(split, context.get(), fact_manager));
-  transformation::Apply(split, context.get(), &fact_manager);
+  ASSERT_FALSE(TransformationSplitBlock(9, 2, 100).IsApplicable(context.get(),
+                                                                fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(15, 3, 100)
+                   .IsApplicable(context.get(), fact_manager));
+
+  auto split = TransformationSplitBlock(9, 1, 100);
+  ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager));
+  split.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after_split = R"(
@@ -674,15 +654,12 @@ TEST(TransformationSplitBlockTest, NoSplitDuringOpPhis) {
 
   // We cannot split before OpPhi instructions, since the number of incoming
   // blocks may not appropriately match after splitting.
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(26, 0, 100), context.get(),
-      fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(27, 0, 100), context.get(),
-      fact_manager));
-  ASSERT_FALSE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(27, 1, 100), context.get(),
-      fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(26, 0, 100)
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(27, 0, 100)
+                   .IsApplicable(context.get(), fact_manager));
+  ASSERT_FALSE(TransformationSplitBlock(27, 1, 100)
+                   .IsApplicable(context.get(), fact_manager));
 }
 
 TEST(TransformationSplitBlockTest, SplitOpPhiWithSinglePredecessor) {
@@ -724,12 +701,11 @@ TEST(TransformationSplitBlockTest, SplitOpPhiWithSinglePredecessor) {
 
   FactManager fact_manager;
 
-  ASSERT_TRUE(transformation::IsApplicable(
-      transformation::MakeTransformationSplitBlock(21, 0, 100), context.get(),
-      fact_manager));
-  auto split = transformation::MakeTransformationSplitBlock(20, 1, 100);
-  ASSERT_TRUE(transformation::IsApplicable(split, context.get(), fact_manager));
-  transformation::Apply(split, context.get(), &fact_manager);
+  ASSERT_TRUE(TransformationSplitBlock(21, 0, 100)
+                  .IsApplicable(context.get(), fact_manager));
+  auto split = TransformationSplitBlock(20, 1, 100);
+  ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager));
+  split.Apply(context.get(), &fact_manager);
   ASSERT_TRUE(IsValid(env, context.get()));
 
   std::string after_split = R"(

+ 322 - 0
3rdparty/spirv-tools/test/opt/inst_bindless_check_test.cpp

@@ -8276,6 +8276,328 @@ OpFunctionEnd
       true, 7u, 23u, true, true, 2u);
 }
 
+TEST_F(InstBindlessTest,
+       InstBoundsComputeShaderInitLoadVariableSizedSampledImagesArray) {
+  // #version 450
+  // #extension GL_EXT_nonuniform_qualifier : enable
+  //
+  // layout (local_size_x = 1, local_size_y = 1) in;
+  //
+  // layout(set = 0, binding = 0, std140) buffer Input {
+  //   uint index;
+  //   float red;
+  // } sbo;
+  //
+  // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[];
+  //
+  // void main()
+  // {
+  //    sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r;
+  // }
+
+  const std::string defs_before =
+      R"(OpCapability Shader
+OpCapability RuntimeDescriptorArrayEXT
+OpExtension "SPV_EXT_descriptor_indexing"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpSource GLSL 450
+OpSourceExtension "GL_EXT_nonuniform_qualifier"
+OpName %main "main"
+OpName %Input "Input"
+OpMemberName %Input 0 "index"
+OpMemberName %Input 1 "red"
+OpName %sbo "sbo"
+OpName %images "images"
+OpMemberDecorate %Input 0 Offset 0
+OpMemberDecorate %Input 1 Offset 4
+OpDecorate %Input BufferBlock
+OpDecorate %sbo DescriptorSet 0
+OpDecorate %sbo Binding 0
+OpDecorate %images DescriptorSet 0
+OpDecorate %images Binding 1
+OpDecorate %images NonWritable
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%float = OpTypeFloat 32
+%Input = OpTypeStruct %uint %float
+%_ptr_Uniform_Input = OpTypePointer Uniform %Input
+%sbo = OpVariable %_ptr_Uniform_Input Uniform
+%int = OpTypeInt 32 1
+%int_1 = OpConstant %int 1
+%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
+%_runtimearr_13 = OpTypeRuntimeArray %13
+%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
+%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+%v2int = OpTypeVector %int 2
+%25 = OpConstantComposite %v2int %int_0 %int_0
+%v4float = OpTypeVector %float 4
+%uint_0 = OpConstant %uint 0
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+)";
+
+  const std::string defs_after =
+      R"(OpCapability Shader
+OpCapability RuntimeDescriptorArrayEXT
+OpExtension "SPV_EXT_descriptor_indexing"
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
+OpExecutionMode %main LocalSize 1 1 1
+OpSource GLSL 450
+OpSourceExtension "GL_EXT_nonuniform_qualifier"
+OpName %main "main"
+OpName %Input "Input"
+OpMemberName %Input 0 "index"
+OpMemberName %Input 1 "red"
+OpName %sbo "sbo"
+OpName %images "images"
+OpMemberDecorate %Input 0 Offset 0
+OpMemberDecorate %Input 1 Offset 4
+OpDecorate %Input BufferBlock
+OpDecorate %sbo DescriptorSet 0
+OpDecorate %sbo Binding 0
+OpDecorate %images DescriptorSet 0
+OpDecorate %images Binding 1
+OpDecorate %images NonWritable
+OpDecorate %_runtimearr_uint ArrayStride 4
+OpDecorate %_struct_39 Block
+OpMemberDecorate %_struct_39 0 Offset 0
+OpDecorate %41 DescriptorSet 7
+OpDecorate %41 Binding 1
+OpDecorate %_struct_63 Block
+OpMemberDecorate %_struct_63 0 Offset 0
+OpMemberDecorate %_struct_63 1 Offset 4
+OpDecorate %65 DescriptorSet 7
+OpDecorate %65 Binding 0
+OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
+%void = OpTypeVoid
+%7 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%float = OpTypeFloat 32
+%Input = OpTypeStruct %uint %float
+%_ptr_Uniform_Input = OpTypePointer Uniform %Input
+%sbo = OpVariable %_ptr_Uniform_Input Uniform
+%int = OpTypeInt 32 1
+%int_1 = OpConstant %int 1
+%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
+%_runtimearr_13 = OpTypeRuntimeArray %13
+%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
+%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+%v2int = OpTypeVector %int 2
+%20 = OpConstantComposite %v2int %int_0 %int_0
+%v4float = OpTypeVector %float 4
+%uint_0 = OpConstant %uint 0
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%uint_1 = OpConstant %uint 1
+%34 = OpTypeFunction %uint %uint %uint
+%_runtimearr_uint = OpTypeRuntimeArray %uint
+%_struct_39 = OpTypeStruct %_runtimearr_uint
+%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39
+%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer
+%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+%bool = OpTypeBool
+%57 = OpTypeFunction %void %uint %uint %uint %uint
+%_struct_63 = OpTypeStruct %uint %_runtimearr_uint
+%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63
+%65 = OpVariable %_ptr_StorageBuffer__struct_63 StorageBuffer
+%uint_10 = OpConstant %uint 10
+%uint_4 = OpConstant %uint 4
+%uint_23 = OpConstant %uint 23
+%uint_2 = OpConstant %uint 2
+%uint_5 = OpConstant %uint 5
+%uint_3 = OpConstant %uint 3
+%v3uint = OpTypeVector %uint 3
+%_ptr_Input_v3uint = OpTypePointer Input %v3uint
+%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
+%uint_6 = OpConstant %uint 6
+%uint_7 = OpConstant %uint 7
+%uint_8 = OpConstant %uint 8
+%uint_9 = OpConstant %uint 9
+%uint_50 = OpConstant %uint 50
+%112 = OpConstantNull %v4float
+%115 = OpTypeFunction %uint %uint %uint %uint %uint
+%uint_47 = OpConstant %uint 47
+%140 = OpConstantNull %uint
+%uint_53 = OpConstant %uint 53
+)";
+
+  const std::string func_before =
+      R"(%main = OpFunction %void None %3
+%5 = OpLabel
+%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
+%20 = OpLoad %uint %19
+%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
+%23 = OpLoad %13 %22
+%27 = OpImageRead %v4float %23 %25
+%29 = OpCompositeExtract %float %27 0
+%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+OpStore %31 %29
+OpReturn
+OpFunctionEnd
+)";
+
+  const std::string func_after =
+      R"(%main = OpFunction %void None %7
+%24 = OpLabel
+%25 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
+%132 = OpFunctionCall %uint %114 %uint_0 %uint_0 %uint_0 %uint_0
+%133 = OpINotEqual %bool %132 %uint_0
+OpSelectionMerge %134 None
+OpBranchConditional %133 %135 %136
+%135 = OpLabel
+%137 = OpLoad %uint %25
+OpBranch %134
+%136 = OpLabel
+%139 = OpFunctionCall %void %56 %uint_47 %uint_1 %uint_0 %uint_0
+OpBranch %134
+%134 = OpLabel
+%141 = OpPhi %uint %137 %135 %140 %136
+%27 = OpAccessChain %_ptr_UniformConstant_13 %images %141
+%28 = OpLoad %13 %27
+%48 = OpFunctionCall %uint %33 %uint_1 %uint_1
+%50 = OpULessThan %bool %141 %48
+OpSelectionMerge %51 None
+OpBranchConditional %50 %52 %53
+%52 = OpLabel
+%54 = OpLoad %13 %27
+%142 = OpFunctionCall %uint %114 %uint_0 %uint_0 %uint_1 %141
+%143 = OpINotEqual %bool %142 %uint_0
+OpSelectionMerge %144 None
+OpBranchConditional %143 %145 %146
+%145 = OpLabel
+%147 = OpLoad %13 %27
+%148 = OpImageRead %v4float %147 %20
+OpBranch %144
+%146 = OpLabel
+%149 = OpFunctionCall %void %56 %uint_50 %uint_1 %141 %uint_0
+OpBranch %144
+%144 = OpLabel
+%150 = OpPhi %v4float %148 %145 %112 %146
+OpBranch %51
+%53 = OpLabel
+%111 = OpFunctionCall %void %56 %uint_50 %uint_0 %141 %48
+OpBranch %51
+%51 = OpLabel
+%113 = OpPhi %v4float %150 %144 %112 %53
+%30 = OpCompositeExtract %float %113 0
+%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+%151 = OpFunctionCall %uint %114 %uint_0 %uint_0 %uint_0 %uint_0
+%152 = OpINotEqual %bool %151 %uint_0
+OpSelectionMerge %153 None
+OpBranchConditional %152 %154 %155
+%154 = OpLabel
+OpStore %31 %30
+OpBranch %153
+%155 = OpLabel
+%157 = OpFunctionCall %void %56 %uint_53 %uint_1 %uint_0 %uint_0
+OpBranch %153
+%153 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  const std::string new_funcs =
+      R"(%33 = OpFunction %uint None %34
+%35 = OpFunctionParameter %uint
+%36 = OpFunctionParameter %uint
+%37 = OpLabel
+%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %35
+%44 = OpLoad %uint %43
+%45 = OpIAdd %uint %44 %36
+%46 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %45
+%47 = OpLoad %uint %46
+OpReturnValue %47
+OpFunctionEnd
+%56 = OpFunction %void None %57
+%58 = OpFunctionParameter %uint
+%59 = OpFunctionParameter %uint
+%60 = OpFunctionParameter %uint
+%61 = OpFunctionParameter %uint
+%62 = OpLabel
+%66 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0
+%69 = OpAtomicIAdd %uint %66 %uint_4 %uint_0 %uint_10
+%70 = OpIAdd %uint %69 %uint_10
+%71 = OpArrayLength %uint %65 1
+%72 = OpULessThanEqual %bool %70 %71
+OpSelectionMerge %73 None
+OpBranchConditional %72 %74 %73
+%74 = OpLabel
+%75 = OpIAdd %uint %69 %uint_0
+%76 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %75
+OpStore %76 %uint_10
+%78 = OpIAdd %uint %69 %uint_1
+%79 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %78
+OpStore %79 %uint_23
+%81 = OpIAdd %uint %69 %uint_2
+%82 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %81
+OpStore %82 %58
+%85 = OpIAdd %uint %69 %uint_3
+%86 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %85
+OpStore %86 %uint_5
+%90 = OpLoad %v3uint %gl_GlobalInvocationID
+%91 = OpCompositeExtract %uint %90 0
+%92 = OpCompositeExtract %uint %90 1
+%93 = OpCompositeExtract %uint %90 2
+%94 = OpIAdd %uint %69 %uint_4
+%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94
+OpStore %95 %91
+%96 = OpIAdd %uint %69 %uint_5
+%97 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %96
+OpStore %97 %92
+%99 = OpIAdd %uint %69 %uint_6
+%100 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %99
+OpStore %100 %93
+%102 = OpIAdd %uint %69 %uint_7
+%103 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %102
+OpStore %103 %59
+%105 = OpIAdd %uint %69 %uint_8
+%106 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %105
+OpStore %106 %60
+%108 = OpIAdd %uint %69 %uint_9
+%109 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %108
+OpStore %109 %61
+OpBranch %73
+%73 = OpLabel
+OpReturn
+OpFunctionEnd
+%114 = OpFunction %uint None %115
+%116 = OpFunctionParameter %uint
+%117 = OpFunctionParameter %uint
+%118 = OpFunctionParameter %uint
+%119 = OpFunctionParameter %uint
+%120 = OpLabel
+%121 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %116
+%122 = OpLoad %uint %121
+%123 = OpIAdd %uint %122 %117
+%124 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %123
+%125 = OpLoad %uint %124
+%126 = OpIAdd %uint %125 %118
+%127 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %126
+%128 = OpLoad %uint %127
+%129 = OpIAdd %uint %128 %119
+%130 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %129
+%131 = OpLoad %uint %130
+OpReturnValue %131
+OpFunctionEnd
+)";
+
+  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  SinglePassRunAndCheck<InstBindlessCheckPass>(
+      defs_before + func_before, defs_after + func_after + new_funcs, true,
+      true, 7u, 23u, true, true, 2u);
+}
+
 // TODO(greg-lunarg): Add tests to verify handling of these cases:
 //
 //   Compute shader

+ 38 - 21
3rdparty/spirv-tools/test/val/val_decoration_test.cpp

@@ -6491,10 +6491,14 @@ OpDecorate %entryPointOutput )" +
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %float = OpTypeFloat 32
-%vtype = )" + type + R"(
+%v3float = OpTypeVector %float 3
+%v4float = OpTypeVector %float 4
+%uint = OpTypeInt 32 0
+%uint_2 = OpConstant %uint 2
+%arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
 %float_0 = OpConstant %float 0
-%_ptr_Output_vtype = OpTypePointer Output %vtype
-%entryPointOutput = OpVariable %_ptr_Output_vtype Output
+%_ptr_Output_type = OpTypePointer Output %)" + type + R"(
+%entryPointOutput = OpVariable %_ptr_Output_type Output
 %main = OpFunction %void None %3
 %5 = OpLabel
 OpReturn
@@ -6504,8 +6508,7 @@ OpFunctionEnd
 
 TEST_F(ValidateDecorations, ComponentDecorationIntGood0Vulkan) {
   const spv_target_env env = SPV_ENV_VULKAN_1_0;
-  std::string spirv =
-      ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 0");
+  std::string spirv = ShaderWithComponentDecoration("uint", "Component 0");
 
   CompileSuccessfully(spirv, env);
   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
@@ -6514,8 +6517,7 @@ TEST_F(ValidateDecorations, ComponentDecorationIntGood0Vulkan) {
 
 TEST_F(ValidateDecorations, ComponentDecorationIntGood1Vulkan) {
   const spv_target_env env = SPV_ENV_VULKAN_1_0;
-  std::string spirv =
-      ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 1");
+  std::string spirv = ShaderWithComponentDecoration("uint", "Component 1");
 
   CompileSuccessfully(spirv, env);
   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
@@ -6524,8 +6526,7 @@ TEST_F(ValidateDecorations, ComponentDecorationIntGood1Vulkan) {
 
 TEST_F(ValidateDecorations, ComponentDecorationIntGood2Vulkan) {
   const spv_target_env env = SPV_ENV_VULKAN_1_0;
-  std::string spirv =
-      ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 2");
+  std::string spirv = ShaderWithComponentDecoration("uint", "Component 2");
 
   CompileSuccessfully(spirv, env);
   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
@@ -6534,8 +6535,7 @@ TEST_F(ValidateDecorations, ComponentDecorationIntGood2Vulkan) {
 
 TEST_F(ValidateDecorations, ComponentDecorationIntGood3Vulkan) {
   const spv_target_env env = SPV_ENV_VULKAN_1_0;
-  std::string spirv =
-      ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 3");
+  std::string spirv = ShaderWithComponentDecoration("uint", "Component 3");
 
   CompileSuccessfully(spirv, env);
   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
@@ -6544,8 +6544,7 @@ TEST_F(ValidateDecorations, ComponentDecorationIntGood3Vulkan) {
 
 TEST_F(ValidateDecorations, ComponentDecorationIntBad4Vulkan) {
   const spv_target_env env = SPV_ENV_VULKAN_1_0;
-  std::string spirv =
-      ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 4");
+  std::string spirv = ShaderWithComponentDecoration("uint", "Component 4");
 
   CompileSuccessfully(spirv, env);
   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
@@ -6556,8 +6555,7 @@ TEST_F(ValidateDecorations, ComponentDecorationIntBad4Vulkan) {
 
 TEST_F(ValidateDecorations, ComponentDecorationVector3GoodVulkan) {
   const spv_target_env env = SPV_ENV_VULKAN_1_0;
-  std::string spirv =
-      ShaderWithComponentDecoration("OpTypeVector %float 3", "Component 1");
+  std::string spirv = ShaderWithComponentDecoration("v3float", "Component 1");
 
   CompileSuccessfully(spirv, env);
   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
@@ -6566,8 +6564,7 @@ TEST_F(ValidateDecorations, ComponentDecorationVector3GoodVulkan) {
 
 TEST_F(ValidateDecorations, ComponentDecorationVector4GoodVulkan) {
   const spv_target_env env = SPV_ENV_VULKAN_1_0;
-  std::string spirv =
-      ShaderWithComponentDecoration("OpTypeVector %float 4", "Component 0");
+  std::string spirv = ShaderWithComponentDecoration("v4float", "Component 0");
 
   CompileSuccessfully(spirv, env);
   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
@@ -6576,8 +6573,7 @@ TEST_F(ValidateDecorations, ComponentDecorationVector4GoodVulkan) {
 
 TEST_F(ValidateDecorations, ComponentDecorationVector4Bad1Vulkan) {
   const spv_target_env env = SPV_ENV_VULKAN_1_0;
-  std::string spirv =
-      ShaderWithComponentDecoration("OpTypeVector %float 4", "Component 1");
+  std::string spirv = ShaderWithComponentDecoration("v4float", "Component 1");
 
   CompileSuccessfully(spirv, env);
   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
@@ -6588,8 +6584,7 @@ TEST_F(ValidateDecorations, ComponentDecorationVector4Bad1Vulkan) {
 
 TEST_F(ValidateDecorations, ComponentDecorationVector4Bad3Vulkan) {
   const spv_target_env env = SPV_ENV_VULKAN_1_0;
-  std::string spirv =
-      ShaderWithComponentDecoration("OpTypeVector %float 4", "Component 3");
+  std::string spirv = ShaderWithComponentDecoration("v4float", "Component 3");
 
   CompileSuccessfully(spirv, env);
   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
@@ -6598,6 +6593,28 @@ TEST_F(ValidateDecorations, ComponentDecorationVector4Bad3Vulkan) {
                         "and ending with 6 gets larger than 3"));
 }
 
+TEST_F(ValidateDecorations, ComponentDecorationArrayGoodVulkan) {
+  const spv_target_env env = SPV_ENV_VULKAN_1_0;
+  std::string spirv =
+      ShaderWithComponentDecoration("arr_v3float_uint_2", "Component 1");
+
+  CompileSuccessfully(spirv, env);
+  EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
+  EXPECT_THAT(getDiagnosticString(), Eq(""));
+}
+
+TEST_F(ValidateDecorations, ComponentDecorationArrayBadVulkan) {
+  const spv_target_env env = SPV_ENV_VULKAN_1_0;
+  std::string spirv =
+      ShaderWithComponentDecoration("arr_v3float_uint_2", "Component 2");
+
+  CompileSuccessfully(spirv, env);
+  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Sequence of components starting with 2 "
+                        "and ending with 4 gets larger than 3"));
+}
+
 TEST_F(ValidateDecorations, ComponentDecorationBlockGood) {
   std::string spirv = R"(
 OpCapability Shader

+ 1 - 1
3rdparty/spirv-tools/tools/fuzz/fuzz.cpp

@@ -257,7 +257,7 @@ int main(int argc, const char** argv) {
   const std::string dot_spv(".spv");
   std::string in_facts_file =
       in_binary_file.substr(0, in_binary_file.length() - dot_spv.length()) +
-      ".json";
+      ".facts";
   std::ifstream facts_input(in_facts_file);
   if (facts_input) {
     std::string facts_json_string((std::istreambuf_iterator<char>(facts_input)),

+ 0 - 2
3rdparty/spirv-tools/tools/reduce/reduce.cpp

@@ -28,8 +28,6 @@
 
 namespace {
 
-using ErrorOrInt = std::pair<std::string, int>;
-
 // Check that the std::system function can actually be used.
 bool CheckExecuteCommand() {
   int res = std::system(nullptr);

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff