spirv-fuzz: Fix usages of irrelevant constants (#3566)

Part of #3177.
diff --git a/source/fuzz/fuzzer_pass_add_synonyms.cpp b/source/fuzz/fuzzer_pass_add_synonyms.cpp
index 032f369..e7bf6fa 100644
--- a/source/fuzz/fuzzer_pass_add_synonyms.cpp
+++ b/source/fuzz/fuzzer_pass_add_synonyms.cpp
@@ -53,11 +53,12 @@
         // Select all instructions that can be used to create a synonym to.
         auto available_instructions = FindAvailableInstructions(
             function, block, inst_it,
-            [synonym_type](opt::IRContext* ir_context, opt::Instruction* inst) {
+            [synonym_type, this](opt::IRContext* ir_context,
+                                 opt::Instruction* inst) {
               // Check that we can create a synonym to |inst| as described by
               // the |synonym_type| and insert it before |inst_it|.
               return TransformationAddSynonym::IsInstructionValid(
-                  ir_context, inst, synonym_type);
+                  ir_context, *GetTransformationContext(), inst, synonym_type);
             });
 
         if (available_instructions.empty()) {
diff --git a/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp b/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp
index 21b5310..453448b 100644
--- a/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp
+++ b/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp
@@ -60,10 +60,10 @@
         std::vector<opt::Instruction*> vector_instructions =
             FindAvailableInstructions(
                 function, block, instruction_iterator,
-                [instruction_descriptor](
+                [this, instruction_descriptor](
                     opt::IRContext* ir_context,
                     opt::Instruction* instruction) -> bool {
-                  if (!instruction->type_id()) {
+                  if (!instruction->result_id() || !instruction->type_id()) {
                     return false;
                   }
 
@@ -73,6 +73,18 @@
                     return false;
                   }
 
+                  if (!GetTransformationContext()
+                           ->GetFactManager()
+                           ->IdIsIrrelevant(instruction->result_id()) &&
+                      !fuzzerutil::CanMakeSynonymOf(ir_context,
+                                                    *GetTransformationContext(),
+                                                    instruction)) {
+                    // If the id is irrelevant, we can use it since it will not
+                    // participate in DataSynonym fact. Otherwise, we should be
+                    // able to produce a synonym out of the id.
+                    return false;
+                  }
+
                   return fuzzerutil::IdIsAvailableBeforeInstruction(
                       ir_context,
                       FindInstruction(instruction_descriptor, ir_context),
diff --git a/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp b/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp
index 122c2dd..2808ad5 100644
--- a/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp
+++ b/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp
@@ -142,6 +142,9 @@
                                                : parent_block->terminator();
           }
 
+          assert(!GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
+                     synonym_to_try->object()) &&
+                 "Irrelevant ids can't participate in DataSynonym facts");
           ApplyTransformation(TransformationCompositeExtract(
               MakeInstructionDescriptor(GetIRContext(),
                                         instruction_to_insert_before),
diff --git a/source/fuzz/fuzzer_pass_construct_composites.cpp b/source/fuzz/fuzzer_pass_construct_composites.cpp
index e78f8ec..6443e89 100644
--- a/source/fuzz/fuzzer_pass_construct_composites.cpp
+++ b/source/fuzz/fuzzer_pass_construct_composites.cpp
@@ -14,12 +14,10 @@
 
 #include "source/fuzz/fuzzer_pass_construct_composites.h"
 
-#include <cmath>
 #include <memory>
 
 #include "source/fuzz/fuzzer_util.h"
 #include "source/fuzz/transformation_composite_construct.h"
-#include "source/util/make_unique.h"
 
 namespace spvtools {
 namespace fuzz {
@@ -67,8 +65,23 @@
         // program point) and suitable for making a synonym of, associate it
         // with the id of its result type.
         TypeIdToInstructions type_id_to_available_instructions;
-        for (auto instruction : FindAvailableInstructions(
-                 function, block, inst_it, fuzzerutil::CanMakeSynonymOf)) {
+        auto available_instructions = FindAvailableInstructions(
+            function, block, inst_it,
+            [this](opt::IRContext* ir_context, opt::Instruction* inst) {
+              if (!inst->result_id() || !inst->type_id()) {
+                return false;
+              }
+
+              // If the id is irrelevant, we can use it since it will not
+              // participate in DataSynonym fact. Otherwise, we should be able
+              // to produce a synonym out of the id.
+              return GetTransformationContext()
+                         ->GetFactManager()
+                         ->IdIsIrrelevant(inst->result_id()) ||
+                     fuzzerutil::CanMakeSynonymOf(
+                         ir_context, *GetTransformationContext(), inst);
+            });
+        for (auto instruction : available_instructions) {
           RecordAvailableInstruction(instruction,
                                      &type_id_to_available_instructions);
         }
diff --git a/source/fuzz/fuzzer_pass_copy_objects.cpp b/source/fuzz/fuzzer_pass_copy_objects.cpp
index 5933bf6..81326ac 100644
--- a/source/fuzz/fuzzer_pass_copy_objects.cpp
+++ b/source/fuzz/fuzzer_pass_copy_objects.cpp
@@ -55,8 +55,12 @@
         }
 
         std::vector<opt::Instruction*> relevant_instructions =
-            FindAvailableInstructions(function, block, inst_it,
-                                      fuzzerutil::CanMakeSynonymOf);
+            FindAvailableInstructions(
+                function, block, inst_it,
+                [this](opt::IRContext* ir_context, opt::Instruction* inst) {
+                  return fuzzerutil::CanMakeSynonymOf(
+                      ir_context, *GetTransformationContext(), inst);
+                });
 
         // At this point, |relevant_instructions| contains all the instructions
         // we might think of copying.
diff --git a/source/fuzz/fuzzer_pass_interchange_zero_like_constants.cpp b/source/fuzz/fuzzer_pass_interchange_zero_like_constants.cpp
index 201c6ff..f44416a 100644
--- a/source/fuzz/fuzzer_pass_interchange_zero_like_constants.cpp
+++ b/source/fuzz/fuzzer_pass_interchange_zero_like_constants.cpp
@@ -14,6 +14,7 @@
 // limitations under the License.
 
 #include "source/fuzz/fuzzer_pass_interchange_zero_like_constants.h"
+
 #include "source/fuzz/fuzzer_util.h"
 #include "source/fuzz/id_use_descriptor.h"
 #include "source/fuzz/transformation_record_synonymous_constants.h"
@@ -83,13 +84,21 @@
 
   for (auto constant : GetIRContext()->GetConstants()) {
     uint32_t constant_id = constant->result_id();
-    uint32_t toggled_id = FindOrCreateToggledConstant(constant);
+    if (GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
+            constant_id)) {
+      continue;
+    }
 
+    uint32_t toggled_id = FindOrCreateToggledConstant(constant);
     if (!toggled_id) {
       // Not a zero-like constant
       continue;
     }
 
+    assert(!GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
+               toggled_id) &&
+           "FindOrCreateToggledConstant can't produce an irrelevant id");
+
     // Record synonymous constants
     ApplyTransformation(
         TransformationRecordSynonymousConstants(constant_id, toggled_id));
diff --git a/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp b/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp
index 0501456..1391976 100644
--- a/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp
+++ b/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp
@@ -80,7 +80,7 @@
         std::vector<opt::Instruction*> value_instructions =
             FindAvailableInstructions(
                 function, block, instruction_iterator,
-                [basic_type_id, instruction_descriptor](
+                [this, basic_type_id, instruction_descriptor](
                     opt::IRContext* ir_context,
                     opt::Instruction* instruction) -> bool {
                   if (!instruction->result_id() || !instruction->type_id()) {
@@ -91,6 +91,12 @@
                     return false;
                   }
 
+                  if (!fuzzerutil::CanMakeSynonymOf(ir_context,
+                                                    *GetTransformationContext(),
+                                                    instruction)) {
+                    return false;
+                  }
+
                   return fuzzerutil::IdIsAvailableBeforeInstruction(
                       ir_context,
                       FindInstruction(instruction_descriptor, ir_context),
diff --git a/source/fuzz/fuzzer_util.cpp b/source/fuzz/fuzzer_util.cpp
index 51dd42a..639c2fa 100644
--- a/source/fuzz/fuzzer_util.cpp
+++ b/source/fuzz/fuzzer_util.cpp
@@ -248,7 +248,9 @@
   return opcode == SpvOpPhi || instruction_in_block->opcode() != SpvOpPhi;
 }
 
-bool CanMakeSynonymOf(opt::IRContext* ir_context, opt::Instruction* inst) {
+bool CanMakeSynonymOf(opt::IRContext* ir_context,
+                      const TransformationContext& transformation_context,
+                      opt::Instruction* inst) {
   if (inst->opcode() == SpvOpSampledImage) {
     // The SPIR-V data rules say that only very specific instructions may
     // may consume the result id of an OpSampledImage, and this excludes the
@@ -259,6 +261,11 @@
     // We can only make a synonym of an instruction that generates an id.
     return false;
   }
+  if (transformation_context.GetFactManager()->IdIsIrrelevant(
+          inst->result_id())) {
+    // An irrelevant id can't be a synonym of anything.
+    return false;
+  }
   if (!inst->type_id()) {
     // We can only make a synonym of an instruction that has a type.
     return false;
diff --git a/source/fuzz/fuzzer_util.h b/source/fuzz/fuzzer_util.h
index ee4d569..42ef5cc 100644
--- a/source/fuzz/fuzzer_util.h
+++ b/source/fuzz/fuzzer_util.h
@@ -93,7 +93,11 @@
     SpvOp opcode, const opt::BasicBlock::iterator& instruction_in_block);
 
 // Determines whether it is OK to make a synonym of |inst|.
-bool CanMakeSynonymOf(opt::IRContext* ir_context, opt::Instruction* inst);
+// |transformation_context| is used to verify that the result id of |inst|
+// does not participate in IdIsIrrelevant fact.
+bool CanMakeSynonymOf(opt::IRContext* ir_context,
+                      const TransformationContext& transformation_context,
+                      opt::Instruction* inst);
 
 // Determines whether the given type is a composite; that is: an array, matrix,
 // struct or vector.
diff --git a/source/fuzz/transformation_add_synonym.cpp b/source/fuzz/transformation_add_synonym.cpp
index e572c0d..90e4054 100644
--- a/source/fuzz/transformation_add_synonym.cpp
+++ b/source/fuzz/transformation_add_synonym.cpp
@@ -56,7 +56,8 @@
   }
 
   // Check that we can apply |synonym_type| to |result_id|.
-  if (!IsInstructionValid(ir_context, synonym, message_.synonym_type())) {
+  if (!IsInstructionValid(ir_context, transformation_context, synonym,
+                          message_.synonym_type())) {
     return false;
   }
 
@@ -124,7 +125,8 @@
 }
 
 bool TransformationAddSynonym::IsInstructionValid(
-    opt::IRContext* ir_context, opt::Instruction* inst,
+    opt::IRContext* ir_context,
+    const TransformationContext& transformation_context, opt::Instruction* inst,
     protobufs::TransformationAddSynonym::SynonymType synonym_type) {
   // Instruction must have a result id, type id. We skip OpUndef and
   // OpConstantNull.
@@ -133,8 +135,10 @@
     return false;
   }
 
-  // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3177):
-  //  We can't create a synonym of an irrelevant id.
+  if (!fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context, inst)) {
+    return false;
+  }
+
   switch (synonym_type) {
     case protobufs::TransformationAddSynonym::ADD_ZERO:
     case protobufs::TransformationAddSynonym::SUB_ZERO:
@@ -151,7 +155,9 @@
       return type->AsInteger() || type->AsFloat();
     }
     case protobufs::TransformationAddSynonym::COPY_OBJECT:
-      return fuzzerutil::CanMakeSynonymOf(ir_context, inst);
+      // All checks for OpCopyObject are handled by
+      // fuzzerutil::CanMakeSynonymOf.
+      return true;
     case protobufs::TransformationAddSynonym::LOGICAL_AND:
     case protobufs::TransformationAddSynonym::LOGICAL_OR: {
       // The instruction must be either a scalar or a vector of booleans.
diff --git a/source/fuzz/transformation_add_synonym.h b/source/fuzz/transformation_add_synonym.h
index a9ad218..7705415 100644
--- a/source/fuzz/transformation_add_synonym.h
+++ b/source/fuzz/transformation_add_synonym.h
@@ -35,6 +35,7 @@
       const protobufs::InstructionDescriptor& insert_before);
 
   // - |result_id| must be a valid result id of some instruction in the module.
+  // - |result_id| may not be an irrelevant id.
   // - |synonym_type| is a type of the synonymous instruction that will be
   //   created.
   // - |synonym_fresh_id| is a fresh id.
@@ -57,7 +58,9 @@
   // Returns true if we can create a synonym of |inst| according to the
   // |synonym_type|.
   static bool IsInstructionValid(
-      opt::IRContext* ir_context, opt::Instruction* inst,
+      opt::IRContext* ir_context,
+      const TransformationContext& transformation_context,
+      opt::Instruction* inst,
       protobufs::TransformationAddSynonym::SynonymType synonym_type);
 
   // Returns true if |synonym_type| requires an additional constant instruction
diff --git a/source/fuzz/transformation_composite_construct.cpp b/source/fuzz/transformation_composite_construct.cpp
index cd4f22f..9cef7ff 100644
--- a/source/fuzz/transformation_composite_construct.cpp
+++ b/source/fuzz/transformation_composite_construct.cpp
@@ -40,7 +40,8 @@
 }
 
 bool TransformationCompositeConstruct::IsApplicable(
-    opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
+    opt::IRContext* ir_context,
+    const TransformationContext& transformation_context) const {
   if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
     // We require the id for the composite constructor to be unused.
     return false;
@@ -87,7 +88,20 @@
 
   // Now check whether every component being used to initialize the composite is
   // available at the desired program point.
-  for (auto& component : message_.component()) {
+  for (auto component : message_.component()) {
+    auto* inst = ir_context->get_def_use_mgr()->GetDef(component);
+    if (!inst) {
+      return false;
+    }
+
+    // We should be able to create a synonym of |component| if it's not
+    // irrelevant.
+    if (!transformation_context.GetFactManager()->IdIsIrrelevant(component) &&
+        !fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context,
+                                      inst)) {
+      return false;
+    }
+
     if (!fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, insert_before,
                                                     component)) {
       return false;
@@ -130,6 +144,11 @@
       ir_context->get_type_mgr()->GetType(message_.composite_type_id());
   uint32_t index = 0;
   for (auto component : message_.component()) {
+    if (transformation_context->GetFactManager()->IdIsIrrelevant(component)) {
+      // Irrelevant ids do not participate in DataSynonym facts.
+      continue;
+    }
+
     auto component_type = ir_context->get_type_mgr()->GetType(
         ir_context->get_def_use_mgr()->GetDef(component)->type_id());
     if (composite_type->AsVector() && component_type->AsVector()) {
diff --git a/source/fuzz/transformation_composite_extract.cpp b/source/fuzz/transformation_composite_extract.cpp
index 3dc3953..9f4d554 100644
--- a/source/fuzz/transformation_composite_extract.cpp
+++ b/source/fuzz/transformation_composite_extract.cpp
@@ -40,7 +40,8 @@
 }
 
 bool TransformationCompositeExtract::IsApplicable(
-    opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
+    opt::IRContext* ir_context,
+    const TransformationContext& transformation_context) const {
   if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
     return false;
   }
@@ -54,6 +55,14 @@
   if (!composite_instruction) {
     return false;
   }
+  if (!transformation_context.GetFactManager()->IdIsIrrelevant(
+          message_.composite_id()) &&
+      !fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context,
+                                    composite_instruction)) {
+    // |composite_id| will participate in DataSynonym facts. Thus, it can't be
+    // an irrelevant id.
+    return false;
+  }
   if (auto block = ir_context->get_instr_block(composite_instruction)) {
     if (composite_instruction == instruction_to_insert_before ||
         !ir_context->GetDominatorAnalysis(block->GetParent())
@@ -105,17 +114,20 @@
 
   // Add the fact that the id storing the extracted element is synonymous with
   // the index into the structure.
-  std::vector<uint32_t> indices;
-  for (auto an_index : message_.index()) {
-    indices.push_back(an_index);
+  if (!transformation_context->GetFactManager()->IdIsIrrelevant(
+          message_.composite_id())) {
+    std::vector<uint32_t> indices;
+    for (auto an_index : message_.index()) {
+      indices.push_back(an_index);
+    }
+    protobufs::DataDescriptor data_descriptor_for_extracted_element =
+        MakeDataDescriptor(message_.composite_id(), std::move(indices));
+    protobufs::DataDescriptor data_descriptor_for_result_id =
+        MakeDataDescriptor(message_.fresh_id(), {});
+    transformation_context->GetFactManager()->AddFactDataSynonym(
+        data_descriptor_for_extracted_element, data_descriptor_for_result_id,
+        ir_context);
   }
-  protobufs::DataDescriptor data_descriptor_for_extracted_element =
-      MakeDataDescriptor(message_.composite_id(), std::move(indices));
-  protobufs::DataDescriptor data_descriptor_for_result_id =
-      MakeDataDescriptor(message_.fresh_id(), {});
-  transformation_context->GetFactManager()->AddFactDataSynonym(
-      data_descriptor_for_extracted_element, data_descriptor_for_result_id,
-      ir_context);
 }
 
 protobufs::Transformation TransformationCompositeExtract::ToMessage() const {
diff --git a/source/fuzz/transformation_composite_extract.h b/source/fuzz/transformation_composite_extract.h
index 8f52d22..34df823 100644
--- a/source/fuzz/transformation_composite_extract.h
+++ b/source/fuzz/transformation_composite_extract.h
@@ -48,7 +48,8 @@
   // Adds an OpCompositeConstruct instruction before the instruction identified
   // by |message_.instruction_to_insert_before|, that extracts from
   // |message_.composite_id| via indices |message_.index| into
-  // |message_.fresh_id|.  Generates a data synonym fact relating
+  // |message_.fresh_id|. If |composite_id| is not an irrelevant id,
+  // generates a data synonym fact relating
   // |message_.fresh_id| to the extracted element.
   void Apply(opt::IRContext* ir_context,
              TransformationContext* transformation_context) const override;
diff --git a/source/fuzz/transformation_equation_instruction.cpp b/source/fuzz/transformation_equation_instruction.cpp
index 5f2c7f7..e27cd29 100644
--- a/source/fuzz/transformation_equation_instruction.cpp
+++ b/source/fuzz/transformation_equation_instruction.cpp
@@ -37,7 +37,8 @@
 }
 
 bool TransformationEquationInstruction::IsApplicable(
-    opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
+    opt::IRContext* ir_context,
+    const TransformationContext& transformation_context) const {
   // The result id must be fresh.
   if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
     return false;
@@ -59,6 +60,9 @@
     if (inst->opcode() == SpvOpUndef) {
       return false;
     }
+    if (transformation_context.GetFactManager()->IdIsIrrelevant(id)) {
+      return false;
+    }
     if (!fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, insert_before,
                                                     id)) {
       return false;
diff --git a/source/fuzz/transformation_push_id_through_variable.cpp b/source/fuzz/transformation_push_id_through_variable.cpp
index a0bf797..131473c 100644
--- a/source/fuzz/transformation_push_id_through_variable.cpp
+++ b/source/fuzz/transformation_push_id_through_variable.cpp
@@ -38,7 +38,8 @@
 }
 
 bool TransformationPushIdThroughVariable::IsApplicable(
-    opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
+    opt::IRContext* ir_context,
+    const TransformationContext& transformation_context) const {
   // |message_.value_synonym_id| and |message_.variable_id| must be fresh.
   if (!fuzzerutil::IsFreshId(ir_context, message_.value_synonym_id()) ||
       !fuzzerutil::IsFreshId(ir_context, message_.variable_id())) {
@@ -73,6 +74,12 @@
     return false;
   }
 
+  // |value_id| may not be an irrelevant id.
+  if (transformation_context.GetFactManager()->IdIsIrrelevant(
+          message_.value_id())) {
+    return false;
+  }
+
   // A pointer type instruction pointing to the value type must be defined.
   auto pointer_type_id = fuzzerutil::MaybeGetPointerType(
       ir_context, value_instruction->type_id(),
diff --git a/source/fuzz/transformation_push_id_through_variable.h b/source/fuzz/transformation_push_id_through_variable.h
index 24d3c2b..81e5892 100644
--- a/source/fuzz/transformation_push_id_through_variable.h
+++ b/source/fuzz/transformation_push_id_through_variable.h
@@ -36,6 +36,7 @@
 
   // - |message_.value_id| must be an instruction result id that has the same
   //   type as the pointee type of |message_.pointer_id|
+  // - |value_id| may not be an irrelevant id.
   // - |message_.value_synonym_id| must be fresh
   // - |message_.variable_id| must be fresh
   // - |message_.variable_storage_class| must be either StorageClassPrivate or
diff --git a/source/fuzz/transformation_record_synonymous_constants.cpp b/source/fuzz/transformation_record_synonymous_constants.cpp
index ccb8ee6..b1568bf 100644
--- a/source/fuzz/transformation_record_synonymous_constants.cpp
+++ b/source/fuzz/transformation_record_synonymous_constants.cpp
@@ -32,12 +32,19 @@
 
 bool TransformationRecordSynonymousConstants::IsApplicable(
     opt::IRContext* ir_context,
-    const TransformationContext& /* unused */) const {
+    const TransformationContext& transformation_context) const {
   // The ids must be different
   if (message_.constant1_id() == message_.constant2_id()) {
     return false;
   }
 
+  if (transformation_context.GetFactManager()->IdIsIrrelevant(
+          message_.constant1_id()) ||
+      transformation_context.GetFactManager()->IdIsIrrelevant(
+          message_.constant2_id())) {
+    return false;
+  }
+
   return AreEquivalentConstants(ir_context, message_.constant1_id(),
                                 message_.constant2_id());
 }
@@ -45,17 +52,10 @@
 void TransformationRecordSynonymousConstants::Apply(
     opt::IRContext* ir_context,
     TransformationContext* transformation_context) const {
-  protobufs::FactDataSynonym fact_data_synonym;
-  // Define the two equivalent data descriptors (just containing the ids)
-  *fact_data_synonym.mutable_data1() =
-      MakeDataDescriptor(message_.constant1_id(), {});
-  *fact_data_synonym.mutable_data2() =
-      MakeDataDescriptor(message_.constant2_id(), {});
-  protobufs::Fact fact;
-  *fact.mutable_data_synonym_fact() = fact_data_synonym;
-
   // Add the fact to the fact manager
-  transformation_context->GetFactManager()->AddFact(fact, ir_context);
+  transformation_context->GetFactManager()->AddFactDataSynonym(
+      MakeDataDescriptor(message_.constant1_id(), {}),
+      MakeDataDescriptor(message_.constant2_id(), {}), ir_context);
 }
 
 protobufs::Transformation TransformationRecordSynonymousConstants::ToMessage()
@@ -67,11 +67,14 @@
 
 bool TransformationRecordSynonymousConstants::AreEquivalentConstants(
     opt::IRContext* ir_context, uint32_t constant_id1, uint32_t constant_id2) {
-  opt::Instruction* def_1 = ir_context->get_def_use_mgr()->GetDef(constant_id1);
-  opt::Instruction* def_2 = ir_context->get_def_use_mgr()->GetDef(constant_id2);
+  const auto* def_1 = ir_context->get_def_use_mgr()->GetDef(constant_id1);
+  const auto* def_2 = ir_context->get_def_use_mgr()->GetDef(constant_id2);
 
   // Check that the definitions exist
-  assert(def_1 && def_2 && "The constant ids must exist in the module.");
+  if (!def_1 || !def_2) {
+    // We don't use an assertion since otherwise the shrinker fails.
+    return false;
+  }
 
   // The type ids must be the same
   // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3536): Somehow
diff --git a/source/fuzz/transformation_record_synonymous_constants.h b/source/fuzz/transformation_record_synonymous_constants.h
index 3f4d29a..b28eeb3 100644
--- a/source/fuzz/transformation_record_synonymous_constants.h
+++ b/source/fuzz/transformation_record_synonymous_constants.h
@@ -41,6 +41,7 @@
   //   - if both of them represent zero-like values of the same type
   //   - if they are composite constants with the same type and their
   //     components are pairwise equivalent.
+  // - |constant1_id| and |constant2_id| may not be irrelevant.
   bool IsApplicable(
       opt::IRContext* ir_context,
       const TransformationContext& transformation_context) const override;
diff --git a/source/fuzz/transformation_vector_shuffle.cpp b/source/fuzz/transformation_vector_shuffle.cpp
index ee64292..b3bd593 100644
--- a/source/fuzz/transformation_vector_shuffle.cpp
+++ b/source/fuzz/transformation_vector_shuffle.cpp
@@ -39,7 +39,8 @@
 }
 
 bool TransformationVectorShuffle::IsApplicable(
-    opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
+    opt::IRContext* ir_context,
+    const TransformationContext& transformation_context) const {
   // The fresh id must not already be in use.
   if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
     return false;
@@ -56,12 +57,26 @@
   if (!vector1_instruction || !vector1_instruction->type_id()) {
     return false;
   }
+  // We should be able to create a synonym of |vector1| if it's not irrelevant.
+  if (!transformation_context.GetFactManager()->IdIsIrrelevant(
+          message_.vector1()) &&
+      !fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context,
+                                    vector1_instruction)) {
+    return false;
+  }
   // The second vector must be an instruction with a type id
   auto vector2_instruction =
       ir_context->get_def_use_mgr()->GetDef(message_.vector2());
   if (!vector2_instruction || !vector2_instruction->type_id()) {
     return false;
   }
+  // We should be able to create a synonym of |vector2| if it's not irrelevant.
+  if (!transformation_context.GetFactManager()->IdIsIrrelevant(
+          message_.vector2()) &&
+      !fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context,
+                                    vector2_instruction)) {
+    return false;
+  }
   auto vector1_type =
       ir_context->get_type_mgr()->GetType(vector1_instruction->type_id());
   // The first vector instruction's type must actually be a vector type.
@@ -161,9 +176,21 @@
     // |component| refers.
     if (component <
         GetVectorType(ir_context, message_.vector1())->element_count()) {
+      // Irrelevant id cannot participate in DataSynonym facts.
+      if (transformation_context->GetFactManager()->IdIsIrrelevant(
+              message_.vector1())) {
+        continue;
+      }
+
       descriptor_for_source_component =
           MakeDataDescriptor(message_.vector1(), {component});
     } else {
+      // Irrelevant id cannot participate in DataSynonym facts.
+      if (transformation_context->GetFactManager()->IdIsIrrelevant(
+              message_.vector2())) {
+        continue;
+      }
+
       auto index_into_vector_2 =
           component -
           GetVectorType(ir_context, message_.vector1())->element_count();
diff --git a/source/fuzz/transformation_vector_shuffle.h b/source/fuzz/transformation_vector_shuffle.h
index f73fc31..f911976 100644
--- a/source/fuzz/transformation_vector_shuffle.h
+++ b/source/fuzz/transformation_vector_shuffle.h
@@ -19,7 +19,6 @@
 #include "source/fuzz/transformation.h"
 #include "source/fuzz/transformation_context.h"
 #include "source/opt/ir_context.h"
-
 #include "source/opt/types.h"
 
 namespace spvtools {
@@ -59,7 +58,9 @@
   // from which it came (with undefined components being ignored).  If the
   // result vector is a contiguous sub-range of one of the input vectors, a
   // fact is added to record that |message_.fresh_id| is synonymous with this
-  // sub-range.
+  // sub-range. DataSynonym facts are added only for non-irrelevant vectors
+  // (e.g. if |vector1| is irrelevant but |vector2| is not, synonyms will be
+  // created for |vector1| but not |vector2|).
   void Apply(opt::IRContext* ir_context,
              TransformationContext* transformation_context) const override;