spirv-fuzz: Do not add synonyms involving irrelevant ids (#3890)

Fixes #3886.
diff --git a/source/fuzz/transformation_add_bit_instruction_synonym.cpp b/source/fuzz/transformation_add_bit_instruction_synonym.cpp
index cf0de40..9fdc37e 100644
--- a/source/fuzz/transformation_add_bit_instruction_synonym.cpp
+++ b/source/fuzz/transformation_add_bit_instruction_synonym.cpp
@@ -94,6 +94,9 @@
   auto bit_instruction =
       ir_context->get_def_use_mgr()->GetDef(message_.instruction_result_id());
 
+  // Use an appropriate helper function to add the new instruction and new
+  // synonym fact.  The helper function should take care of invalidating
+  // analyses before adding facts.
   switch (bit_instruction->opcode()) {
     case SpvOpBitwiseOr:
     case SpvOpBitwiseXor:
@@ -106,8 +109,6 @@
       assert(false && "Should be unreachable.");
       break;
   }
-
-  ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
 }
 
 protobufs::Transformation TransformationAddBitInstructionSynonym::ToMessage()
@@ -223,11 +224,19 @@
 
   ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
 
-  // Adds the fact that the last |bit_insert| instruction is synonymous of
-  // |bit_instruction|.
-  transformation_context->GetFactManager()->AddFactDataSynonym(
-      MakeDataDescriptor(bit_insert.result_id(), {}),
-      MakeDataDescriptor(bit_instruction->result_id(), {}));
+  // We only add a synonym fact if the bit instruction is not irrelevant, and if
+  // the new result id we would make it synonymous with is not irrelevant.  (It
+  // could be irrelevant if we are in a dead block.)
+  if (!transformation_context->GetFactManager()->IdIsIrrelevant(
+          bit_instruction->result_id()) &&
+      !transformation_context->GetFactManager()->IdIsIrrelevant(
+          bit_insert.result_id())) {
+    // Adds the fact that the last |bit_insert| instruction is synonymous of
+    // |bit_instruction|.
+    transformation_context->GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(bit_insert.result_id(), {}),
+        MakeDataDescriptor(bit_instruction->result_id(), {}));
+  }
 }
 
 std::unordered_set<uint32_t>
diff --git a/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.cpp b/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.cpp
index 93705f2..5252d19 100644
--- a/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.cpp
+++ b/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.cpp
@@ -53,8 +53,8 @@
     opt::IRContext* ir_context,
     const TransformationContext& transformation_context) const {
   // Check that |message_.constant_id|, |message_.initial_val_id| and
-  // |message_.step_val_id| are existing constants.
-
+  // |message_.step_val_id| are existing constants, and that their values are
+  // not irrelevant.
   auto constant = ir_context->get_constant_mgr()->FindDeclaredConstant(
       message_.constant_id());
   auto initial_val = ir_context->get_constant_mgr()->FindDeclaredConstant(
@@ -65,6 +65,14 @@
   if (!constant || !initial_val || !step_val) {
     return false;
   }
+  if (transformation_context.GetFactManager()->IdIsIrrelevant(
+          message_.constant_id()) ||
+      transformation_context.GetFactManager()->IdIsIrrelevant(
+          message_.initial_val_id()) ||
+      transformation_context.GetFactManager()->IdIsIrrelevant(
+          message_.step_val_id())) {
+    return false;
+  }
 
   // Check that the type of |constant| is integer scalar or vector with integer
   // components.
@@ -101,12 +109,15 @@
     return false;
   }
 
-  // |message_.num_iterations_id| is an integer constant with bit width 32.
+  // |message_.num_iterations_id| must be a non-irrelevant integer constant with
+  // bit width 32.
   auto num_iterations = ir_context->get_constant_mgr()->FindDeclaredConstant(
       message_.num_iterations_id());
 
   if (!num_iterations || !num_iterations->AsIntConstant() ||
-      num_iterations->type()->AsInteger()->width() != 32) {
+      num_iterations->type()->AsInteger()->width() != 32 ||
+      transformation_context.GetFactManager()->IdIsIrrelevant(
+          message_.num_iterations_id())) {
     return false;
   }
 
@@ -181,6 +192,13 @@
     return false;
   }
 
+  // Check that the block is not dead.  If it is then the new loop would be
+  // dead and the data it computes would be irrelevant, so we would not be able
+  // to make a synonym.
+  if (transformation_context.GetFactManager()->BlockIsDead(block->id())) {
+    return false;
+  }
+
   // Check that the block is not a merge block.
   if (ir_context->GetStructuredCFGAnalysis()->IsMergeBlock(block->id())) {
     return false;
diff --git a/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.h b/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.h
index f041f55..67c3bcd 100644
--- a/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.h
+++ b/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.h
@@ -45,6 +45,7 @@
   // - |message_.block_after_loop_id| is the label of a block which has a single
   //   predecessor and which is not a merge block, a continue block or a loop
   //   header.
+  // - |message_.block_after_loop_id| must not be a dead block.
   // - |message_.additional_block_id| is either 0 or a valid fresh id, distinct
   //   from the other fresh ids.
   // - All of the other parameters are valid fresh ids.
diff --git a/source/fuzz/transformation_add_opphi_synonym.cpp b/source/fuzz/transformation_add_opphi_synonym.cpp
index a2ddfc4..227c433 100644
--- a/source/fuzz/transformation_add_opphi_synonym.cpp
+++ b/source/fuzz/transformation_add_opphi_synonym.cpp
@@ -34,9 +34,11 @@
 bool TransformationAddOpPhiSynonym::IsApplicable(
     opt::IRContext* ir_context,
     const TransformationContext& transformation_context) const {
-  // Check that |message_.block_id| is a block label id.
+  // Check that |message_.block_id| is a block label id, and that it is not
+  // dead.
   auto block = fuzzerutil::MaybeFindBlock(ir_context, message_.block_id());
-  if (!block) {
+  if (!block ||
+      transformation_context.GetFactManager()->BlockIsDead(block->id())) {
     return false;
   }
 
diff --git a/source/fuzz/transformation_add_opphi_synonym.h b/source/fuzz/transformation_add_opphi_synonym.h
index 56b5652..3b68abe 100644
--- a/source/fuzz/transformation_add_opphi_synonym.h
+++ b/source/fuzz/transformation_add_opphi_synonym.h
@@ -30,6 +30,7 @@
 
   // - |message_.block_id| is the label of a block with at least one
   //   predecessor.
+  // - |message_.block_id| must not be a dead block.
   // - |message_.pred_to_id| contains a mapping from each of the predecessors of
   //   the block to an id that is available at the end of the predecessor.
   // - All the ids corresponding to a predecessor in |message_.pred_to_id|:
diff --git a/source/fuzz/transformation_composite_construct.cpp b/source/fuzz/transformation_composite_construct.cpp
index bcf2c7d..e3376cb 100644
--- a/source/fuzz/transformation_composite_construct.cpp
+++ b/source/fuzz/transformation_composite_construct.cpp
@@ -40,8 +40,7 @@
 }
 
 bool TransformationCompositeConstruct::IsApplicable(
-    opt::IRContext* ir_context,
-    const TransformationContext& transformation_context) const {
+    opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
   if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
     // We require the id for the composite constructor to be unused.
     return false;
@@ -94,14 +93,6 @@
       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;
@@ -136,48 +127,7 @@
   fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
   ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
 
-  // Inform the fact manager that we now have new synonyms: every component of
-  // the composite is synonymous with the id used to construct that component,
-  // except in the case of a vector where a single vector id can span multiple
-  // components.
-  auto composite_type =
-      ir_context->get_type_mgr()->GetType(message_.composite_type_id());
-  uint32_t index = 0;
-  for (auto component : message_.component()) {
-    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()) {
-      // The case where the composite being constructed is a vector and the
-      // component provided for construction is also a vector is special.  It
-      // requires adding a synonym fact relating each element of the sub-vector
-      // to the corresponding element of the composite being constructed.
-      assert(component_type->AsVector()->element_type() ==
-             composite_type->AsVector()->element_type());
-      assert(component_type->AsVector()->element_count() <
-             composite_type->AsVector()->element_count());
-      for (uint32_t subvector_index = 0;
-           subvector_index < component_type->AsVector()->element_count();
-           subvector_index++) {
-        if (!transformation_context->GetFactManager()->IdIsIrrelevant(
-                component)) {
-          transformation_context->GetFactManager()->AddFactDataSynonym(
-              MakeDataDescriptor(component, {subvector_index}),
-              MakeDataDescriptor(message_.fresh_id(), {index}));
-        }
-        index++;
-      }
-    } else {
-      // The other cases are simple: the component is made directly synonymous
-      // with the element of the composite being constructed.
-      if (!transformation_context->GetFactManager()->IdIsIrrelevant(
-              component)) {
-        transformation_context->GetFactManager()->AddFactDataSynonym(
-            MakeDataDescriptor(component, {}),
-            MakeDataDescriptor(message_.fresh_id(), {index}));
-      }
-      index++;
-    }
-  }
+  AddDataSynonymFacts(ir_context, transformation_context);
 }
 
 bool TransformationCompositeConstruct::ComponentsForArrayConstructionAreOK(
@@ -315,5 +265,58 @@
   return {message_.fresh_id()};
 }
 
+void TransformationCompositeConstruct::AddDataSynonymFacts(
+    opt::IRContext* ir_context,
+    TransformationContext* transformation_context) const {
+  // If the result id of the composite we are constructing is irrelevant (e.g.
+  // because it is in a dead block) then we do not make any synonyms.
+  if (transformation_context->GetFactManager()->IdIsIrrelevant(
+          message_.fresh_id())) {
+    return;
+  }
+
+  // Inform the fact manager that we now have new synonyms: every component of
+  // the composite is synonymous with the id used to construct that component
+  // (so long as it is legitimate to create a synonym from that id), except in
+  // the case of a vector where a single vector id can span multiple components.
+  auto composite_type =
+      ir_context->get_type_mgr()->GetType(message_.composite_type_id());
+  uint32_t index = 0;
+  for (auto component : message_.component()) {
+    if (!fuzzerutil::CanMakeSynonymOf(
+            ir_context, *transformation_context,
+            ir_context->get_def_use_mgr()->GetDef(component))) {
+      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()) {
+      // The case where the composite being constructed is a vector and the
+      // component provided for construction is also a vector is special.  It
+      // requires adding a synonym fact relating each element of the sub-vector
+      // to the corresponding element of the composite being constructed.
+      assert(component_type->AsVector()->element_type() ==
+             composite_type->AsVector()->element_type());
+      assert(component_type->AsVector()->element_count() <
+             composite_type->AsVector()->element_count());
+      for (uint32_t subvector_index = 0;
+           subvector_index < component_type->AsVector()->element_count();
+           subvector_index++) {
+        transformation_context->GetFactManager()->AddFactDataSynonym(
+            MakeDataDescriptor(component, {subvector_index}),
+            MakeDataDescriptor(message_.fresh_id(), {index}));
+        index++;
+      }
+    } else {
+      // The other cases are simple: the component is made directly synonymous
+      // with the element of the composite being constructed.
+      transformation_context->GetFactManager()->AddFactDataSynonym(
+          MakeDataDescriptor(component, {}),
+          MakeDataDescriptor(message_.fresh_id(), {index}));
+      index++;
+    }
+  }
+}
+
 }  // namespace fuzz
 }  // namespace spvtools
