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