mirror of
https://gitee.com/openharmony/third_party_spirv-tools
synced 2024-11-27 09:32:08 +00:00
spirv-fuzz: Do not add synonyms involving irrelevant ids (#3890)
Fixes #3886.
This commit is contained in:
parent
d52f79122a
commit
3602287858
@ -94,6 +94,9 @@ void TransformationAddBitInstructionSynonym::Apply(
|
||||
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 @@ void TransformationAddBitInstructionSynonym::Apply(
|
||||
assert(false && "Should be unreachable.");
|
||||
break;
|
||||
}
|
||||
|
||||
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
|
||||
}
|
||||
|
||||
protobufs::Transformation TransformationAddBitInstructionSynonym::ToMessage()
|
||||
@ -223,11 +224,19 @@ void TransformationAddBitInstructionSynonym::AddOpBitwiseOrOpNotSynonym(
|
||||
|
||||
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
|
||||
|
||||
// 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>
|
||||
|
@ -53,8 +53,8 @@ bool TransformationAddLoopToCreateIntConstantSynonym::IsApplicable(
|
||||
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 @@ bool TransformationAddLoopToCreateIntConstantSynonym::IsApplicable(
|
||||
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 @@ bool TransformationAddLoopToCreateIntConstantSynonym::IsApplicable(
|
||||
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 @@ bool TransformationAddLoopToCreateIntConstantSynonym::IsApplicable(
|
||||
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;
|
||||
|
@ -45,6 +45,7 @@ class TransformationAddLoopToCreateIntConstantSynonym : public Transformation {
|
||||
// - |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.
|
||||
|
@ -34,9 +34,11 @@ TransformationAddOpPhiSynonym::TransformationAddOpPhiSynonym(
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@ class TransformationAddOpPhiSynonym : public Transformation {
|
||||
|
||||
// - |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|:
|
||||
|
@ -40,8 +40,7 @@ TransformationCompositeConstruct::TransformationCompositeConstruct(
|
||||
}
|
||||
|
||||
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 @@ bool TransformationCompositeConstruct::IsApplicable(
|
||||
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 @@ void TransformationCompositeConstruct::Apply(
|
||||
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 @@ std::unordered_set<uint32_t> TransformationCompositeConstruct::GetFreshIds()
|
||||
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
|
||||
|
@ -58,6 +58,10 @@ class TransformationCompositeConstruct : public Transformation {
|
||||
// |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 @@ class TransformationCompositeConstruct : public Transformation {
|
||||
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_;
|
||||
};
|
||||
|
||||
|
@ -41,8 +41,7 @@ TransformationCompositeExtract::TransformationCompositeExtract(
|
||||
}
|
||||
|
||||
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 @@ bool TransformationCompositeExtract::IsApplicable(
|
||||
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 @@ void TransformationCompositeExtract::Apply(
|
||||
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 @@ void TransformationCompositeExtract::Apply(
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -49,9 +49,11 @@ class TransformationCompositeExtract : public Transformation {
|
||||
// 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 @@ class TransformationCompositeExtract : public Transformation {
|
||||
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_;
|
||||
};
|
||||
|
||||
|
@ -134,54 +134,8 @@ void TransformationCompositeInsert::Apply(
|
||||
// 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 @@ std::unordered_set<uint32_t> TransformationCompositeInsert::GetFreshIds()
|
||||
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
|
||||
|
@ -65,6 +65,11 @@ class TransformationCompositeInsert : public Transformation {
|
||||
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_;
|
||||
};
|
||||
|
||||
|
@ -38,8 +38,7 @@ TransformationPushIdThroughVariable::TransformationPushIdThroughVariable(
|
||||
}
|
||||
|
||||
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 @@ bool TransformationPushIdThroughVariable::IsApplicable(
|
||||
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 @@ void TransformationPushIdThroughVariable::Apply(
|
||||
|
||||
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(
|
||||
|
@ -52,7 +52,7 @@ class TransformationPushIdThroughVariable : public Transformation {
|
||||
|
||||
// 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;
|
||||
|
||||
|
@ -89,7 +89,7 @@ void TransformationReplaceCopyObjectWithStoreLoad::Apply(
|
||||
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 @@ void TransformationReplaceCopyObjectWithStoreLoad::Apply(
|
||||
|
||||
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
|
||||
|
||||
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
|
||||
|
@ -39,8 +39,7 @@ TransformationVectorShuffle::TransformationVectorShuffle(
|
||||
}
|
||||
|
||||
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 @@ bool TransformationVectorShuffle::IsApplicable(
|
||||
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 @@ void TransformationVectorShuffle::Apply(
|
||||
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 @@ std::unordered_set<uint32_t> TransformationVectorShuffle::GetFreshIds() const {
|
||||
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
|
||||
|
@ -52,15 +52,16 @@ class TransformationVectorShuffle : public Transformation {
|
||||
// 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 @@ class TransformationVectorShuffle : public Transformation {
|
||||
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_;
|
||||
};
|
||||
|
||||
|
@ -721,6 +721,184 @@ TEST(TransformationAddBitInstructionSynonymTest, AddOpNotSynonym) {
|
||||
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
|
||||
|
@ -948,6 +948,79 @@ TEST(TransformationAddLoopToCreateIntConstantSynonymTest, Underflow) {
|
||||
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
|
||||
|
@ -418,6 +418,68 @@ TEST(TransformationAddOpPhiSynonymTest, VariablePointers) {
|
||||
|
||||
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
|
||||
|
@ -1517,10 +1517,64 @@ TEST(TransformationCompositeConstructTest, DontAddSynonymsForIrrelevantIds) {
|
||||
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
|
||||
|
@ -577,6 +577,55 @@ TEST(TransformationCompositeExtractTest, DontAddSynonymsForIrrelevantIds) {
|
||||
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
|
||||
|
@ -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 @@ TEST(TransformationCompositeInsertTest, IrrelevantCompositeNoSynonyms) {
|
||||
&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 @@ TEST(TransformationCompositeInsertTest, IrrelevantCompositeNoSynonyms) {
|
||||
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 @@ TEST(TransformationCompositeInsertTest, IrrelevantObjectSomeSynonyms) {
|
||||
&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 @@ TEST(TransformationCompositeInsertTest, IrrelevantObjectSomeSynonyms) {
|
||||
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 @@ TEST(TransformationCompositeInsertTest, IdNotAvailableScenarios) {
|
||||
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
|
||||
|
@ -694,6 +694,61 @@ TEST(TransformationPushIdThroughVariableTest, DontAddSynonymsForIrrelevantIds) {
|
||||
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
|
||||
|
@ -195,6 +195,67 @@ TEST(TransformationReplaceCopyObjectWithStoreLoad, BasicScenarios) {
|
||||
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
|
||||
|
@ -21,7 +21,7 @@ namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationVectorShuffle, BasicTest) {
|
||||
TEST(TransformationVectorShuffleTest, BasicTest) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
@ -544,7 +544,7 @@ TEST(TransformationVectorShuffleTest, IllegalInsertionPoints) {
|
||||
.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 @@ TEST(TransformationVectorShuffle, HandlesIrrelevantIds1) {
|
||||
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 @@ TEST(TransformationVectorShuffle, HandlesIrrelevantIds2) {
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user