diff --git a/source/fuzz/transformation_composite_construct.h b/source/fuzz/transformation_composite_construct.h
index 848634c..3a3e43c 100644
--- a/source/fuzz/transformation_composite_construct.h
+++ b/source/fuzz/transformation_composite_construct.h
@@ -58,6 +58,10 @@
   // |message_.base_instruction_id| and |message_.offset|.  The instruction
   // creates a composite of type |message_.composite_type_id| using the ids of
   // |message_.component|.
+  //
+  // Synonym facts are added between the elements of the resulting composite
+  // and the components used to construct it, as long as the associated ids
+  // support synonym creation.
   void Apply(opt::IRContext* ir_context,
              TransformationContext* transformation_context) const override;
 
@@ -86,6 +90,11 @@
       opt::IRContext* ir_context,
       const opt::analysis::Vector& vector_type) const;
 
+  // Helper method for adding data synonym facts when applying the
+  // transformation to |ir_context| and |transformation_context|.
+  void AddDataSynonymFacts(opt::IRContext* ir_context,
+                           TransformationContext* transformation_context) const;
+
   protobufs::TransformationCompositeConstruct message_;
 };
 
diff --git a/source/fuzz/transformation_composite_extract.cpp b/source/fuzz/transformation_composite_extract.cpp
index bc8797d..291331c 100644
--- a/source/fuzz/transformation_composite_extract.cpp
+++ b/source/fuzz/transformation_composite_extract.cpp
@@ -41,8 +41,7 @@
 }
 
 bool TransformationCompositeExtract::IsApplicable(
-    opt::IRContext* ir_context,
-    const TransformationContext& transformation_context) const {
+    opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
   if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
     return false;
   }
@@ -56,14 +55,6 @@
   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())
@@ -113,6 +104,33 @@
   ir_context->InvalidateAnalysesExceptFor(
       opt::IRContext::Analysis::kAnalysisNone);
 
+  AddDataSynonymFacts(ir_context, transformation_context);
+}
+
+protobufs::Transformation TransformationCompositeExtract::ToMessage() const {
+  protobufs::Transformation result;
+  *result.mutable_composite_extract() = message_;
+  return result;
+}
+
+std::unordered_set<uint32_t> TransformationCompositeExtract::GetFreshIds()
+    const {
+  return {message_.fresh_id()};
+}
+
+void TransformationCompositeExtract::AddDataSynonymFacts(
+    opt::IRContext* ir_context,
+    TransformationContext* transformation_context) const {
+  // Don't add synonyms if the composite being extracted from is not suitable,
+  // or if the result id into which we are extracting is irrelevant.
+  if (!fuzzerutil::CanMakeSynonymOf(
+          ir_context, *transformation_context,
+          ir_context->get_def_use_mgr()->GetDef(message_.composite_id())) ||
+      transformation_context->GetFactManager()->IdIsIrrelevant(
+          message_.fresh_id())) {
+    return;
+  }
+
   // Add the fact that the id storing the extracted element is synonymous with
   // the index into the structure.
   if (!transformation_context->GetFactManager()->IdIsIrrelevant(
@@ -130,16 +148,5 @@
   }
 }
 
-protobufs::Transformation TransformationCompositeExtract::ToMessage() const {
-  protobufs::Transformation result;
-  *result.mutable_composite_extract() = message_;
-  return result;
-}
-
-std::unordered_set<uint32_t> TransformationCompositeExtract::GetFreshIds()
-    const {
-  return {message_.fresh_id()};
-}
-
 }  // namespace fuzz
 }  // namespace spvtools
diff --git a/source/fuzz/transformation_composite_extract.h b/source/fuzz/transformation_composite_extract.h
index de59bed..0f5348a 100644
--- a/source/fuzz/transformation_composite_extract.h
+++ b/source/fuzz/transformation_composite_extract.h
@@ -49,9 +49,11 @@
   // 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|. If |composite_id| is not an irrelevant id,
-  // generates a data synonym fact relating
-  // |message_.fresh_id| to the extracted element.
+  // |message_.fresh_id|.
+  //
+  // Adds a synonym fact associating |message_.fresh_id| with the relevant
+  // element of |message_.composite_id|, as long as these ids support synonym
+  // creation.
   void Apply(opt::IRContext* ir_context,
              TransformationContext* transformation_context) const override;
 
@@ -60,6 +62,11 @@
   protobufs::Transformation ToMessage() const override;
 
  private:
+  // Helper method for adding data synonym facts when applying the
+  // transformation to |ir_context| and |transformation_context|.
+  void AddDataSynonymFacts(opt::IRContext* ir_context,
+                           TransformationContext* transformation_context) const;
+
   protobufs::TransformationCompositeExtract message_;
 };
 
diff --git a/source/fuzz/transformation_composite_insert.cpp b/source/fuzz/transformation_composite_insert.cpp
index e08a09f..cc68141 100644
--- a/source/fuzz/transformation_composite_insert.cpp
+++ b/source/fuzz/transformation_composite_insert.cpp
@@ -134,54 +134,8 @@
   // We have modified the module so most analyzes are now invalid.
   ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
 
