spirv-fuzz: Consider all ids from dead blocks irrelevant (#3795)
This PR modifies the FactManager methods IdIsIrrelevant and GetIrrelevantIds so that an id is always considered irrelevant if it comes from a dead block. Fixes #3733.
This commit is contained in:
Родитель
50ae4c5f44
Коммит
2945963cce
|
@ -53,11 +53,15 @@ bool DataSynonymAndIdEquationFacts::OperationEquals::operator()(
|
|||
|
||||
void DataSynonymAndIdEquationFacts::AddFact(
|
||||
const protobufs::FactDataSynonym& fact,
|
||||
const DeadBlockFacts& dead_block_facts,
|
||||
const IrrelevantValueFacts& irrelevant_value_facts,
|
||||
opt::IRContext* context) {
|
||||
(void)dead_block_facts; // Keep release compilers happy.
|
||||
(void)irrelevant_value_facts; // Keep release compilers happy.
|
||||
assert(!irrelevant_value_facts.IdIsIrrelevant(fact.data1().object()) &&
|
||||
!irrelevant_value_facts.IdIsIrrelevant(fact.data2().object()) &&
|
||||
assert(!irrelevant_value_facts.IdIsIrrelevant(fact.data1().object(),
|
||||
dead_block_facts, context) &&
|
||||
!irrelevant_value_facts.IdIsIrrelevant(fact.data2().object(),
|
||||
dead_block_facts, context) &&
|
||||
"Irrelevant ids cannot be synonymous with other ids.");
|
||||
|
||||
// Add the fact, including all facts relating sub-components of the data
|
||||
|
@ -67,10 +71,13 @@ void DataSynonymAndIdEquationFacts::AddFact(
|
|||
|
||||
void DataSynonymAndIdEquationFacts::AddFact(
|
||||
const protobufs::FactIdEquation& fact,
|
||||
const DeadBlockFacts& dead_block_facts,
|
||||
const IrrelevantValueFacts& irrelevant_value_facts,
|
||||
opt::IRContext* context) {
|
||||
(void)dead_block_facts; // Keep release compilers happy.
|
||||
(void)irrelevant_value_facts; // Keep release compilers happy.
|
||||
assert(!irrelevant_value_facts.IdIsIrrelevant(fact.lhs_id()) &&
|
||||
assert(!irrelevant_value_facts.IdIsIrrelevant(fact.lhs_id(), dead_block_facts,
|
||||
context) &&
|
||||
"Irrelevant ids are not allowed.");
|
||||
|
||||
protobufs::DataDescriptor lhs_dd = MakeDataDescriptor(fact.lhs_id(), {});
|
||||
|
@ -82,7 +89,8 @@ void DataSynonymAndIdEquationFacts::AddFact(
|
|||
// equation.
|
||||
std::vector<const protobufs::DataDescriptor*> rhs_dds;
|
||||
for (auto rhs_id : fact.rhs_id()) {
|
||||
assert(!irrelevant_value_facts.IdIsIrrelevant(rhs_id) &&
|
||||
assert(!irrelevant_value_facts.IdIsIrrelevant(rhs_id, dead_block_facts,
|
||||
context) &&
|
||||
"Irrelevant ids are not allowed.");
|
||||
|
||||
// Register a data descriptor based on this id in the equivalence relation
|
||||
|
|
|
@ -27,6 +27,8 @@ namespace spvtools {
|
|||
namespace fuzz {
|
||||
namespace fact_manager {
|
||||
|
||||
// Forward reference to the DeadBlockFacts class.
|
||||
class DeadBlockFacts;
|
||||
// Forward reference to the IrrelevantValueFacts class.
|
||||
class IrrelevantValueFacts;
|
||||
|
||||
|
@ -35,14 +37,18 @@ class IrrelevantValueFacts;
|
|||
class DataSynonymAndIdEquationFacts {
|
||||
public:
|
||||
// See method in FactManager which delegates to this method.
|
||||
// |irrelevant_value_facts| is passed for consistency checks.
|
||||
// |dead_block_facts| and |irrelevant_value_facts| are passed for consistency
|
||||
// checks.
|
||||
void AddFact(const protobufs::FactDataSynonym& fact,
|
||||
const DeadBlockFacts& dead_block_facts,
|
||||
const IrrelevantValueFacts& irrelevant_value_facts,
|
||||
opt::IRContext* context);
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
// |irrelevant_value_facts| is passed for consistency checks.
|
||||
// |dead_block_facts| and |irrelevant_value_facts| are passed for consistency
|
||||
// checks.
|
||||
void AddFact(const protobufs::FactIdEquation& fact,
|
||||
const DeadBlockFacts& dead_block_facts,
|
||||
const IrrelevantValueFacts& irrelevant_value_facts,
|
||||
opt::IRContext* context);
|
||||
|
||||
|
|
|
@ -26,6 +26,10 @@ bool DeadBlockFacts::BlockIsDead(uint32_t block_id) const {
|
|||
return dead_block_ids_.count(block_id) != 0;
|
||||
}
|
||||
|
||||
const std::unordered_set<uint32_t>& DeadBlockFacts::GetDeadBlocks() const {
|
||||
return dead_block_ids_;
|
||||
}
|
||||
|
||||
} // namespace fact_manager
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
|
|
@ -33,6 +33,9 @@ class DeadBlockFacts {
|
|||
// See method in FactManager which delegates to this method.
|
||||
bool BlockIsDead(uint32_t block_id) const;
|
||||
|
||||
// Returns a set of all the block ids that have been declared dead.
|
||||
const std::unordered_set<uint32_t>& GetDeadBlocks() const;
|
||||
|
||||
private:
|
||||
std::unordered_set<uint32_t> dead_block_ids_;
|
||||
};
|
||||
|
|
|
@ -106,7 +106,8 @@ bool FactManager::AddFact(const fuzz::protobufs::Fact& fact,
|
|||
context);
|
||||
case protobufs::Fact::kDataSynonymFact:
|
||||
data_synonym_and_id_equation_facts_.AddFact(
|
||||
fact.data_synonym_fact(), irrelevant_value_facts_, context);
|
||||
fact.data_synonym_fact(), dead_block_facts_, irrelevant_value_facts_,
|
||||
context);
|
||||
return true;
|
||||
case protobufs::Fact::kBlockIsDeadFact:
|
||||
dead_block_facts_.AddFact(fact.block_is_dead_fact());
|
||||
|
@ -126,8 +127,8 @@ void FactManager::AddFactDataSynonym(const protobufs::DataDescriptor& data1,
|
|||
protobufs::FactDataSynonym fact;
|
||||
*fact.mutable_data1() = data1;
|
||||
*fact.mutable_data2() = data2;
|
||||
data_synonym_and_id_equation_facts_.AddFact(fact, irrelevant_value_facts_,
|
||||
context);
|
||||
data_synonym_and_id_equation_facts_.AddFact(fact, dead_block_facts_,
|
||||
irrelevant_value_facts_, context);
|
||||
}
|
||||
|
||||
std::vector<uint32_t> FactManager::GetConstantsAvailableFromUniformsForType(
|
||||
|
@ -207,12 +208,15 @@ bool FactManager::PointeeValueIsIrrelevant(uint32_t pointer_id) const {
|
|||
return irrelevant_value_facts_.PointeeValueIsIrrelevant(pointer_id);
|
||||
}
|
||||
|
||||
bool FactManager::IdIsIrrelevant(uint32_t result_id) const {
|
||||
return irrelevant_value_facts_.IdIsIrrelevant(result_id);
|
||||
bool FactManager::IdIsIrrelevant(uint32_t result_id,
|
||||
opt::IRContext* context) const {
|
||||
return irrelevant_value_facts_.IdIsIrrelevant(result_id, dead_block_facts_,
|
||||
context);
|
||||
}
|
||||
|
||||
const std::unordered_set<uint32_t>& FactManager::GetIrrelevantIds() const {
|
||||
return irrelevant_value_facts_.GetIrrelevantIds();
|
||||
std::unordered_set<uint32_t> FactManager::GetIrrelevantIds(
|
||||
opt::IRContext* context) const {
|
||||
return irrelevant_value_facts_.GetIrrelevantIds(dead_block_facts_, context);
|
||||
}
|
||||
|
||||
void FactManager::AddFactValueOfPointeeIsIrrelevant(uint32_t pointer_id,
|
||||
|
@ -240,8 +244,8 @@ void FactManager::AddFactIdEquation(uint32_t lhs_id, SpvOp opcode,
|
|||
for (auto an_rhs_id : rhs_id) {
|
||||
fact.add_rhs_id(an_rhs_id);
|
||||
}
|
||||
data_synonym_and_id_equation_facts_.AddFact(fact, irrelevant_value_facts_,
|
||||
context);
|
||||
data_synonym_and_id_equation_facts_.AddFact(fact, dead_block_facts_,
|
||||
irrelevant_value_facts_, context);
|
||||
}
|
||||
|
||||
void FactManager::ComputeClosureOfFacts(
|
||||
|
|
|
@ -194,12 +194,13 @@ class FactManager {
|
|||
// |pointer_id| is irrelevant.
|
||||
bool PointeeValueIsIrrelevant(uint32_t pointer_id) const;
|
||||
|
||||
// Returns true iff there exists a fact that the |result_id| is irrelevant.
|
||||
bool IdIsIrrelevant(uint32_t result_id) const;
|
||||
// Returns true if there exists a fact that the |result_id| is irrelevant or
|
||||
// if |result_id| is declared in a block that has been declared dead.
|
||||
bool IdIsIrrelevant(uint32_t result_id, opt::IRContext* context) const;
|
||||
|
||||
// Returns an unordered set of all the ids which have been declared
|
||||
// irrelevant.
|
||||
const std::unordered_set<uint32_t>& GetIrrelevantIds() const;
|
||||
// Returns a set of all the ids which have been declared irrelevant, or which
|
||||
// have been declared inside a dead block.
|
||||
std::unordered_set<uint32_t> GetIrrelevantIds(opt::IRContext* context) const;
|
||||
|
||||
// End of irrelevant value facts
|
||||
//==============================
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include "source/fuzz/data_descriptor.h"
|
||||
#include "source/fuzz/fact_manager/data_synonym_and_id_equation_facts.h"
|
||||
#include "source/fuzz/fact_manager/dead_block_facts.h"
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
|
@ -60,13 +62,54 @@ bool IrrelevantValueFacts::PointeeValueIsIrrelevant(uint32_t pointer_id) const {
|
|||
return pointers_to_irrelevant_pointees_ids_.count(pointer_id) != 0;
|
||||
}
|
||||
|
||||
bool IrrelevantValueFacts::IdIsIrrelevant(uint32_t pointer_id) const {
|
||||
return irrelevant_ids_.count(pointer_id) != 0;
|
||||
bool IrrelevantValueFacts::IdIsIrrelevant(
|
||||
uint32_t result_id, const DeadBlockFacts& dead_block_facts,
|
||||
opt::IRContext* context) const {
|
||||
// The id is irrelevant if it has been declared irrelevant.
|
||||
if (irrelevant_ids_.count(result_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The id must have a non-pointer type to be irrelevant.
|
||||
auto def = context->get_def_use_mgr()->GetDef(result_id);
|
||||
if (!def) {
|
||||
return false;
|
||||
}
|
||||
auto type = context->get_type_mgr()->GetType(def->type_id());
|
||||
if (!type || type->AsPointer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The id is irrelevant if it is in a dead block.
|
||||
return context->get_instr_block(result_id) &&
|
||||
dead_block_facts.BlockIsDead(
|
||||
context->get_instr_block(result_id)->id());
|
||||
}
|
||||
|
||||
const std::unordered_set<uint32_t>& IrrelevantValueFacts::GetIrrelevantIds()
|
||||
const {
|
||||
return irrelevant_ids_;
|
||||
std::unordered_set<uint32_t> IrrelevantValueFacts::GetIrrelevantIds(
|
||||
const DeadBlockFacts& dead_block_facts, opt::IRContext* context) const {
|
||||
// Get all the ids that have been declared irrelevant.
|
||||
auto irrelevant_ids = irrelevant_ids_;
|
||||
|
||||
// Get all the non-pointer ids declared in dead blocks that have a type.
|
||||
for (uint32_t block_id : dead_block_facts.GetDeadBlocks()) {
|
||||
auto block = fuzzerutil::MaybeFindBlock(context, block_id);
|
||||
// It is possible and allowed for the block not to exist, e.g. it could have
|
||||
// been merged with another block.
|
||||
if (!block) {
|
||||
continue;
|
||||
}
|
||||
block->ForEachInst([context, &irrelevant_ids](opt::Instruction* inst) {
|
||||
// The instruction must have a result id and a type, and it must not be a
|
||||
// pointer.
|
||||
if (inst->HasResultId() && inst->type_id() &&
|
||||
!context->get_type_mgr()->GetType(inst->type_id())->AsPointer()) {
|
||||
irrelevant_ids.emplace(inst->result_id());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return irrelevant_ids;
|
||||
}
|
||||
|
||||
} // namespace fact_manager
|
||||
|
|
|
@ -26,6 +26,8 @@ namespace fact_manager {
|
|||
|
||||
// Forward reference to the DataSynonymAndIdEquationFacts class.
|
||||
class DataSynonymAndIdEquationFacts;
|
||||
// Forward reference to the DeadBlockFacts class.
|
||||
class DeadBlockFacts;
|
||||
|
||||
// The purpose of this class is to group the fields and data used to represent
|
||||
// facts about various irrelevant values in the module.
|
||||
|
@ -51,10 +53,17 @@ class IrrelevantValueFacts {
|
|||
bool PointeeValueIsIrrelevant(uint32_t pointer_id) const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
bool IdIsIrrelevant(uint32_t pointer_id) const;
|
||||
// |dead_block_facts| and |context| are passed to check whether |result_id| is
|
||||
// declared inside a dead block, in which case it is irrelevant.
|
||||
bool IdIsIrrelevant(uint32_t result_id,
|
||||
const DeadBlockFacts& dead_block_facts,
|
||||
opt::IRContext* context) const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
const std::unordered_set<uint32_t>& GetIrrelevantIds() const;
|
||||
// |dead_block_facts| and |context| are passed to also add all the ids
|
||||
// declared in dead blocks to the set of irrelevant ids.
|
||||
std::unordered_set<uint32_t> GetIrrelevantIds(
|
||||
const DeadBlockFacts& dead_block_facts, opt::IRContext* context) const;
|
||||
|
||||
private:
|
||||
std::unordered_set<uint32_t> pointers_to_irrelevant_pointees_ids_;
|
||||
|
|
|
@ -77,12 +77,14 @@ void FuzzerPassAddEquationInstructions::Apply() {
|
|||
std::vector<opt::Instruction*> available_instructions =
|
||||
FindAvailableInstructions(
|
||||
function, block, inst_it,
|
||||
[this](opt::IRContext*, opt::Instruction* instruction) -> bool {
|
||||
[this](opt::IRContext* ir_context,
|
||||
opt::Instruction* instruction) -> bool {
|
||||
return instruction->result_id() && instruction->type_id() &&
|
||||
instruction->opcode() != SpvOpUndef &&
|
||||
!GetTransformationContext()
|
||||
->GetFactManager()
|
||||
->IdIsIrrelevant(instruction->result_id());
|
||||
->IdIsIrrelevant(instruction->result_id(),
|
||||
ir_context);
|
||||
});
|
||||
|
||||
// Try the opcodes for which we know how to make ids at random until
|
||||
|
|
|
@ -157,7 +157,7 @@ FuzzerPassAddOpPhiSynonyms::GetIdEquivalenceClasses() {
|
|||
|
||||
// Exclude irrelevant ids.
|
||||
if (GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
|
||||
pair.first)) {
|
||||
pair.first, GetIRContext())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,7 @@ FuzzerPassAddOpPhiSynonyms::GetIdEquivalenceClasses() {
|
|||
|
||||
// The synonym must not be irrelevant.
|
||||
if (GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
|
||||
synonym->object())) {
|
||||
synonym->object(), GetIRContext())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,8 @@ void FuzzerPassAddVectorShuffleInstructions::Apply() {
|
|||
|
||||
if (!GetTransformationContext()
|
||||
->GetFactManager()
|
||||
->IdIsIrrelevant(instruction->result_id()) &&
|
||||
->IdIsIrrelevant(instruction->result_id(),
|
||||
GetIRContext()) &&
|
||||
!fuzzerutil::CanMakeSynonymOf(ir_context,
|
||||
*GetTransformationContext(),
|
||||
instruction)) {
|
||||
|
|
|
@ -148,7 +148,7 @@ void FuzzerPassApplyIdSynonyms::Apply() {
|
|||
}
|
||||
|
||||
assert(!GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
|
||||
synonym_to_try->object()) &&
|
||||
synonym_to_try->object(), GetIRContext()) &&
|
||||
"Irrelevant ids can't participate in DataSynonym facts");
|
||||
ApplyTransformation(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(GetIRContext(),
|
||||
|
|
|
@ -77,7 +77,7 @@ void FuzzerPassConstructComposites::Apply() {
|
|||
// to produce a synonym out of the id.
|
||||
return GetTransformationContext()
|
||||
->GetFactManager()
|
||||
->IdIsIrrelevant(inst->result_id()) ||
|
||||
->IdIsIrrelevant(inst->result_id(), GetIRContext()) ||
|
||||
fuzzerutil::CanMakeSynonymOf(
|
||||
ir_context, *GetTransformationContext(), inst);
|
||||
});
|
||||
|
|
|
@ -48,7 +48,7 @@ void FuzzerPassInterchangeSignednessOfIntegerOperands::Apply() {
|
|||
// constant with opposite signedness, and this can only be done if they are
|
||||
// not irrelevant.
|
||||
if (GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
|
||||
constant_id)) {
|
||||
constant_id, GetIRContext())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ void FuzzerPassInterchangeSignednessOfIntegerOperands::Apply() {
|
|||
}
|
||||
|
||||
assert(!GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
|
||||
toggled_id) &&
|
||||
toggled_id, GetIRContext()) &&
|
||||
"FindOrCreateToggledConstant can't produce an irrelevant id");
|
||||
|
||||
// Record synonymous constants
|
||||
|
|
|
@ -73,7 +73,7 @@ void FuzzerPassInterchangeZeroLikeConstants::Apply() {
|
|||
for (auto constant : GetIRContext()->GetConstants()) {
|
||||
uint32_t constant_id = constant->result_id();
|
||||
if (GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
|
||||
constant_id)) {
|
||||
constant_id, GetIRContext())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,7 @@ void FuzzerPassInterchangeZeroLikeConstants::Apply() {
|
|||
}
|
||||
|
||||
assert(!GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
|
||||
toggled_id) &&
|
||||
toggled_id, GetIRContext()) &&
|
||||
"FindOrCreateToggledConstant can't produce an irrelevant id");
|
||||
|
||||
// Record synonymous constants
|
||||
|
|
|
@ -96,7 +96,8 @@ void FuzzerPassPushIdsThroughVariables::Apply() {
|
|||
// able to produce a synonym out of the id.
|
||||
if (!GetTransformationContext()
|
||||
->GetFactManager()
|
||||
->IdIsIrrelevant(instruction->result_id()) &&
|
||||
->IdIsIrrelevant(instruction->result_id(),
|
||||
GetIRContext()) &&
|
||||
!fuzzerutil::CanMakeSynonymOf(ir_context,
|
||||
*GetTransformationContext(),
|
||||
instruction)) {
|
||||
|
|
|
@ -46,8 +46,8 @@ void FuzzerPassReplaceIrrelevantIds::Apply() {
|
|||
|
||||
// Find all the irrelevant ids that still exist in the module and all the
|
||||
// types for which irrelevant ids exist.
|
||||
for (auto id :
|
||||
GetTransformationContext()->GetFactManager()->GetIrrelevantIds()) {
|
||||
for (auto id : GetTransformationContext()->GetFactManager()->GetIrrelevantIds(
|
||||
GetIRContext())) {
|
||||
// Check that the id still exists in the module.
|
||||
auto declaration = GetIRContext()->get_def_use_mgr()->GetDef(id);
|
||||
if (!declaration) {
|
||||
|
|
|
@ -33,7 +33,7 @@ uint32_t MaybeGetOpConstant(opt::IRContext* ir_context,
|
|||
if (inst.opcode() == SpvOpConstant && inst.type_id() == type_id &&
|
||||
inst.GetInOperand(0).words == words &&
|
||||
transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
inst.result_id()) == is_irrelevant) {
|
||||
inst.result_id(), ir_context) == is_irrelevant) {
|
||||
return inst.result_id();
|
||||
}
|
||||
}
|
||||
|
@ -261,8 +261,8 @@ bool CanMakeSynonymOf(opt::IRContext* ir_context,
|
|||
// We can only make a synonym of an instruction that generates an id.
|
||||
return false;
|
||||
}
|
||||
if (transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
inst->result_id())) {
|
||||
if (transformation_context.GetFactManager()->IdIsIrrelevant(inst->result_id(),
|
||||
ir_context)) {
|
||||
// An irrelevant id can't be a synonym of anything.
|
||||
return false;
|
||||
}
|
||||
|
@ -1149,7 +1149,7 @@ uint32_t MaybeGetCompositeConstant(
|
|||
if (inst.opcode() == SpvOpConstantComposite &&
|
||||
inst.type_id() == composite_type_id &&
|
||||
transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
inst.result_id()) == is_irrelevant &&
|
||||
inst.result_id(), ir_context) == is_irrelevant &&
|
||||
inst.NumInOperands() == component_ids.size()) {
|
||||
bool is_match = true;
|
||||
|
||||
|
@ -1229,7 +1229,7 @@ uint32_t MaybeGetBoolConstant(
|
|||
if (inst.opcode() == (value ? SpvOpConstantTrue : SpvOpConstantFalse) &&
|
||||
inst.type_id() == type_id &&
|
||||
transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
inst.result_id()) == is_irrelevant) {
|
||||
inst.result_id(), ir_context) == is_irrelevant) {
|
||||
return inst.result_id();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,8 @@ bool TransformationCompositeConstruct::IsApplicable(
|
|||
|
||||
// We should be able to create a synonym of |component| if it's not
|
||||
// irrelevant.
|
||||
if (!transformation_context.GetFactManager()->IdIsIrrelevant(component) &&
|
||||
if (!transformation_context.GetFactManager()->IdIsIrrelevant(component,
|
||||
ir_context) &&
|
||||
!fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context,
|
||||
inst)) {
|
||||
return false;
|
||||
|
@ -159,7 +160,7 @@ void TransformationCompositeConstruct::Apply(
|
|||
subvector_index < component_type->AsVector()->element_count();
|
||||
subvector_index++) {
|
||||
if (!transformation_context->GetFactManager()->IdIsIrrelevant(
|
||||
component)) {
|
||||
component, ir_context)) {
|
||||
transformation_context->GetFactManager()->AddFactDataSynonym(
|
||||
MakeDataDescriptor(component, {subvector_index}),
|
||||
MakeDataDescriptor(message_.fresh_id(), {index}), ir_context);
|
||||
|
@ -170,7 +171,7 @@ void TransformationCompositeConstruct::Apply(
|
|||
// 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)) {
|
||||
component, ir_context)) {
|
||||
transformation_context->GetFactManager()->AddFactDataSynonym(
|
||||
MakeDataDescriptor(component, {}),
|
||||
MakeDataDescriptor(message_.fresh_id(), {index}), ir_context);
|
||||
|
|
|
@ -56,7 +56,7 @@ bool TransformationCompositeExtract::IsApplicable(
|
|||
return false;
|
||||
}
|
||||
if (!transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
message_.composite_id()) &&
|
||||
message_.composite_id(), ir_context) &&
|
||||
!fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context,
|
||||
composite_instruction)) {
|
||||
// |composite_id| will participate in DataSynonym facts. Thus, it can't be
|
||||
|
@ -115,7 +115,7 @@ void TransformationCompositeExtract::Apply(
|
|||
// Add the fact that the id storing the extracted element is synonymous with
|
||||
// the index into the structure.
|
||||
if (!transformation_context->GetFactManager()->IdIsIrrelevant(
|
||||
message_.composite_id())) {
|
||||
message_.composite_id(), ir_context)) {
|
||||
std::vector<uint32_t> indices;
|
||||
for (auto an_index : message_.index()) {
|
||||
indices.push_back(an_index);
|
||||
|
|
|
@ -143,7 +143,7 @@ void TransformationCompositeInsert::Apply(
|
|||
|
||||
// If |composite_id| is irrelevant then don't add any synonyms.
|
||||
if (transformation_context->GetFactManager()->IdIsIrrelevant(
|
||||
message_.composite_id())) {
|
||||
message_.composite_id(), ir_context)) {
|
||||
return;
|
||||
}
|
||||
uint32_t current_node_type_id = composite_type_id;
|
||||
|
@ -184,7 +184,7 @@ void TransformationCompositeInsert::Apply(
|
|||
// 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())) {
|
||||
message_.object_id(), ir_context)) {
|
||||
transformation_context->GetFactManager()->AddFactDataSynonym(
|
||||
MakeDataDescriptor(message_.object_id(), {}),
|
||||
MakeDataDescriptor(message_.fresh_id(), std::vector<uint32_t>(index)),
|
||||
|
|
|
@ -60,7 +60,8 @@ bool TransformationEquationInstruction::IsApplicable(
|
|||
if (inst->opcode() == SpvOpUndef) {
|
||||
return false;
|
||||
}
|
||||
if (transformation_context.GetFactManager()->IdIsIrrelevant(id)) {
|
||||
if (transformation_context.GetFactManager()->IdIsIrrelevant(id,
|
||||
ir_context)) {
|
||||
return false;
|
||||
}
|
||||
if (!fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, insert_before,
|
||||
|
|
|
@ -76,7 +76,7 @@ bool TransformationPushIdThroughVariable::IsApplicable(
|
|||
|
||||
// We should be able to create a synonym of |value_id| if it's not irrelevant.
|
||||
if (!transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
message_.value_id()) &&
|
||||
message_.value_id(), ir_context) &&
|
||||
!fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context,
|
||||
value_instruction)) {
|
||||
return false;
|
||||
|
@ -154,7 +154,7 @@ void TransformationPushIdThroughVariable::Apply(
|
|||
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
|
||||
|
||||
if (!transformation_context->GetFactManager()->IdIsIrrelevant(
|
||||
message_.value_id())) {
|
||||
message_.value_id(), ir_context)) {
|
||||
// Adds the fact that |message_.value_synonym_id|
|
||||
// and |message_.value_id| are synonymous.
|
||||
transformation_context->GetFactManager()->AddFactDataSynonym(
|
||||
|
|
|
@ -41,9 +41,9 @@ bool TransformationRecordSynonymousConstants::IsApplicable(
|
|||
}
|
||||
|
||||
if (transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
message_.constant1_id()) ||
|
||||
message_.constant1_id(), ir_context) ||
|
||||
transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
message_.constant2_id())) {
|
||||
message_.constant2_id(), ir_context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,8 +37,8 @@ bool TransformationReplaceIrrelevantId::IsApplicable(
|
|||
auto id_of_interest = message_.id_use_descriptor().id_of_interest();
|
||||
|
||||
// The id must be irrelevant.
|
||||
if (!transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
id_of_interest)) {
|
||||
if (!transformation_context.GetFactManager()->IdIsIrrelevant(id_of_interest,
|
||||
ir_context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -184,7 +184,7 @@ void TransformationReplaceParameterWithGlobal::Apply(
|
|||
// Mark the pointee of the global variable storing the parameter's value as
|
||||
// irrelevant if replaced parameter is irrelevant.
|
||||
if (transformation_context->GetFactManager()->IdIsIrrelevant(
|
||||
message_.parameter_id())) {
|
||||
message_.parameter_id(), ir_context)) {
|
||||
transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
|
||||
message_.global_variable_fresh_id(), ir_context);
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ bool TransformationVectorShuffle::IsApplicable(
|
|||
}
|
||||
// We should be able to create a synonym of |vector1| if it's not irrelevant.
|
||||
if (!transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
message_.vector1()) &&
|
||||
message_.vector1(), ir_context) &&
|
||||
!fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context,
|
||||
vector1_instruction)) {
|
||||
return false;
|
||||
|
@ -72,7 +72,7 @@ bool TransformationVectorShuffle::IsApplicable(
|
|||
}
|
||||
// We should be able to create a synonym of |vector2| if it's not irrelevant.
|
||||
if (!transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
message_.vector2()) &&
|
||||
message_.vector2(), ir_context) &&
|
||||
!fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context,
|
||||
vector2_instruction)) {
|
||||
return false;
|
||||
|
@ -153,6 +153,13 @@ 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(), ir_context)) {
|
||||
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;
|
||||
|
@ -178,7 +185,7 @@ void TransformationVectorShuffle::Apply(
|
|||
GetVectorType(ir_context, message_.vector1())->element_count()) {
|
||||
// Irrelevant id cannot participate in DataSynonym facts.
|
||||
if (transformation_context->GetFactManager()->IdIsIrrelevant(
|
||||
message_.vector1())) {
|
||||
message_.vector1(), ir_context)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -187,7 +194,7 @@ void TransformationVectorShuffle::Apply(
|
|||
} else {
|
||||
// Irrelevant id cannot participate in DataSynonym facts.
|
||||
if (transformation_context->GetFactManager()->IdIsIrrelevant(
|
||||
message_.vector2())) {
|
||||
message_.vector2(), ir_context)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -1440,13 +1440,13 @@ TEST(FactManagerTest, IdIsIrrelevant) {
|
|||
|
||||
FactManager fact_manager;
|
||||
|
||||
ASSERT_FALSE(fact_manager.IdIsIrrelevant(12));
|
||||
ASSERT_FALSE(fact_manager.IdIsIrrelevant(13));
|
||||
ASSERT_FALSE(fact_manager.IdIsIrrelevant(12, context.get()));
|
||||
ASSERT_FALSE(fact_manager.IdIsIrrelevant(13, context.get()));
|
||||
|
||||
fact_manager.AddFactIdIsIrrelevant(12, context.get());
|
||||
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(12));
|
||||
ASSERT_FALSE(fact_manager.IdIsIrrelevant(13));
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(12, context.get()));
|
||||
ASSERT_FALSE(fact_manager.IdIsIrrelevant(13, context.get()));
|
||||
}
|
||||
|
||||
TEST(FactManagerTest, GetIrrelevantIds) {
|
||||
|
@ -1476,20 +1476,136 @@ TEST(FactManagerTest, GetIrrelevantIds) {
|
|||
|
||||
FactManager fact_manager;
|
||||
|
||||
ASSERT_TRUE(fact_manager.GetIrrelevantIds() ==
|
||||
std::unordered_set<uint32_t>({}));
|
||||
ASSERT_EQ(fact_manager.GetIrrelevantIds(context.get()),
|
||||
std::unordered_set<uint32_t>({}));
|
||||
|
||||
fact_manager.AddFactIdIsIrrelevant(12, context.get());
|
||||
|
||||
ASSERT_TRUE(fact_manager.GetIrrelevantIds() ==
|
||||
std::unordered_set<uint32_t>({12}));
|
||||
ASSERT_EQ(fact_manager.GetIrrelevantIds(context.get()),
|
||||
std::unordered_set<uint32_t>({12}));
|
||||
|
||||
fact_manager.AddFactIdIsIrrelevant(13, context.get());
|
||||
|
||||
ASSERT_TRUE(fact_manager.GetIrrelevantIds() ==
|
||||
std::unordered_set<uint32_t>({12, 13}));
|
||||
ASSERT_EQ(fact_manager.GetIrrelevantIds(context.get()),
|
||||
std::unordered_set<uint32_t>({12, 13}));
|
||||
}
|
||||
|
||||
TEST(FactManagerTest, BlockIsDead) {
|
||||
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 = OpTypePointer Function %7
|
||||
%2 = OpFunction %3 None %4
|
||||
%9 = OpLabel
|
||||
OpSelectionMerge %10 None
|
||||
OpBranchConditional %6 %11 %12
|
||||
%11 = OpLabel
|
||||
OpBranch %10
|
||||
%12 = OpLabel
|
||||
OpBranch %10
|
||||
%10 = 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()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
ASSERT_FALSE(fact_manager.BlockIsDead(9));
|
||||
ASSERT_FALSE(fact_manager.BlockIsDead(11));
|
||||
ASSERT_FALSE(fact_manager.BlockIsDead(12));
|
||||
|
||||
fact_manager.AddFactBlockIsDead(12);
|
||||
|
||||
ASSERT_FALSE(fact_manager.BlockIsDead(9));
|
||||
ASSERT_FALSE(fact_manager.BlockIsDead(11));
|
||||
ASSERT_TRUE(fact_manager.BlockIsDead(12));
|
||||
}
|
||||
|
||||
TEST(FactManagerTest, IdsFromDeadBlocksAreIrrelevant) {
|
||||
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 = OpTypePointer Function %7
|
||||
%9 = OpConstant %7 1
|
||||
%2 = OpFunction %3 None %4
|
||||
%10 = OpLabel
|
||||
%11 = OpVariable %8 Function
|
||||
OpSelectionMerge %12 None
|
||||
OpBranchConditional %6 %13 %14
|
||||
%13 = OpLabel
|
||||
OpBranch %12
|
||||
%14 = OpLabel
|
||||
%15 = OpCopyObject %8 %11
|
||||
%16 = OpCopyObject %7 %9
|
||||
%17 = OpFunctionCall %3 %18
|
||||
OpBranch %12
|
||||
%12 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%18 = OpFunction %3 None %4
|
||||
%19 = OpLabel
|
||||
%20 = OpVariable %8 Function
|
||||
%21 = OpCopyObject %7 %9
|
||||
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()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
ASSERT_FALSE(fact_manager.BlockIsDead(14));
|
||||
ASSERT_FALSE(fact_manager.BlockIsDead(19));
|
||||
|
||||
// Initially no id is irrelevant.
|
||||
ASSERT_FALSE(fact_manager.IdIsIrrelevant(16, context.get()));
|
||||
ASSERT_FALSE(fact_manager.IdIsIrrelevant(17, context.get()));
|
||||
ASSERT_EQ(fact_manager.GetIrrelevantIds(context.get()),
|
||||
std::unordered_set<uint32_t>({}));
|
||||
|
||||
fact_manager.AddFactBlockIsDead(14);
|
||||
|
||||
// %16 and %17 should now be considered irrelevant.
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(16, context.get()));
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(17, context.get()));
|
||||
ASSERT_EQ(fact_manager.GetIrrelevantIds(context.get()),
|
||||
std::unordered_set<uint32_t>({16, 17}));
|
||||
|
||||
// Similarly for %21.
|
||||
ASSERT_FALSE(fact_manager.IdIsIrrelevant(21, context.get()));
|
||||
|
||||
fact_manager.AddFactBlockIsDead(19);
|
||||
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(21, context.get()));
|
||||
ASSERT_EQ(fact_manager.GetIrrelevantIds(context.get()),
|
||||
std::unordered_set<uint32_t>({16, 17, 21}));
|
||||
}
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
|
|
@ -107,10 +107,10 @@ TEST(TransformationAddConstantBooleanTest, NeitherPresentInitiallyAddBoth) {
|
|||
irrelevant_false.Apply(context.get(), &transformation_context);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_FALSE(fact_manager.IdIsIrrelevant(100));
|
||||
ASSERT_FALSE(fact_manager.IdIsIrrelevant(101));
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(102));
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(103));
|
||||
ASSERT_FALSE(fact_manager.IdIsIrrelevant(100, context.get()));
|
||||
ASSERT_FALSE(fact_manager.IdIsIrrelevant(101, context.get()));
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(102, context.get()));
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(103, context.get()));
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
|
|
|
@ -135,11 +135,11 @@ TEST(TransformationAddConstantCompositeTest, BasicTest) {
|
|||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
for (uint32_t id = 100; id <= 106; ++id) {
|
||||
ASSERT_FALSE(fact_manager.IdIsIrrelevant(id));
|
||||
ASSERT_FALSE(fact_manager.IdIsIrrelevant(id, context.get()));
|
||||
}
|
||||
|
||||
for (uint32_t id = 107; id <= 113; ++id) {
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(id));
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(id, context.get()));
|
||||
}
|
||||
|
||||
std::string after_transformation = R"(
|
||||
|
|
|
@ -272,11 +272,11 @@ TEST(TransformationAddConstantScalarTest, Apply) {
|
|||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
for (uint32_t result_id = 19; result_id <= 24; ++result_id) {
|
||||
ASSERT_FALSE(fact_manager.IdIsIrrelevant(result_id));
|
||||
ASSERT_FALSE(fact_manager.IdIsIrrelevant(result_id, context.get()));
|
||||
}
|
||||
|
||||
for (uint32_t result_id = 25; result_id <= 30; ++result_id) {
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(result_id));
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(result_id, context.get()));
|
||||
}
|
||||
|
||||
std::string variant_shader = R"(
|
||||
|
|
|
@ -136,28 +136,28 @@ TEST(TransformationAddParameterTest, NonPointerBasicTest) {
|
|||
ASSERT_TRUE(correct.IsApplicable(context.get(), transformation_context));
|
||||
correct.Apply(context.get(), &transformation_context);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(60));
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(60, context.get()));
|
||||
}
|
||||
{
|
||||
TransformationAddParameter correct(17, 62, 7, {{}}, 63);
|
||||
ASSERT_TRUE(correct.IsApplicable(context.get(), transformation_context));
|
||||
correct.Apply(context.get(), &transformation_context);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(62));
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(62, context.get()));
|
||||
}
|
||||
{
|
||||
TransformationAddParameter correct(29, 64, 31, {{}}, 65);
|
||||
ASSERT_TRUE(correct.IsApplicable(context.get(), transformation_context));
|
||||
correct.Apply(context.get(), &transformation_context);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(64));
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(64, context.get()));
|
||||
}
|
||||
{
|
||||
TransformationAddParameter correct(34, 66, 7, {{}}, 67);
|
||||
ASSERT_TRUE(correct.IsApplicable(context.get(), transformation_context));
|
||||
correct.Apply(context.get(), &transformation_context);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(66));
|
||||
ASSERT_TRUE(fact_manager.IdIsIrrelevant(66, context.get()));
|
||||
}
|
||||
|
||||
std::string expected_shader = R"(
|
||||
|
|
|
@ -490,7 +490,8 @@ TEST(TransformationFlattenConditionalBranchTest, LoadStoreFunctionCall) {
|
|||
transformation1.Apply(context.get(), &transformation_context);
|
||||
|
||||
// Check that the placeholder id was marked as irrelevant.
|
||||
ASSERT_TRUE(transformation_context.GetFactManager()->IdIsIrrelevant(103));
|
||||
ASSERT_TRUE(transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
103, context.get()));
|
||||
|
||||
// Make a new transformation context with a source of overflow ids.
|
||||
TransformationContext new_transformation_context(
|
||||
|
|
Загрузка…
Ссылка в новой задаче