-  // Add facts about synonyms. Every element which hasn't been changed in
-  // the copy is synonymous to the corresponding element in the original
-  // composite which has id |message_.composite_id|. For every index that is a
-  // prefix of |index|, the components different from the one that
-  // contains the inserted object are synonymous with corresponding
-  // elements in the original composite.
-
-  // If |composite_id| is irrelevant then don't add any synonyms.
-  if (transformation_context->GetFactManager()->IdIsIrrelevant(
-          message_.composite_id())) {
-    return;
-  }
-  uint32_t current_node_type_id = composite_type_id;
-  std::vector<uint32_t> current_index;
-
-  for (uint32_t current_level = 0; current_level < index.size();
-       current_level++) {
-    auto current_node_type_inst =
-        ir_context->get_def_use_mgr()->GetDef(current_node_type_id);
-    uint32_t index_to_skip = index[current_level];
-    uint32_t num_of_components = fuzzerutil::GetBoundForCompositeIndex(
-        *current_node_type_inst, ir_context);
-
-    // Update the current_node_type_id.
-    current_node_type_id = fuzzerutil::WalkOneCompositeTypeIndex(
-        ir_context, current_node_type_id, index_to_skip);
-
-    for (uint32_t i = 0; i < num_of_components; i++) {
-      if (i == index_to_skip) {
-        continue;
-      }
-      current_index.push_back(i);
-      transformation_context->GetFactManager()->AddFactDataSynonym(
-          MakeDataDescriptor(message_.fresh_id(), current_index),
-          MakeDataDescriptor(message_.composite_id(), current_index));
-      current_index.pop_back();
-    }
-    // Store the prefix of the |index|.
-    current_index.push_back(index[current_level]);
-  }
-  // The element which has been changed is synonymous to the found object
-  // itself. Add this fact only if |object_id| is not irrelevant.
-  if (!transformation_context->GetFactManager()->IdIsIrrelevant(
-          message_.object_id())) {
-    transformation_context->GetFactManager()->AddFactDataSynonym(
-        MakeDataDescriptor(message_.object_id(), {}),
-        MakeDataDescriptor(message_.fresh_id(), index));
-  }
+  // Add data synonym facts that arise from the insertion.
+  AddDataSynonymFacts(ir_context, transformation_context);
 }
 
 protobufs::Transformation TransformationCompositeInsert::ToMessage() const {
@@ -219,5 +173,69 @@
   return {message_.fresh_id()};
 }
 
+void TransformationCompositeInsert::AddDataSynonymFacts(
+    opt::IRContext* ir_context,
+    TransformationContext* transformation_context) const {
+  // If the result id arising from the insertion is irrelevant then do not add
+  // any data synonym facts.  (The result id can be irrelevant if the insertion
+  // occurs in a dead block.)
+  if (transformation_context->GetFactManager()->IdIsIrrelevant(
+          message_.fresh_id())) {
+    return;
+  }
+
+  // So long as the |message_.composite_id| is suitable for participating in
+  // synonyms, every every element of the insertion result except for at the
+  // index being inserted into is synonymous with the corresponding element of
+  // |message_.composite_id|.  In that case, for every index that is a prefix of
+  // |index|, the components different from the one that contains the inserted
+  // object are synonymous with corresponding elements in the original
+  // composite.
+  uint32_t current_node_type_id =
+      fuzzerutil::GetTypeId(ir_context, message_.composite_id());
+  std::vector<uint32_t> current_index;
+
+  std::vector<uint32_t> index =
+      fuzzerutil::RepeatedFieldToVector(message_.index());
+
+  for (uint32_t current_level : index) {
+    auto current_node_type_inst =
+        ir_context->get_def_use_mgr()->GetDef(current_node_type_id);
+    uint32_t index_to_skip = current_level;
+    uint32_t num_of_components = fuzzerutil::GetBoundForCompositeIndex(
+        *current_node_type_inst, ir_context);
+
+    // Update the current_node_type_id.
+    current_node_type_id = fuzzerutil::WalkOneCompositeTypeIndex(
+        ir_context, current_node_type_id, index_to_skip);
+
+    for (uint32_t i = 0; i < num_of_components; i++) {
+      if (i == index_to_skip) {
+        continue;
+      }
+      current_index.push_back(i);
+      if (fuzzerutil::CanMakeSynonymOf(
+              ir_context, *transformation_context,
+              ir_context->get_def_use_mgr()->GetDef(message_.composite_id()))) {
+        transformation_context->GetFactManager()->AddFactDataSynonym(
+            MakeDataDescriptor(message_.fresh_id(), current_index),
+            MakeDataDescriptor(message_.composite_id(), current_index));
+      }
+      current_index.pop_back();
+    }
+    // Store the prefix of the |index|.
+    current_index.push_back(current_level);
+  }
+  // If the object being inserted supports synonym creation then it is
+  // synonymous with the result of the insert instruction at the given index.
+  if (fuzzerutil::CanMakeSynonymOf(
+          ir_context, *transformation_context,
+          ir_context->get_def_use_mgr()->GetDef(message_.object_id()))) {
+    transformation_context->GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(message_.object_id(), {}),
+        MakeDataDescriptor(message_.fresh_id(), index));
+  }
+}
+
 }  // namespace fuzz
 }  // namespace spvtools
diff --git a/source/fuzz/transformation_composite_insert.h b/source/fuzz/transformation_composite_insert.h
index 5647fff..f229014 100644
--- a/source/fuzz/transformation_composite_insert.h
+++ b/source/fuzz/transformation_composite_insert.h
@@ -65,6 +65,11 @@
                                               opt::Instruction* instruction);
 
  private:
+  // Helper method for adding data synonym facts when applying the
+  // transformation to |ir_context| and |transformation_context|.
+  void AddDataSynonymFacts(opt::IRContext* ir_context,
+                           TransformationContext* transformation_context) const;
+
   protobufs::TransformationCompositeInsert message_;
 };
 
diff --git a/source/fuzz/transformation_push_id_through_variable.cpp b/source/fuzz/transformation_push_id_through_variable.cpp
index accbce7..cdc40aa 100644
--- a/source/fuzz/transformation_push_id_through_variable.cpp
+++ b/source/fuzz/transformation_push_id_through_variable.cpp
@@ -38,8 +38,7 @@
 }
 
 bool TransformationPushIdThroughVariable::IsApplicable(
-    opt::IRContext* ir_context,
-    const TransformationContext& transformation_context) const {
+    opt::IRContext* ir_context, const TransformationContext& /*unused*/) 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())) {
@@ -74,14 +73,6 @@
     return false;
   }
 
-  // We should be able to create a synonym of |value_id| if it's not irrelevant.
-  if (!transformation_context.GetFactManager()->IdIsIrrelevant(
-          message_.value_id()) &&
-      !fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context,
-                                    value_instruction)) {
-    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(),
@@ -153,8 +144,11 @@
 
   ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
 
-  if (!transformation_context->GetFactManager()->IdIsIrrelevant(
-          message_.value_id())) {
+  // We should be able to create a synonym of |value_id| if it's not irrelevant.
+  if (fuzzerutil::CanMakeSynonymOf(ir_context, *transformation_context,
+                                   value_instruction) &&
+      !transformation_context->GetFactManager()->IdIsIrrelevant(
+          message_.value_synonym_id())) {
     // Adds the fact that |message_.value_synonym_id|
     // and |message_.value_id| are synonymous.
     transformation_context->GetFactManager()->AddFactDataSynonym(
diff --git a/source/fuzz/transformation_push_id_through_variable.h b/source/fuzz/transformation_push_id_through_variable.h
index 11c56f7..d055825 100644
--- a/source/fuzz/transformation_push_id_through_variable.h
+++ b/source/fuzz/transformation_push_id_through_variable.h
@@ -52,7 +52,7 @@
 
   // Stores |value_id| to |variable_id|, loads |variable_id| to
   // |value_synonym_id|. Adds the fact that |value_synonym_id| and |value_id|
-  // are synonymous if |value_id| is not irrelevant.
+  // are synonymous if |value_id| and |value_synonym_id| are not irrelevant.
   void Apply(opt::IRContext* ir_context,
              TransformationContext* transformation_context) const override;
 
diff --git a/source/fuzz/transformation_replace_copy_object_with_store_load.cpp b/source/fuzz/transformation_replace_copy_object_with_store_load.cpp
index 5e80eec..54c99d5 100644
--- a/source/fuzz/transformation_replace_copy_object_with_store_load.cpp
+++ b/source/fuzz/transformation_replace_copy_object_with_store_load.cpp
@@ -89,7 +89,7 @@
          copy_object_instruction->opcode() == SpvOpCopyObject &&
          "The required OpCopyObject instruction must be defined.");
   // Get id used as a source by the OpCopyObject instruction.
-  uint32_t src_operand = copy_object_instruction->GetSingleWordOperand(2);
+  uint32_t src_operand = copy_object_instruction->GetSingleWordInOperand(0);
   // A pointer type instruction pointing to the value type must be defined.
   auto pointer_type_id = fuzzerutil::MaybeGetPointerType(
       ir_context, copy_object_instruction->type_id(),
@@ -129,11 +129,15 @@
 
   ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
 
-  // Adds the fact that |message_.copy_object_result_id|
-  // and src_operand (id used by OpCopyObject) are synonymous.
-  transformation_context->GetFactManager()->AddFactDataSynonym(
-      MakeDataDescriptor(message_.copy_object_result_id(), {}),
-      MakeDataDescriptor(src_operand, {}));
+  if (!transformation_context->GetFactManager()->IdIsIrrelevant(
+          message_.copy_object_result_id()) &&
+      !transformation_context->GetFactManager()->IdIsIrrelevant(src_operand)) {
+    // Adds the fact that |message_.copy_object_result_id|
+    // and src_operand (id used by OpCopyObject) are synonymous.
+    transformation_context->GetFactManager()->AddFactDataSynonym(
+        MakeDataDescriptor(message_.copy_object_result_id(), {}),
+        MakeDataDescriptor(src_operand, {}));
+  }
 }
 
 protobufs::Transformation
diff --git a/source/fuzz/transformation_vector_shuffle.cpp b/source/fuzz/transformation_vector_shuffle.cpp
index ae1a8f5..05af18e 100644
--- a/source/fuzz/transformation_vector_shuffle.cpp
+++ b/source/fuzz/transformation_vector_shuffle.cpp
@@ -39,8 +39,7 @@
 }
 
 bool TransformationVectorShuffle::IsApplicable(
-    opt::IRContext* ir_context,
-    const TransformationContext& transformation_context) const {
+    opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
   // The fresh id must not already be in use.
   if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
     return false;
@@ -57,26 +56,12 @@
   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.
@@ -153,67 +138,7 @@
   ir_context->InvalidateAnalysesExceptFor(
       opt::IRContext::Analysis::kAnalysisNone);
 
-  // If the new instruction is irrelevant (because it is in a dead block), it
-  // cannot participate in any DataSynonym fact.
-  if (transformation_context->GetFactManager()->IdIsIrrelevant(
-          message_.fresh_id())) {
-    return;
-  }
-
-  // Add synonym facts relating the defined elements of the shuffle result to
-  // the vector components that they come from.
-  for (uint32_t component_index = 0;
-       component_index < static_cast<uint32_t>(message_.component_size());
-       component_index++) {
-    uint32_t component = message_.component(component_index);
-    if (component == 0xFFFFFFFF) {
-      // This component is undefined, so move on - but first note that the
-      // overall shuffle result cannot be synonymous with any vector.
-      continue;
-    }
-
-    // This describes the element of the result vector associated with
-    // |component_index|.
-    protobufs::DataDescriptor descriptor_for_result_component =
-        MakeDataDescriptor(message_.fresh_id(), {component_index});
-
-    protobufs::DataDescriptor descriptor_for_source_component;
-
-    // Get a data descriptor for the component of the input vector to which
-    // |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();
-      assert(
-          index_into_vector_2 <
-              GetVectorType(ir_context, message_.vector2())->element_count() &&
-          "Vector shuffle index is out of bounds.");
-      descriptor_for_source_component =
-          MakeDataDescriptor(message_.vector2(), {index_into_vector_2});
-    }
-
-    // Add a fact relating this input vector component with the associated
-    // result component.
-    transformation_context->GetFactManager()->AddFactDataSynonym(
-        descriptor_for_result_component, descriptor_for_source_component);
-  }
+  AddDataSynonymFacts(ir_context, transformation_context);
 }
 
 protobufs::Transformation TransformationVectorShuffle::ToMessage() const {
@@ -240,5 +165,69 @@
   return {message_.fresh_id()};
 }
 
+void TransformationVectorShuffle::AddDataSynonymFacts(
+    opt::IRContext* ir_context,
+    TransformationContext* transformation_context) const {
+  // If the new instruction is irrelevant (because it is in a dead block), it
+  // cannot participate in any DataSynonym fact.
+  if (transformation_context->GetFactManager()->IdIsIrrelevant(
+          message_.fresh_id())) {
+    return;
+  }
+
+  // Add synonym facts relating the defined elements of the shuffle result to
+  // the vector components that they come from.
+  for (uint32_t component_index = 0;
+       component_index < static_cast<uint32_t>(message_.component_size());
+       component_index++) {
+    uint32_t component = message_.component(component_index);
+    if (component == 0xFFFFFFFF) {
+      // This component is undefined, we do not introduce a synonym.
+      continue;
+    }
+    // This describes the element of the result vector associated with
+    // |component_index|.
+    protobufs::DataDescriptor descriptor_for_result_component =
+        MakeDataDescriptor(message_.fresh_id(), {component_index});
+
+    protobufs::DataDescriptor descriptor_for_source_component;
+
+    // Get a data descriptor for the component of the input vector to which
+    // |component| refers.
+    if (component <
+        GetVectorType(ir_context, message_.vector1())->element_count()) {
+      // Check that the first vector can participate in data synonym facts.
+      if (!fuzzerutil::CanMakeSynonymOf(
+              ir_context, *transformation_context,
+              ir_context->get_def_use_mgr()->GetDef(message_.vector1()))) {
+        continue;
+      }
+      descriptor_for_source_component =
+          MakeDataDescriptor(message_.vector1(), {component});
+    } else {
+      // Check that the second vector can participate in data synonym facts.
+      if (!fuzzerutil::CanMakeSynonymOf(
+              ir_context, *transformation_context,
+              ir_context->get_def_use_mgr()->GetDef(message_.vector2()))) {
+        continue;
+      }
+      auto index_into_vector_2 =
+          component -
+          GetVectorType(ir_context, message_.vector1())->element_count();
+      assert(
+          index_into_vector_2 <
+              GetVectorType(ir_context, message_.vector2())->element_count() &&
+          "Vector shuffle index is out of bounds.");
+      descriptor_for_source_component =
+          MakeDataDescriptor(message_.vector2(), {index_into_vector_2});
+    }
+
+    // Add a fact relating this input vector component with the associated
+    // result component.
+    transformation_context->GetFactManager()->AddFactDataSynonym(
+        descriptor_for_result_component, descriptor_for_source_component);
+  }
+}
+
 }  // namespace fuzz
 }  // namespace spvtools
diff --git a/source/fuzz/transformation_vector_shuffle.h b/source/fuzz/transformation_vector_shuffle.h
index e20e617..cf08a62 100644
--- a/source/fuzz/transformation_vector_shuffle.h
+++ b/source/fuzz/transformation_vector_shuffle.h
@@ -52,15 +52,16 @@
   // Inserts an OpVectorShuffle instruction before
   // |message_.instruction_to_insert_before|, shuffles vectors
   // |message_.vector1| and |message_.vector2| using the indices provided by
-  // |message_.component|, into |message_.fresh_id|.  Adds a fact to the fact
-  // manager recording the fact each element of |message_.fresh_id| is
+  // |message_.component|, into |message_.fresh_id|.
+  //
+  // If |message_.fresh_id| is irrelevant (e.g. due to being in a dead block)
+  // of if one of |message_.vector1| or |message_.vector2| is irrelevant and the
+  // shuffle reads components from the irrelevant vector then no synonym facts
+  // are added.
+  //
+  // Otherwise, a fact is added recording that element of |message_.fresh_id| is
   // synonymous with the element of |message_.vector1| or |message_.vector2|
-  // 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. 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|).
+  // from which it came (with undefined components being ignored).
   void Apply(opt::IRContext* ir_context,
              TransformationContext* transformation_context) const override;
 
@@ -76,9 +77,15 @@
   uint32_t GetResultTypeId(opt::IRContext* ir_context,
                            const opt::analysis::Type& element_type) const;
 
+  // Returns the type associated with |id_of_vector| in |ir_context|.
   static opt::analysis::Vector* GetVectorType(opt::IRContext* ir_context,
                                               uint32_t id_of_vector);
 
+  // Helper method for adding data synonym facts when applying the
+  // transformation to |ir_context| and |transformation_context|.
+  void AddDataSynonymFacts(opt::IRContext* ir_context,
+                           TransformationContext* transformation_context) const;
+
   protobufs::TransformationVectorShuffle message_;
 };
 
diff --git a/test/fuzz/transformation_add_bit_instruction_synonym_test.cpp b/test/fuzz/transformation_add_bit_instruction_synonym_test.cpp
index 6b2df0d..132f020 100644
--- a/test/fuzz/transformation_add_bit_instruction_synonym_test.cpp
+++ b/test/fuzz/transformation_add_bit_instruction_synonym_test.cpp
@@ -721,6 +721,184 @@
   ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
 }
 
+TEST(TransformationAddBitInstructionSynonymTest, NoSynonymWhenIdIsIrrelevant) {
+  std::string reference_shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %37 "main"
+
+; Types
+          %2 = OpTypeInt 32 0
+          %3 = OpTypeVoid
+          %4 = OpTypeFunction %3
+
+; Constants
+          %5 = OpConstant %2 0
+          %6 = OpConstant %2 1
+          %7 = OpConstant %2 2
+          %8 = OpConstant %2 3
+          %9 = OpConstant %2 4
+         %10 = OpConstant %2 5
+         %11 = OpConstant %2 6
+         %12 = OpConstant %2 7
+         %13 = OpConstant %2 8
+         %14 = OpConstant %2 9
+         %15 = OpConstant %2 10
+         %16 = OpConstant %2 11
+         %17 = OpConstant %2 12
+         %18 = OpConstant %2 13
+         %19 = OpConstant %2 14
+         %20 = OpConstant %2 15
+         %21 = OpConstant %2 16
+         %22 = OpConstant %2 17
+         %23 = OpConstant %2 18
+         %24 = OpConstant %2 19
+         %25 = OpConstant %2 20
+         %26 = OpConstant %2 21
+         %27 = OpConstant %2 22
+         %28 = OpConstant %2 23
+         %29 = OpConstant %2 24
+         %30 = OpConstant %2 25
+         %31 = OpConstant %2 26
+         %32 = OpConstant %2 27
+         %33 = OpConstant %2 28
+         %34 = OpConstant %2 29
+         %35 = OpConstant %2 30
+         %36 = OpConstant %2 31
+
+; main function
+         %37 = OpFunction %3 None %4
+         %38 = OpLabel
+         %39 = OpBitwiseOr %2 %5 %6 ; bit instruction
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_5;
+  const auto consumer = nullptr;
+  const auto context =
+      BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
+  ASSERT_TRUE(IsValid(env, context.get()));
+
+  spvtools::ValidatorOptions validator_options;
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+  // Mark the result id of the bit instruction as irrelevant.
+  transformation_context.GetFactManager()->AddFactIdIsIrrelevant(39);
+
+  // Adds OpBitwiseOr synonym.
+  auto transformation = TransformationAddBitInstructionSynonym(
+      39, {40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,
+           53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,
+           66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,
+           79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,
+           92,  93,  94,  95,  96,  97,  98,  99,  100, 101, 102, 103, 104,
+           105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+           118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
+           131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+           144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156,
+           157, 158, 159, 160, 161, 162, 163, 164, 165, 166});
+  ASSERT_TRUE(
+      transformation.IsApplicable(context.get(), transformation_context));
+  ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
+  ASSERT_TRUE(IsValid(env, context.get()));
+  // No synonym should have been created, since the bit instruction is
+  // irrelevant.
+  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(166, {}), MakeDataDescriptor(39, {})));
+}
+
+TEST(TransformationAddBitInstructionSynonymTest, NoSynonymWhenBlockIsDead) {
+  std::string reference_shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %37 "main"
+
+; Types
+          %2 = OpTypeInt 32 0
+          %3 = OpTypeVoid
+          %4 = OpTypeFunction %3
+
+; Constants
+          %5 = OpConstant %2 0
+          %6 = OpConstant %2 1
+          %7 = OpConstant %2 2
+          %8 = OpConstant %2 3
+          %9 = OpConstant %2 4
+         %10 = OpConstant %2 5
+         %11 = OpConstant %2 6
+         %12 = OpConstant %2 7
+         %13 = OpConstant %2 8
+         %14 = OpConstant %2 9
+         %15 = OpConstant %2 10
+         %16 = OpConstant %2 11
+         %17 = OpConstant %2 12
+         %18 = OpConstant %2 13
+         %19 = OpConstant %2 14
+         %20 = OpConstant %2 15
+         %21 = OpConstant %2 16
+         %22 = OpConstant %2 17
+         %23 = OpConstant %2 18
+         %24 = OpConstant %2 19
+         %25 = OpConstant %2 20
+         %26 = OpConstant %2 21
+         %27 = OpConstant %2 22
+         %28 = OpConstant %2 23
+         %29 = OpConstant %2 24
+         %30 = OpConstant %2 25
+         %31 = OpConstant %2 26
+         %32 = OpConstant %2 27
+         %33 = OpConstant %2 28
+         %34 = OpConstant %2 29
+         %35 = OpConstant %2 30
+         %36 = OpConstant %2 31
+
+; main function
+         %37 = OpFunction %3 None %4
+         %38 = OpLabel
+         %39 = OpBitwiseOr %2 %5 %6 ; bit instruction
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_5;
+  const auto consumer = nullptr;
+  const auto context =
+      BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
+  ASSERT_TRUE(IsValid(env, context.get()));
+
+  spvtools::ValidatorOptions validator_options;
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+  // Mark the block where we will try to create the synonym as dead.
+  transformation_context.GetFactManager()->AddFactBlockIsDead(38);
+
+  // Adds OpBitwiseOr synonym.
+  auto transformation = TransformationAddBitInstructionSynonym(
+      39, {40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,
+           53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,
+           66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,
+           79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,
+           92,  93,  94,  95,  96,  97,  98,  99,  100, 101, 102, 103, 104,
+           105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+           118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
+           131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+           144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156,
+           157, 158, 159, 160, 161, 162, 163, 164, 165, 166});
+  ASSERT_TRUE(
+      transformation.IsApplicable(context.get(), transformation_context));
+  ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
+  ASSERT_TRUE(IsValid(env, context.get()));
+  // No synonym should have been created, since the bit instruction is
+  // irrelevant.
+  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(166, {}), MakeDataDescriptor(39, {})));
+}
+
 }  // namespace
 }  // namespace fuzz
 }  // namespace spvtools
diff --git a/test/fuzz/transformation_add_loop_to_create_int_constant_synonym_test.cpp b/test/fuzz/transformation_add_loop_to_create_int_constant_synonym_test.cpp
index 34616eb..93c2d11 100644
--- a/test/fuzz/transformation_add_loop_to_create_int_constant_synonym_test.cpp
+++ b/test/fuzz/transformation_add_loop_to_create_int_constant_synonym_test.cpp
@@ -948,6 +948,79 @@
   ASSERT_TRUE(IsEqual(env, after_transformations, context.get()));
 }
 
+TEST(TransformationAddLoopToCreateIntConstantSynonymTest,
+     InapplicableDueToDeadBlockOrIrrelevantId) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %2 "main"
+               OpExecutionMode %2 OriginUpperLeft
+               OpSource ESSL 310
+          %3 = OpTypeVoid
+          %4 = OpTypeFunction %3
+          %5 = OpTypeBool
+          %6 = OpConstantTrue %5
+          %7 = OpTypeInt 32 1
+          %8 = OpConstant %7 0
+          %9 = OpConstant %7 1
+         %10 = OpConstant %7 2
+         %11 = OpConstant %7 5
+         %12 = OpConstant %7 10
+         %13 = OpConstant %7 20
+       %1010 = OpConstant %7 2
+       %1011 = OpConstant %7 5
+       %1012 = OpConstant %7 10
+       %1013 = OpConstant %7 20
+          %2 = OpFunction %3 None %4
+         %14 = OpLabel
+               OpSelectionMerge %16 None
+               OpBranchConditional %6 %16 %15
+         %15 = OpLabel
+               OpBranch %16
+         %16 = OpLabel
+               OpBranch %17
+         %17 = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_5;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  ASSERT_TRUE(IsValid(env, context.get()));
+
+  spvtools::ValidatorOptions validator_options;
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+  transformation_context.GetFactManager()->AddFactBlockIsDead(15);
+  transformation_context.GetFactManager()->AddFactIdIsIrrelevant(1010);
+  transformation_context.GetFactManager()->AddFactIdIsIrrelevant(1011);
+  transformation_context.GetFactManager()->AddFactIdIsIrrelevant(1012);
+  transformation_context.GetFactManager()->AddFactIdIsIrrelevant(1013);
+  // Bad because the block before which the loop would be inserted is dead.
+  ASSERT_FALSE(TransformationAddLoopToCreateIntConstantSynonym(
+                   12, 13, 11, 10, 15, 100, 101, 102, 103, 104, 105, 106, 0)
+                   .IsApplicable(context.get(), transformation_context));
+  // OK
+  ASSERT_TRUE(TransformationAddLoopToCreateIntConstantSynonym(
+                  12, 13, 11, 10, 17, 100, 101, 102, 103, 104, 105, 106, 0)
+                  .IsApplicable(context.get(), transformation_context));
+  // Bad because in each case one of the constants involved is irrelevant.
+  ASSERT_FALSE(TransformationAddLoopToCreateIntConstantSynonym(
+                   1012, 13, 11, 10, 17, 100, 101, 102, 103, 104, 105, 106, 0)
+                   .IsApplicable(context.get(), transformation_context));
+  ASSERT_FALSE(TransformationAddLoopToCreateIntConstantSynonym(
+                   12, 1013, 11, 10, 17, 100, 101, 102, 103, 104, 105, 106, 0)
+                   .IsApplicable(context.get(), transformation_context));
+  ASSERT_FALSE(TransformationAddLoopToCreateIntConstantSynonym(
+                   12, 13, 1011, 10, 17, 100, 101, 102, 103, 104, 105, 106, 0)
+                   .IsApplicable(context.get(), transformation_context));
+  ASSERT_FALSE(TransformationAddLoopToCreateIntConstantSynonym(
+                   12, 13, 11, 1010, 17, 100, 101, 102, 103, 104, 105, 106, 0)
+                   .IsApplicable(context.get(), transformation_context));
+}
+
 }  // namespace
 }  // namespace fuzz
 }  // namespace spvtools
diff --git a/test/fuzz/transformation_add_opphi_synonym_test.cpp b/test/fuzz/transformation_add_opphi_synonym_test.cpp
index a6f067f..7cf073b 100644
--- a/test/fuzz/transformation_add_opphi_synonym_test.cpp
+++ b/test/fuzz/transformation_add_opphi_synonym_test.cpp
@@ -418,6 +418,68 @@
 
   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
 }
+
+TEST(TransformationAddOpPhiSynonymTest, DeadBlock) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypePointer Function %6
+          %9 = OpConstant %6 2
+         %10 = OpTypeBool
+         %11 = OpConstantFalse %10
+         %15 = OpConstant %6 0
+         %50 = OpConstant %6 0
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %8 = OpVariable %7 Function
+               OpStore %8 %9
+               OpSelectionMerge %13 None
+               OpBranchConditional %11 %12 %13
+         %12 = OpLabel
+         %14 = OpLoad %6 %8
+         %16 = OpIEqual %10 %14 %15
+               OpSelectionMerge %18 None
+               OpBranchConditional %16 %17 %40
+         %17 = OpLabel
+               OpBranch %18
+         %40 = OpLabel
+               OpBranch %18
+         %18 = OpLabel
+               OpBranch %13
+         %13 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_5;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  ASSERT_TRUE(IsValid(env, context.get()));
+
+  spvtools::ValidatorOptions validator_options;
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+  // Dead blocks
+  transformation_context.GetFactManager()->AddFactBlockIsDead(12);
+  transformation_context.GetFactManager()->AddFactBlockIsDead(17);
+  transformation_context.GetFactManager()->AddFactBlockIsDead(18);
+
+  // Declare synonym
+  ASSERT_TRUE(transformation_context.GetFactManager()->MaybeAddFact(
+      MakeSynonymFact(15, 50)));
+
+  // Bad because the block 18 is dead.
+  ASSERT_FALSE(TransformationAddOpPhiSynonym(18, {{{17, 15}, {40, 50}}}, 100)
+                   .IsApplicable(context.get(), transformation_context));
+}
+
 }  // namespace
 }  // namespace fuzz
 }  // namespace spvtools
diff --git a/test/fuzz/transformation_composite_construct_test.cpp b/test/fuzz/transformation_composite_construct_test.cpp
index 2e595f8..eed73b4 100644
--- a/test/fuzz/transformation_composite_construct_test.cpp
+++ b/test/fuzz/transformation_composite_construct_test.cpp
@@ -1517,10 +1517,64 @@
   ASSERT_TRUE(IsValid(env, context.get()));
   ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
       MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0})));
-  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+  // Even though %28 is not irrelevant, we do not create a synonym because part
+  // of the new composite, %200, is tainted by the irrelevant id %25.
+  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
       MakeDataDescriptor(28, {}), MakeDataDescriptor(200, {1})));
 }
 
+TEST(TransformationCompositeConstructTest, DontAddSynonymsInDeadBlock) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeVector %6 2
+          %8 = OpTypePointer Function %7
+         %10 = OpConstant %6 0
+         %11 = OpConstant %6 1
+         %12 = OpConstantComposite %7 %10 %11
+         %13 = OpTypeBool
+         %14 = OpConstantFalse %13
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %9 = OpVariable %8 Function
+               OpStore %9 %12
+               OpSelectionMerge %16 None
+               OpBranchConditional %14 %15 %16
+         %15 = OpLabel
+               OpBranch %16
+         %16 = OpLabel
+               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()));
+
+  spvtools::ValidatorOptions validator_options;
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+  transformation_context.GetFactManager()->AddFactBlockIsDead(15);
+
+  TransformationCompositeConstruct transformation(
+      7, {10, 11}, MakeInstructionDescriptor(15, SpvOpBranch, 0), 100);
+  ASSERT_TRUE(
+      transformation.IsApplicable(context.get(), transformation_context));
+  ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
+  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(7, {0}), MakeDataDescriptor(10, {})));
+  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(7, {1}), MakeDataDescriptor(11, {})));
+}
+
 }  // namespace
 }  // namespace fuzz
 }  // namespace spvtools
diff --git a/test/fuzz/transformation_composite_extract_test.cpp b/test/fuzz/transformation_composite_extract_test.cpp
index ea2f721..2aa8322 100644
--- a/test/fuzz/transformation_composite_extract_test.cpp
+++ b/test/fuzz/transformation_composite_extract_test.cpp
@@ -577,6 +577,55 @@
       MakeDataDescriptor(201, {}), MakeDataDescriptor(100, {2})));
 }
 
+TEST(TransformationCompositeExtractTest, DontAddSynonymInDeadBlock) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeVector %6 2
+          %8 = OpTypePointer Function %7
+         %10 = OpConstant %6 0
+         %11 = OpConstant %6 1
+         %12 = OpConstantComposite %7 %10 %11
+         %13 = OpTypeBool
+         %14 = OpConstantFalse %13
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %9 = OpVariable %8 Function
+               OpStore %9 %12
+               OpSelectionMerge %16 None
+               OpBranchConditional %14 %15 %16
+         %15 = OpLabel
+               OpBranch %16
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  ASSERT_TRUE(IsValid(env, context.get()));
+
+  spvtools::ValidatorOptions validator_options;
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+  transformation_context.GetFactManager()->AddFactBlockIsDead(15);
+  TransformationCompositeExtract transformation(
+      MakeInstructionDescriptor(15, SpvOpBranch, 0), 100, 12, {0});
+  ASSERT_TRUE(
+      transformation.IsApplicable(context.get(), transformation_context));
+  ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
+  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(100, {}), MakeDataDescriptor(12, {0})));
+}
+
 }  // namespace
 }  // namespace fuzz
 }  // namespace spvtools
diff --git a/test/fuzz/transformation_composite_insert_test.cpp b/test/fuzz/transformation_composite_insert_test.cpp
index b1a7699..4468786 100644
--- a/test/fuzz/transformation_composite_insert_test.cpp
+++ b/test/fuzz/transformation_composite_insert_test.cpp
@@ -14,6 +14,7 @@
 
 #include "source/fuzz/transformation_composite_insert.h"
 
+#include "source/fuzz/data_descriptor.h"
 #include "source/fuzz/instruction_descriptor.h"
 #include "test/fuzz/fuzz_test_util.h"
 
@@ -370,7 +371,8 @@
                         &transformation_context);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  // No synonyms should have been added.
+  // No synonyms that involve the original object - %30 - should have been
+  // added.
   ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
       MakeDataDescriptor(30, {0}), MakeDataDescriptor(50, {0})));
   ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
@@ -379,15 +381,13 @@
       MakeDataDescriptor(30, {1, 2}), MakeDataDescriptor(50, {1, 2})));
   ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
       MakeDataDescriptor(30, {1, 0, 1}), MakeDataDescriptor(50, {1, 0, 1})));
-  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
+  // We *should* have a synonym between %11 and the component of %50 into which
+  // it has been inserted.
+  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
       MakeDataDescriptor(50, {1, 0, 0}), MakeDataDescriptor(11, {})));
 }
-TEST(TransformationCompositeInsertTest, IrrelevantObjectSomeSynonyms) {
-  // This test handles cases where |object| is irrelevant.
-  // The transformation should create some synonyms. It shouldn't create a
-  // synonym related to |object|. The member composite has a different number of
-  // elements than the parent composite.
 
+TEST(TransformationCompositeInsertTest, IrrelevantObjectNoSynonyms) {
   std::string shader = R"(
                OpCapability Shader
           %1 = OpExtInstImport "GLSL.std.450"
@@ -474,7 +474,8 @@
                         &transformation_context);
   ASSERT_TRUE(IsValid(env, context.get()));
 
-  // These synonyms should have been added.
+  // Since %30 and %50 are not irrelevant, they should be synonymous at all
+  // indices unaffected by the insertion.
   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
       MakeDataDescriptor(30, {0}), MakeDataDescriptor(50, {0})));
   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
@@ -483,7 +484,8 @@
       MakeDataDescriptor(30, {1, 2}), MakeDataDescriptor(50, {1, 2})));
   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
       MakeDataDescriptor(30, {1, 0, 1}), MakeDataDescriptor(50, {1, 0, 1})));
-  // This synonym shouldn't have been added.
+  // Since %11 is irrelevant it should not be synonymous with the component into
+  // which it has been inserted.
   ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
       MakeDataDescriptor(50, {1, 0, 0}), MakeDataDescriptor(11, {})));
 }
@@ -802,6 +804,106 @@
   ASSERT_FALSE(
       transformation_bad_4.IsApplicable(context.get(), transformation_context));
 }
+
+TEST(TransformationCompositeInsertTest, CompositeInsertionWithIrrelevantIds) {
+  // This checks that we do *not* get data synonym facts when we do composite
+  // insertion using irrelevant ids or in dead blocks.
+
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %12 "main"
+               OpExecutionMode %12 OriginUpperLeft
+               OpSource ESSL 310
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeVector %6 2
+          %8 = OpConstant %6 0
+          %9 = OpConstantComposite %7 %8 %8
+         %10 = OpTypeBool
+         %11 = OpConstantFalse %10
+         %16 = OpConstant %6 0
+         %17 = OpConstant %6 1
+         %18 = OpConstantComposite %7 %8 %8
+         %12 = OpFunction %2 None %3
+         %13 = OpLabel
+               OpSelectionMerge %15 None
+               OpBranchConditional %11 %14 %15
+         %14 = OpLabel
+               OpBranch %15
+         %15 = OpLabel
+               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()));
+
+  spvtools::ValidatorOptions validator_options;
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+
+  transformation_context.GetFactManager()->AddFactBlockIsDead(14);
+  transformation_context.GetFactManager()->AddFactIdIsIrrelevant(16);
+  transformation_context.GetFactManager()->AddFactIdIsIrrelevant(18);
+
+  // Leads to synonyms - nothing is irrelevant.
+  auto transformation1 = TransformationCompositeInsert(
+      MakeInstructionDescriptor(13, SpvOpSelectionMerge, 0), 100, 9, 17, {0});
+  ASSERT_TRUE(
+      transformation1.IsApplicable(context.get(), transformation_context));
+  ApplyAndCheckFreshIds(transformation1, context.get(),
+                        &transformation_context);
+  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(100, {0}), MakeDataDescriptor(17, {})));
+  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(100, {1}), MakeDataDescriptor(9, {1})));
+
+  // Because %16 is irrelevant, we don't get a synonym with the component to
+  // which it has been inserted (but we do for the other component).
+  auto transformation2 = TransformationCompositeInsert(
+      MakeInstructionDescriptor(13, SpvOpSelectionMerge, 0), 101, 9, 16, {0});
+  ASSERT_TRUE(
+      transformation2.IsApplicable(context.get(), transformation_context));
+  ApplyAndCheckFreshIds(transformation2, context.get(),
+                        &transformation_context);
+  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(101, {0}), MakeDataDescriptor(16, {})));
+  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(101, {1}), MakeDataDescriptor(9, {1})));
+
+  // Because %18 is irrelevant we only get a synonym for the component into
+  // which insertion has taken place.
+  auto transformation3 = TransformationCompositeInsert(
+      MakeInstructionDescriptor(13, SpvOpSelectionMerge, 0), 102, 18, 17, {0});
+  ASSERT_TRUE(
+      transformation3.IsApplicable(context.get(), transformation_context));
+  ApplyAndCheckFreshIds(transformation3, context.get(),
+                        &transformation_context);
+  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(102, {0}), MakeDataDescriptor(17, {})));
+  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(102, {1}), MakeDataDescriptor(18, {1})));
+
+  // Does not lead to synonyms as block %14 is dead.
+  auto transformation4 = TransformationCompositeInsert(
+      MakeInstructionDescriptor(14, SpvOpBranch, 0), 103, 9, 17, {0});
+  ASSERT_TRUE(
+      transformation4.IsApplicable(context.get(), transformation_context));
+  ApplyAndCheckFreshIds(transformation4, context.get(),
+                        &transformation_context);
+  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(103, {0}), MakeDataDescriptor(17, {})));
+  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(103, {1}), MakeDataDescriptor(9, {1})));
+
+  ASSERT_TRUE(IsValid(env, context.get()));
+}
+
 }  // namespace
 }  // namespace fuzz
 }  // namespace spvtools
diff --git a/test/fuzz/transformation_push_id_through_variable_test.cpp b/test/fuzz/transformation_push_id_through_variable_test.cpp
index 82d8379..3fbe132 100644
--- a/test/fuzz/transformation_push_id_through_variable_test.cpp
+++ b/test/fuzz/transformation_push_id_through_variable_test.cpp
@@ -694,6 +694,61 @@
       MakeDataDescriptor(21, {}), MakeDataDescriptor(62, {})));
 }
 
+TEST(TransformationPushIdThroughVariableTest, DontAddSynonymsInDeadBlocks) {
+  std::string reference_shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeVector %6 2
+          %8 = OpTypePointer Function %7
+         %10 = OpConstant %6 0
+         %11 = OpConstant %6 1
+         %12 = OpConstantComposite %7 %10 %11
+         %13 = OpTypeBool
+         %50 = OpTypePointer Function %13
+         %14 = OpConstantFalse %13
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %9 = OpVariable %8 Function
+               OpStore %9 %12
+               OpSelectionMerge %16 None
+               OpBranchConditional %14 %15 %16
+         %15 = OpLabel
+               OpBranch %16
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const auto context =
+      BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
+
+  spvtools::ValidatorOptions validator_options;
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+  // Tests the reference shader validity.
+  ASSERT_TRUE(IsValid(env, context.get()));
+
+  transformation_context.GetFactManager()->AddFactBlockIsDead(15);
+  auto transformation = TransformationPushIdThroughVariable(
+      14, 100, 101, SpvStorageClassFunction, 14,
+      MakeInstructionDescriptor(15, SpvOpBranch, 0));
+  ASSERT_TRUE(
+      transformation.IsApplicable(context.get(), transformation_context));
+  ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
+  ASSERT_TRUE(IsValid(env, context.get()));
+  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(14, {}), MakeDataDescriptor(100, {})));
+}
+
 }  // namespace
 }  // namespace fuzz
 }  // namespace spvtools
diff --git a/test/fuzz/transformation_replace_copy_object_with_store_load_test.cpp b/test/fuzz/transformation_replace_copy_object_with_store_load_test.cpp
index 1b2d144..52b0ed3 100644
--- a/test/fuzz/transformation_replace_copy_object_with_store_load_test.cpp
+++ b/test/fuzz/transformation_replace_copy_object_with_store_load_test.cpp
@@ -195,6 +195,67 @@
   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
 }
 
+TEST(TransformationReplaceCopyObjectWithStoreLoad, IrrelevantIdsAndDeadBlocks) {
+  std::string reference_shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+         %30 = OpTypePointer Function %6
+         %10 = OpConstant %6 0
+         %11 = OpConstant %6 1
+         %13 = OpTypeBool
+         %14 = OpConstantFalse %13
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+               OpSelectionMerge %16 None
+               OpBranchConditional %14 %15 %16
+         %15 = OpLabel
+         %50 = OpCopyObject %6 %10
+               OpBranch %16
+         %16 = OpLabel
+         %51 = OpCopyObject %6 %11
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const auto context =
+      BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
+
+  spvtools::ValidatorOptions validator_options;
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+  ASSERT_TRUE(IsValid(env, context.get()));
+
+  transformation_context.GetFactManager()->AddFactBlockIsDead(15);
+  transformation_context.GetFactManager()->AddFactIdIsIrrelevant(11);
+
+  auto transformation_1 = TransformationReplaceCopyObjectWithStoreLoad(
+      50, 100, SpvStorageClassFunction, 10);
+  ASSERT_TRUE(
+      transformation_1.IsApplicable(context.get(), transformation_context));
+  ApplyAndCheckFreshIds(transformation_1, context.get(),
+                        &transformation_context);
+  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(100, {}), MakeDataDescriptor(50, {})));
+
+  auto transformation_2 = TransformationReplaceCopyObjectWithStoreLoad(
+      51, 101, SpvStorageClassFunction, 10);
+  ASSERT_TRUE(
+      transformation_2.IsApplicable(context.get(), transformation_context));
+  ApplyAndCheckFreshIds(transformation_2, context.get(),
+                        &transformation_context);
+  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(101, {}), MakeDataDescriptor(51, {})));
+}
+
 }  // namespace
 }  // namespace fuzz
 }  // namespace spvtools
diff --git a/test/fuzz/transformation_vector_shuffle_test.cpp b/test/fuzz/transformation_vector_shuffle_test.cpp
index 5f19258..8a8279b 100644
--- a/test/fuzz/transformation_vector_shuffle_test.cpp
+++ b/test/fuzz/transformation_vector_shuffle_test.cpp
@@ -21,7 +21,7 @@
 namespace fuzz {
 namespace {
 
-TEST(TransformationVectorShuffle, BasicTest) {
+TEST(TransformationVectorShuffleTest, BasicTest) {
   std::string shader = R"(
                OpCapability Shader
           %1 = OpExtInstImport "GLSL.std.450"
@@ -544,7 +544,7 @@
                    .IsApplicable(context.get(), transformation_context));
 }
 
-TEST(TransformationVectorShuffle, HandlesIrrelevantIds1) {
+TEST(TransformationVectorShuffleTest, HandlesIrrelevantIds1) {
   std::string shader = R"(
                OpCapability Shader
           %1 = OpExtInstImport "GLSL.std.450"
@@ -624,7 +624,7 @@
       MakeDataDescriptor(112, {0}), MakeDataDescriptor(200, {0})));
 }
 
-TEST(TransformationVectorShuffle, HandlesIrrelevantIds2) {
+TEST(TransformationVectorShuffleTest, HandlesIrrelevantIds2) {
   std::string shader = R"(
                OpCapability Shader
           %1 = OpExtInstImport "GLSL.std.450"
@@ -699,12 +699,104 @@
       transformation.IsApplicable(context.get(), transformation_context));
   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
   ASSERT_TRUE(IsValid(env, context.get()));
+  // Because %12 is not irrelevant, we get a synonym between it and %200[1].
   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
       MakeDataDescriptor(12, {0}), MakeDataDescriptor(200, {1})));
+  // Because %112 is irrelevant, we do not get a synonym between it and %200[0].
   ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
       MakeDataDescriptor(112, {0}), MakeDataDescriptor(200, {0})));
 }
 
+TEST(TransformationVectorShuffleTest, HandlesIrrelevantIds3) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 320
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeInt 32 1
+          %7 = OpTypeVector %6 2
+          %8 = OpTypePointer Function %7
+         %10 = OpConstant %6 0
+         %11 = OpConstant %6 1
+         %12 = OpConstantComposite %7 %10 %11
+         %40 = OpConstantComposite %7 %10 %11
+         %13 = OpTypeBool
+         %14 = OpConstantFalse %13
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+          %9 = OpVariable %8 Function
+               OpStore %9 %12
+               OpSelectionMerge %16 None
+               OpBranchConditional %14 %15 %16
+         %15 = OpLabel
+               OpBranch %16
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  ASSERT_TRUE(IsValid(env, context.get()));
+
+  spvtools::ValidatorOptions validator_options;
+  TransformationContext transformation_context(
+      MakeUnique<FactManager>(context.get()), validator_options);
+  transformation_context.GetFactManager()->AddFactIdIsIrrelevant(40);
+  transformation_context.GetFactManager()->AddFactBlockIsDead(15);
+
+  TransformationVectorShuffle transformation1(
+      MakeInstructionDescriptor(15, SpvOpBranch, 0), 200, 12, 12, {0, 3});
+  ASSERT_TRUE(
+      transformation1.IsApplicable(context.get(), transformation_context));
+  ApplyAndCheckFreshIds(transformation1, context.get(),
+                        &transformation_context);
+  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(200, {0}), MakeDataDescriptor(12, {0})));
+  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(200, {1}), MakeDataDescriptor(12, {1})));
+
+  TransformationVectorShuffle transformation2(
+      MakeInstructionDescriptor(16, SpvOpReturn, 0), 201, 12, 40, {0, 1});
+  ASSERT_TRUE(
+      transformation2.IsApplicable(context.get(), transformation_context));
+  ApplyAndCheckFreshIds(transformation2, context.get(),
+                        &transformation_context);
+  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(201, {0}), MakeDataDescriptor(12, {0})));
+  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(201, {1}), MakeDataDescriptor(12, {1})));
+
+  TransformationVectorShuffle transformation3(
+      MakeInstructionDescriptor(16, SpvOpReturn, 0), 202, 40, 12, {2, 3});
+  ASSERT_TRUE(
+      transformation3.IsApplicable(context.get(), transformation_context));
+  ApplyAndCheckFreshIds(transformation3, context.get(),
+                        &transformation_context);
+  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(202, {0}), MakeDataDescriptor(12, {0})));
+  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(202, {1}), MakeDataDescriptor(12, {1})));
+
+  TransformationVectorShuffle transformation4(
+      MakeInstructionDescriptor(16, SpvOpReturn, 0), 203, 40, 12, {0, 3});
+  ASSERT_TRUE(
+      transformation4.IsApplicable(context.get(), transformation_context));
+  ApplyAndCheckFreshIds(transformation4, context.get(),
+                        &transformation_context);
+  // Because %40 is irrelevant we do not get a synonym between it and %203[0].
+  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(203, {0}), MakeDataDescriptor(40, {0})));
+  // Because %12 is *not* irrelevant we do get a synonym between it and %203[1].
+  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
+      MakeDataDescriptor(203, {1}), MakeDataDescriptor(12, {1})));
+}
+
 }  // namespace
 }  // namespace fuzz
 }  // namespace spvtools