spirv-fuzz: better computation of data synonym facts (#3010)

When a data synonym fact about two composites is added, data synonym
facts between all sub-components of the composites are also added.

Furthermore, when data synonym facts been all sub-components of two
composites are known, a data synonym fact relating the two composites
is added. Identification of this case is done in a lazy manner, when
questions about data synonym facts are asked.

The change introduces helper methods to get the size of an array type
and the number of elements of a struct type, and fixes
TransformationCompositeExtract to invalidate analyses appropriately.
This commit is contained in:
Alastair Donaldson 2019-11-05 16:45:14 +00:00 committed by GitHub
parent fb6bac889e
commit 3724cfbea8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1162 additions and 214 deletions

View File

@ -14,8 +14,9 @@
#include "source/fuzz/fact_manager.h"
#include <map>
#include <sstream>
#include <unordered_map>
#include <unordered_set>
#include "source/fuzz/equivalence_relation.h"
#include "source/fuzz/fuzzer_util.h"
@ -29,7 +30,7 @@ namespace {
std::string ToString(const protobufs::Fact& fact) {
assert(fact.fact_case() == protobufs::Fact::kConstantUniformFact &&
"Right now this is the only fact.");
"Right now this is the only fact we know how to stringify.");
std::stringstream stream;
stream << "("
<< fact.constant_uniform_fact()
@ -74,9 +75,10 @@ std::string ToString(const protobufs::Fact& fact) {
//=======================
// Constant uniform facts
// The purpose of this struct is to group the fields and data used to represent
// The purpose of this class is to group the fields and data used to represent
// facts about uniform constants.
struct FactManager::ConstantUniformFacts {
class FactManager::ConstantUniformFacts {
public:
// See method in FactManager which delegates to this method.
bool AddFact(const protobufs::FactConstantUniform& fact,
opt::IRContext* context);
@ -99,6 +101,11 @@ struct FactManager::ConstantUniformFacts {
// See method in FactManager which delegates to this method.
std::vector<uint32_t> GetTypesForWhichUniformValuesAreKnown() const;
// See method in FactManager which delegates to this method.
const std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>&
GetConstantUniformFactsAndTypes() const;
private:
// Returns true if and only if the words associated with
// |constant_instruction| exactly match the words for the constant associated
// with |constant_uniform_fact|.
@ -124,7 +131,7 @@ struct FactManager::ConstantUniformFacts {
uint32_t width) const;
std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>
facts_and_type_ids;
facts_and_type_ids_;
};
uint32_t FactManager::ConstantUniformFacts::GetConstantId(
@ -163,7 +170,7 @@ FactManager::ConstantUniformFacts::GetConstantsAvailableFromUniformsForType(
opt::IRContext* ir_context, uint32_t type_id) const {
std::vector<uint32_t> result;
std::set<uint32_t> already_seen;
for (auto& fact_and_type_id : facts_and_type_ids) {
for (auto& fact_and_type_id : facts_and_type_ids_) {
if (fact_and_type_id.second != type_id) {
continue;
}
@ -186,7 +193,7 @@ FactManager::ConstantUniformFacts::GetUniformDescriptorsForConstant(
assert(constant_inst->opcode() == SpvOpConstant &&
"The given id must be that of a constant");
auto type_id = constant_inst->type_id();
for (auto& fact_and_type_id : facts_and_type_ids) {
for (auto& fact_and_type_id : facts_and_type_ids_) {
if (fact_and_type_id.second != type_id) {
continue;
}
@ -202,7 +209,7 @@ uint32_t FactManager::ConstantUniformFacts::GetConstantFromUniformDescriptor(
opt::IRContext* context,
const protobufs::UniformBufferElementDescriptor& uniform_descriptor) const {
// Consider each fact.
for (auto& fact_and_type : facts_and_type_ids) {
for (auto& fact_and_type : facts_and_type_ids_) {
// Check whether the uniform descriptor associated with the fact matches
// |uniform_descriptor|.
if (UniformBufferElementDescriptorEquals()(
@ -219,7 +226,7 @@ std::vector<uint32_t>
FactManager::ConstantUniformFacts::GetTypesForWhichUniformValuesAreKnown()
const {
std::vector<uint32_t> result;
for (auto& fact_and_type : facts_and_type_ids) {
for (auto& fact_and_type : facts_and_type_ids_) {
if (std::find(result.begin(), result.end(), fact_and_type.second) ==
result.end()) {
result.push_back(fact_and_type.second);
@ -309,44 +316,485 @@ bool FactManager::ConstantUniformFacts::AddFact(
if (static_cast<uint32_t>(fact.constant_word().size()) != required_words) {
return false;
}
facts_and_type_ids.emplace_back(
facts_and_type_ids_.emplace_back(
std::pair<protobufs::FactConstantUniform, uint32_t>(
fact, final_element_type_id));
return true;
}
const std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>&
FactManager::ConstantUniformFacts::GetConstantUniformFactsAndTypes() const {
return facts_and_type_ids_;
}
// End of uniform constant facts
//==============================
//==============================
// Data synonym facts
// The purpose of this struct is to group the fields and data used to represent
// The purpose of this class is to group the fields and data used to represent
// facts about data synonyms.
struct FactManager::DataSynonymFacts {
class FactManager::DataSynonymFacts {
public:
// See method in FactManager which delegates to this method.
void AddFact(const protobufs::FactDataSynonym& fact);
void AddFact(const protobufs::FactDataSynonym& fact, opt::IRContext* context);
// See method in FactManager which delegates to this method.
std::vector<const protobufs::DataDescriptor*> GetSynonymsForDataDescriptor(
const protobufs::DataDescriptor& data_descriptor,
opt::IRContext* context) const;
// See method in FactManager which delegates to this method.
std::vector<uint32_t> GetIdsForWhichSynonymsAreKnown(
opt::IRContext* context) const;
// See method in FactManager which delegates to this method.
bool IsSynonymous(const protobufs::DataDescriptor& data_descriptor1,
const protobufs::DataDescriptor& data_descriptor2) const;
const protobufs::DataDescriptor& data_descriptor2,
opt::IRContext* context) const;
EquivalenceRelation<protobufs::DataDescriptor, DataDescriptorHash,
DataDescriptorEquals>
synonymous;
private:
// Adds |fact| to the set of managed facts, and recurses into sub-components
// of the data descriptors referenced in |fact|, if they are composites, to
// record that their components are pairwise-synonymous.
void AddFactRecursive(const protobufs::FactDataSynonym& fact,
opt::IRContext* context);
// Inspects all known facts and adds corollary facts; e.g. if we know that
// a.x == b.x and a.y == b.y, where a and b have vec2 type, we can record
// that a == b holds.
//
// This method is expensive, and is thus called on demand: rather than
// computing the closure of facts each time a data synonym fact is added, we
// compute the closure only when a data synonym fact is *queried*.
void ComputeClosureOfFacts(opt::IRContext* context) const;
// Returns true if and only if |dd1| and |dd2| are valid data descriptors
// whose associated data have the same type.
bool DataDescriptorsAreWellFormedAndComparable(
opt::IRContext* context, const protobufs::DataDescriptor& dd1,
const protobufs::DataDescriptor& dd2) const;
// The data descriptors that are known to be synonymous with one another are
// captured by this equivalence relation.
//
// This member is mutable in order to allow the closure of facts captured by
// the relation to be computed lazily when a question about data synonym
// facts is asked.
mutable EquivalenceRelation<protobufs::DataDescriptor, DataDescriptorHash,
DataDescriptorEquals>
synonymous_;
// When a new synonym fact is added, it may be possible to deduce further
// synonym facts by computing a closure of all known facts. However, there is
// no point computing this closure until a question regarding synonym facts is
// actually asked: if several facts are added in succession with no questions
// asked in between, we can avoid computing fact closures multiple times.
//
// This boolean tracks whether a closure computation is required - i.e.,
// whether a new fact has been added since the last time such a computation
// was performed.
//
// It is mutable so faciliate having const methods, that provide answers to
// questions about data synonym facts, triggering closure computation on
// demand.
mutable bool closure_computation_required = false;
};
void FactManager::DataSynonymFacts::AddFact(
const protobufs::FactDataSynonym& fact) {
synonymous.MakeEquivalent(fact.data1(), fact.data2());
const protobufs::FactDataSynonym& fact, opt::IRContext* context) {
// Add the fact, including all facts relating sub-components of the data
// descriptors that are involved.
AddFactRecursive(fact, context);
}
void FactManager::DataSynonymFacts::AddFactRecursive(
const protobufs::FactDataSynonym& fact, opt::IRContext* context) {
assert(DataDescriptorsAreWellFormedAndComparable(context, fact.data1(),
fact.data2()));
// Record that the data descriptors provided in the fact are equivalent.
synonymous_.MakeEquivalent(fact.data1(), fact.data2());
// As we have updated the equivalence relation, we might be able to deduce
// more facts by performing a closure computation, so we record that such a
// computation is required; it will be performed next time a method answering
// a data synonym fact-related question is invoked.
closure_computation_required = true;
// We now check whether this is a synonym about composite objects. If it is,
// we can recursively add synonym facts about their associated sub-components.
// Get the type of the object referred to by the first data descriptor in the
// synonym fact.
uint32_t type_id = fuzzerutil::WalkCompositeTypeIndices(
context,
context->get_def_use_mgr()->GetDef(fact.data1().object())->type_id(),
fact.data1().index());
auto type = context->get_type_mgr()->GetType(type_id);
auto type_instruction = context->get_def_use_mgr()->GetDef(type_id);
assert(type != nullptr &&
"Invalid data synonym fact: one side has an unknown type.");
// Check whether the type is composite, recording the number of elements
// associated with the composite if so.
uint32_t num_composite_elements;
if (type->AsArray()) {
num_composite_elements =
fuzzerutil::GetArraySize(*type_instruction, context);
} else if (type->AsMatrix()) {
num_composite_elements = type->AsMatrix()->element_count();
} else if (type->AsStruct()) {
num_composite_elements =
fuzzerutil::GetNumberOfStructMembers(*type_instruction);
} else if (type->AsVector()) {
num_composite_elements = type->AsVector()->element_count();
} else {
// The type is not a composite, so return.
return;
}
// If the fact has the form:
// obj_1[a_1, ..., a_m] == obj_2[b_1, ..., b_n]
// then for each composite index i, we add a fact of the form:
// obj_1[a_1, ..., a_m, i] == obj_2[b_1, ..., b_n, i]
for (uint32_t i = 0; i < num_composite_elements; i++) {
std::vector<uint32_t> extended_indices1 =
fuzzerutil::RepeatedFieldToVector(fact.data1().index());
extended_indices1.push_back(i);
std::vector<uint32_t> extended_indices2 =
fuzzerutil::RepeatedFieldToVector(fact.data2().index());
extended_indices2.push_back(i);
protobufs::FactDataSynonym extended_data_synonym_fact;
*extended_data_synonym_fact.mutable_data1() =
MakeDataDescriptor(fact.data1().object(), std::move(extended_indices1));
*extended_data_synonym_fact.mutable_data2() =
MakeDataDescriptor(fact.data2().object(), std::move(extended_indices2));
AddFactRecursive(extended_data_synonym_fact, context);
}
}
void FactManager::DataSynonymFacts::ComputeClosureOfFacts(
opt::IRContext* context) const {
// Suppose that obj_1[a_1, ..., a_m] and obj_2[b_1, ..., b_n] are distinct
// data descriptors that describe objects of the same composite type, and that
// the composite type is comprised of k components.
//
// For example, if m is a mat4x4 and v a vec4, we might consider:
// m[2]: describes the 2nd column of m, a vec4
// v[]: describes all of v, a vec4
//
// Suppose that we know, for every 0 <= i < k, that the fact:
// obj_1[a_1, ..., a_m, i] == obj_2[b_1, ..., b_n, i]
// holds - i.e. that the children of the two data descriptors are synonymous.
//
// Then we can conclude that:
// obj_1[a_1, ..., a_m] == obj_2[b_1, ..., b_n]
// holds.
//
// For instance, if we have the facts:
// m[2, 0] == v[0]
// m[2, 1] == v[1]
// m[2, 2] == v[2]
// m[2, 3] == v[3]
// then we can conclude that:
// m[2] == v.
//
// This method repeatedly searches the equivalence relation of data
// descriptors, deducing and adding such facts, until a pass over the
// relation leads to no further facts being deduced.
// The method relies on working with pairs of data descriptors, and in
// particular being able to hash and compare such pairs.
using DataDescriptorPair =
std::pair<protobufs::DataDescriptor, protobufs::DataDescriptor>;
struct DataDescriptorPairHash {
std::size_t operator()(const DataDescriptorPair& pair) const {
return DataDescriptorHash()(&pair.first) ^
DataDescriptorHash()(&pair.second);
}
};
struct DataDescriptorPairEquals {
bool operator()(const DataDescriptorPair& first,
const DataDescriptorPair& second) const {
return DataDescriptorEquals()(&first.first, &second.first) &&
DataDescriptorEquals()(&first.second, &second.second);
}
};
// This map records, for a given pair of composite data descriptors of the
// same type, all the indices at which the data descriptors are known to be
// synonymous. A pair is a key to this map only if we have observed that
// the pair are synonymous at *some* index, but not at *all* indices.
// Once we find that a pair of data descriptors are equivalent at all indices
// we record the fact that they are synonymous and remove them from the map.
//
// Using the m and v example from above, initially the pair (m[2], v) would
// not be a key to the map. If we find that m[2, 2] == v[2] holds, we would
// add an entry:
// (m[2], v) -> [false, false, true, false]
// to record that they are synonymous at index 2. If we then find that
// m[2, 0] == v[0] holds, we would update this entry to:
// (m[2], v) -> [true, false, true, false]
// If we then find that m[2, 3] == v[3] holds, we would update this entry to:
// (m[2], v) -> [true, false, true, true]
// Finally, if we then find that m[2, 1] == v[1] holds, which would make the
// boolean vector true at every index, we would add the fact:
// m[2] == v
// to the equivalence relation and remove (m[2], v) from the map.
std::unordered_map<DataDescriptorPair, std::vector<bool>,
DataDescriptorPairHash, DataDescriptorPairEquals>
candidate_composite_synonyms;
// We keep looking for new facts until we perform a complete pass over the
// equivalence relation without finding any new facts.
while (closure_computation_required) {
// We have not found any new facts yet during this pass; we set this to
// 'true' if we do find a new fact.
closure_computation_required = false;
// Consider each class in the equivalence relation.
for (auto representative :
synonymous_.GetEquivalenceClassRepresentatives()) {
auto equivalence_class = synonymous_.GetEquivalenceClass(*representative);
// Consider every data descriptor in the equivalence class.
for (auto dd1_it = equivalence_class.begin();
dd1_it != equivalence_class.end(); ++dd1_it) {
// If this data descriptor has no indices then it does not have the form
// obj_1[a_1, ..., a_m, i], so move on.
auto dd1 = *dd1_it;
if (dd1->index_size() == 0) {
continue;
}
// Consider every other data descriptor later in the equivalence class
// (due to symmetry, there is no need to compare with previous data
// descriptors).
auto dd2_it = dd1_it;
for (++dd2_it; dd2_it != equivalence_class.end(); ++dd2_it) {
auto dd2 = *dd2_it;
// If this data descriptor has no indices then it does not have the
// form obj_2[b_1, ..., b_n, i], so move on.
if (dd2->index_size() == 0) {
continue;
}
// At this point we know that:
// - |dd1| has the form obj_1[a_1, ..., a_m, i]
// - |dd2| has the form obj_2[b_1, ..., b_n, j]
assert(dd1->index_size() > 0 && dd2->index_size() > 0 &&
"Control should not reach here if either data descriptor has "
"no indices.");
// We are only interested if i == j.
if (dd1->index(dd1->index_size() - 1) !=
dd2->index(dd2->index_size() - 1)) {
continue;
}
const uint32_t common_final_index = dd1->index(dd1->index_size() - 1);
// Make data descriptors |dd1_prefix| and |dd2_prefix| for
// obj_1[a_1, ..., a_m]
// and
// obj_2[b_1, ..., b_n]
// These are the two data descriptors we might be getting closer to
// deducing as being synonymous, due to knowing that they are
// synonymous when extended by a particular index.
protobufs::DataDescriptor dd1_prefix;
dd1_prefix.set_object(dd1->object());
for (uint32_t i = 0; i < static_cast<uint32_t>(dd1->index_size() - 1);
i++) {
dd1_prefix.add_index(dd1->index(i));
}
protobufs::DataDescriptor dd2_prefix;
dd2_prefix.set_object(dd2->object());
for (uint32_t i = 0; i < static_cast<uint32_t>(dd2->index_size() - 1);
i++) {
dd2_prefix.add_index(dd2->index(i));
}
assert(!DataDescriptorEquals()(&dd1_prefix, &dd2_prefix) &&
"By construction these prefixes should be different.");
// If we already know that these prefixes are synonymous, move on.
if (synonymous_.Exists(dd1_prefix) &&
synonymous_.Exists(dd2_prefix) &&
synonymous_.IsEquivalent(dd1_prefix, dd2_prefix)) {
continue;
}
// Get the type of obj_1
auto dd1_root_type_id =
context->get_def_use_mgr()->GetDef(dd1->object())->type_id();
// Use this type, together with a_1, ..., a_m, to get the type of
// obj_1[a_1, ..., a_m].
auto dd1_prefix_type = fuzzerutil::WalkCompositeTypeIndices(
context, dd1_root_type_id, dd1_prefix.index());
// Similarly, get the type of obj_2 and use it to get the type of
// obj_2[b_1, ..., b_n].
auto dd2_root_type_id =
context->get_def_use_mgr()->GetDef(dd2->object())->type_id();
auto dd2_prefix_type = fuzzerutil::WalkCompositeTypeIndices(
context, dd2_root_type_id, dd2_prefix.index());
// If the types of dd1_prefix and dd2_prefix are not the same, they
// cannot be synonymous.
if (dd1_prefix_type != dd2_prefix_type) {
continue;
}
// At this point, we know we have synonymous data descriptors of the
// form:
// obj_1[a_1, ..., a_m, i]
// obj_2[b_1, ..., b_n, i]
// with the same last_index i, such that:
// obj_1[a_1, ..., a_m]
// and
// obj_2[b_1, ..., b_n]
// have the same type.
// Work out how many components there are in the (common) commposite
// type associated with obj_1[a_1, ..., a_m] and obj_2[b_1, ..., b_n].
// This depends on whether the composite type is array, matrix, struct
// or vector.
uint32_t num_components_in_composite;
auto composite_type =
context->get_type_mgr()->GetType(dd1_prefix_type);
auto composite_type_instruction =
context->get_def_use_mgr()->GetDef(dd1_prefix_type);
if (composite_type->AsArray()) {
num_components_in_composite =
fuzzerutil::GetArraySize(*composite_type_instruction, context);
if (num_components_in_composite == 0) {
// This indicates that the array has an unknown size, in which
// case we cannot be sure we have matched all of its elements with
// synonymous elements of another array.
continue;
}
} else if (composite_type->AsMatrix()) {
num_components_in_composite =
composite_type->AsMatrix()->element_count();
} else if (composite_type->AsStruct()) {
num_components_in_composite = fuzzerutil::GetNumberOfStructMembers(
*composite_type_instruction);
} else {
assert(composite_type->AsVector());
num_components_in_composite =
composite_type->AsVector()->element_count();
}
// We are one step closer to being able to say that |dd1_prefix| and
// |dd2_prefix| are synonymous.
DataDescriptorPair candidate_composite_synonym(dd1_prefix,
dd2_prefix);
// We look up what we already know about this pair.
auto existing_entry =
candidate_composite_synonyms.find(candidate_composite_synonym);
if (existing_entry == candidate_composite_synonyms.end()) {
// If this is the first time we have seen the pair, we make a vector
// of size |num_components_in_composite| that is 'true' at the
// common final index associated with |dd1| and |dd2|, and 'false'
// everywhere else, and register this vector as being associated
// with the pair.
std::vector<bool> entry;
for (uint32_t i = 0; i < num_components_in_composite; i++) {
entry.push_back(i == common_final_index);
}
candidate_composite_synonyms[candidate_composite_synonym] = entry;
existing_entry =
candidate_composite_synonyms.find(candidate_composite_synonym);
} else {
// We have seen this pair of data descriptors before, and we now
// know that they are synonymous at one further index, so we
// update the entry to record that.
existing_entry->second[common_final_index] = true;
}
assert(existing_entry != candidate_composite_synonyms.end());
// Check whether |dd1_prefix| and |dd2_prefix| are now known to match
// at every sub-component.
bool all_components_match = true;
for (uint32_t i = 0; i < num_components_in_composite; i++) {
if (!existing_entry->second[i]) {
all_components_match = false;
break;
}
}
if (all_components_match) {
// The two prefixes match on all sub-components, so we know that
// they are synonymous. We add this fact *non-recursively*, as we
// have deduced that |dd1_prefix| and |dd2_prefix| are synonymous
// by observing that all their sub-components are already
// synonymous.
assert(DataDescriptorsAreWellFormedAndComparable(
context, dd1_prefix, dd2_prefix));
synonymous_.MakeEquivalent(dd1_prefix, dd2_prefix);
// As we have added a new synonym fact, we might benefit from doing
// another pass over the equivalence relation.
closure_computation_required = true;
// Now that we know this pair of data descriptors are synonymous,
// there is no point recording how close they are to being
// synonymous.
candidate_composite_synonyms.erase(candidate_composite_synonym);
}
}
}
}
}
}
bool FactManager::DataSynonymFacts::DataDescriptorsAreWellFormedAndComparable(
opt::IRContext* context, const protobufs::DataDescriptor& dd1,
const protobufs::DataDescriptor& dd2) const {
auto end_type_1 = fuzzerutil::WalkCompositeTypeIndices(
context, context->get_def_use_mgr()->GetDef(dd1.object())->type_id(),
dd1.index());
auto end_type_2 = fuzzerutil::WalkCompositeTypeIndices(
context, context->get_def_use_mgr()->GetDef(dd2.object())->type_id(),
dd2.index());
return end_type_1 && end_type_1 == end_type_2;
}
std::vector<const protobufs::DataDescriptor*>
FactManager::DataSynonymFacts::GetSynonymsForDataDescriptor(
const protobufs::DataDescriptor& data_descriptor,
opt::IRContext* context) const {
ComputeClosureOfFacts(context);
if (synonymous_.Exists(data_descriptor)) {
return synonymous_.GetEquivalenceClass(data_descriptor);
}
return std::vector<const protobufs::DataDescriptor*>();
}
std::vector<uint32_t>
FactManager::DataSynonymFacts ::GetIdsForWhichSynonymsAreKnown(
opt::IRContext* context) const {
ComputeClosureOfFacts(context);
std::vector<uint32_t> result;
for (auto& data_descriptor : synonymous_.GetAllKnownValues()) {
if (data_descriptor->index().empty()) {
result.push_back(data_descriptor->object());
}
}
return result;
}
bool FactManager::DataSynonymFacts::IsSynonymous(
const protobufs::DataDescriptor& data_descriptor1,
const protobufs::DataDescriptor& data_descriptor2) const {
return synonymous.Exists(data_descriptor1) &&
synonymous.Exists(data_descriptor2) &&
synonymous.IsEquivalent(data_descriptor1, data_descriptor2);
const protobufs::DataDescriptor& data_descriptor2,
opt::IRContext* context) const {
const_cast<FactManager::DataSynonymFacts*>(this)->ComputeClosureOfFacts(
context);
return synonymous_.Exists(data_descriptor1) &&
synonymous_.Exists(data_descriptor2) &&
synonymous_.IsEquivalent(data_descriptor1, data_descriptor2);
}
// End of data synonym facts
@ -377,7 +825,7 @@ bool FactManager::AddFact(const fuzz::protobufs::Fact& fact,
return uniform_constant_facts_->AddFact(fact.constant_uniform_fact(),
context);
case protobufs::Fact::kDataSynonymFact:
data_synonym_facts_->AddFact(fact.data_synonym_fact());
data_synonym_facts_->AddFact(fact.data_synonym_fact(), context);
return true;
default:
assert(false && "Unknown fact type.");
@ -387,11 +835,11 @@ bool FactManager::AddFact(const fuzz::protobufs::Fact& fact,
void FactManager::AddFactDataSynonym(const protobufs::DataDescriptor& data1,
const protobufs::DataDescriptor& data2,
opt::IRContext* /*unused*/) {
opt::IRContext* context) {
protobufs::FactDataSynonym fact;
*fact.mutable_data1() = data1;
*fact.mutable_data2() = data2;
data_synonym_facts_->AddFact(fact);
data_synonym_facts_->AddFact(fact, context);
}
std::vector<uint32_t> FactManager::GetConstantsAvailableFromUniformsForType(
@ -421,30 +869,33 @@ std::vector<uint32_t> FactManager::GetTypesForWhichUniformValuesAreKnown()
const std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>&
FactManager::GetConstantUniformFactsAndTypes() const {
return uniform_constant_facts_->facts_and_type_ids;
return uniform_constant_facts_->GetConstantUniformFactsAndTypes();
}
std::vector<uint32_t> FactManager::GetIdsForWhichSynonymsAreKnown() const {
std::vector<uint32_t> result;
for (auto& data_descriptor :
data_synonym_facts_->synonymous.GetAllKnownValues()) {
if (data_descriptor->index().empty()) {
result.push_back(data_descriptor->object());
}
}
return result;
std::vector<uint32_t> FactManager::GetIdsForWhichSynonymsAreKnown(
opt::IRContext* context) const {
return data_synonym_facts_->GetIdsForWhichSynonymsAreKnown(context);
}
std::vector<const protobufs::DataDescriptor*>
FactManager::GetSynonymsForDataDescriptor(
const protobufs::DataDescriptor& data_descriptor,
opt::IRContext* context) const {
return data_synonym_facts_->GetSynonymsForDataDescriptor(data_descriptor,
context);
}
std::vector<const protobufs::DataDescriptor*> FactManager::GetSynonymsForId(
uint32_t id) const {
return data_synonym_facts_->synonymous.GetEquivalenceClass(
MakeDataDescriptor(id, {}));
uint32_t id, opt::IRContext* context) const {
return GetSynonymsForDataDescriptor(MakeDataDescriptor(id, {}), context);
}
bool FactManager::IsSynonymous(
const protobufs::DataDescriptor& data_descriptor1,
const protobufs::DataDescriptor& data_descriptor2) const {
return data_synonym_facts_->IsSynonymous(data_descriptor1, data_descriptor2);
const protobufs::DataDescriptor& data_descriptor2,
opt::IRContext* context) const {
return data_synonym_facts_->IsSynonymous(data_descriptor1, data_descriptor2,
context);
};
} // namespace fuzz

View File

@ -105,34 +105,41 @@ class FactManager {
//==============================
// Querying facts about id synonyms
// Returns every id for which a fact of the form "this id is synonymous
// with this piece of data" is known.
std::vector<uint32_t> GetIdsForWhichSynonymsAreKnown() const;
// Returns every id for which a fact of the form "this id is synonymous with
// this piece of data" is known.
std::vector<uint32_t> GetIdsForWhichSynonymsAreKnown(
opt::IRContext* context) const;
// Returns the equivalence class of all known synonyms of |id|, or an empty
// set if no synonyms are known.
std::vector<const protobufs::DataDescriptor*> GetSynonymsForId(
uint32_t id) const;
uint32_t id, opt::IRContext* context) const;
// Return true if and ony if |data_descriptor1| and |data_descriptor2| are
// Returns the equivalence class of all known synonyms of |data_descriptor|,
// or empty if no synonyms are known.
std::vector<const protobufs::DataDescriptor*> GetSynonymsForDataDescriptor(
const protobufs::DataDescriptor& data_descriptor,
opt::IRContext* context) const;
// Returns true if and ony if |data_descriptor1| and |data_descriptor2| are
// known to be synonymous.
bool IsSynonymous(const protobufs::DataDescriptor& data_descriptor1,
const protobufs::DataDescriptor& data_descriptor2) const;
const protobufs::DataDescriptor& data_descriptor2,
opt::IRContext* context) const;
// End of id synonym facts
//==============================
private:
// For each distinct kind of fact to be managed, we use a separate opaque
// struct type.
// class type.
struct ConstantUniformFacts; // Opaque class for management of
// constant uniform facts.
class ConstantUniformFacts; // Opaque class for management of
// constant uniform facts.
std::unique_ptr<ConstantUniformFacts>
uniform_constant_facts_; // Unique pointer to internal data.
struct DataSynonymFacts; // Opaque class for management of data synonym
// facts.
class DataSynonymFacts; // Opaque class for management of data synonym facts.
std::unique_ptr<DataSynonymFacts>
data_synonym_facts_; // Unique pointer to internal data.
};

View File

@ -32,7 +32,7 @@ void FuzzerPassApplyIdSynonyms::Apply() {
std::vector<TransformationReplaceIdWithSynonym> transformations_to_apply;
for (auto id_with_known_synonyms :
GetFactManager()->GetIdsForWhichSynonymsAreKnown()) {
GetFactManager()->GetIdsForWhichSynonymsAreKnown(GetIRContext())) {
GetIRContext()->get_def_use_mgr()->ForEachUse(
id_with_known_synonyms,
[this, id_with_known_synonyms, &transformations_to_apply](
@ -54,8 +54,8 @@ void FuzzerPassApplyIdSynonyms::Apply() {
use_index - use_inst->NumOperands() + use_inst->NumInOperands();
std::vector<const protobufs::DataDescriptor*> synonyms_to_try;
for (auto& data_descriptor :
GetFactManager()->GetSynonymsForId(id_with_known_synonyms)) {
for (auto& data_descriptor : GetFactManager()->GetSynonymsForId(
id_with_known_synonyms, GetIRContext())) {
synonyms_to_try.push_back(data_descriptor);
}
while (!synonyms_to_try.empty()) {

View File

@ -330,6 +330,15 @@ bool IsCompositeType(const opt::analysis::Type* type) {
type->AsVector());
}
std::vector<uint32_t> RepeatedFieldToVector(
const google::protobuf::RepeatedField<uint32_t>& repeated_field) {
std::vector<uint32_t> result;
for (auto i : repeated_field) {
result.push_back(i);
}
return result;
}
uint32_t WalkCompositeTypeIndices(
opt::IRContext* context, uint32_t base_object_type_id,
const google::protobuf::RepeatedField<google::protobuf::uint32>& indices) {
@ -338,29 +347,9 @@ uint32_t WalkCompositeTypeIndices(
auto should_be_composite_type =
context->get_def_use_mgr()->GetDef(sub_object_type_id);
assert(should_be_composite_type && "The type should exist.");
if (SpvOpTypeStruct == should_be_composite_type->opcode()) {
if (index >= should_be_composite_type->NumInOperands()) {
return 0;
}
sub_object_type_id =
should_be_composite_type->GetSingleWordInOperand(index);
} else if (SpvOpTypeArray == should_be_composite_type->opcode()) {
auto array_length_constant =
context->get_constant_mgr()
->GetConstantFromInst(context->get_def_use_mgr()->GetDef(
should_be_composite_type->GetSingleWordInOperand(1)))
->AsIntConstant();
if (array_length_constant->words().size() != 1) {
return 0;
}
auto array_length = array_length_constant->GetU32();
if (index >= array_length) {
return 0;
}
sub_object_type_id = should_be_composite_type->GetSingleWordInOperand(0);
} else if (SpvOpTypeVector == should_be_composite_type->opcode()) {
auto vector_length = should_be_composite_type->GetSingleWordInOperand(1);
if (index >= vector_length) {
if (SpvOpTypeArray == should_be_composite_type->opcode()) {
auto array_length = GetArraySize(*should_be_composite_type, context);
if (array_length == 0 || index >= array_length) {
return 0;
}
sub_object_type_id = should_be_composite_type->GetSingleWordInOperand(0);
@ -371,6 +360,18 @@ uint32_t WalkCompositeTypeIndices(
return 0;
}
sub_object_type_id = should_be_composite_type->GetSingleWordInOperand(0);
} else if (SpvOpTypeStruct == should_be_composite_type->opcode()) {
if (index >= GetNumberOfStructMembers(*should_be_composite_type)) {
return 0;
}
sub_object_type_id =
should_be_composite_type->GetSingleWordInOperand(index);
} else if (SpvOpTypeVector == should_be_composite_type->opcode()) {
auto vector_length = should_be_composite_type->GetSingleWordInOperand(1);
if (index >= vector_length) {
return 0;
}
sub_object_type_id = should_be_composite_type->GetSingleWordInOperand(0);
} else {
return 0;
}
@ -378,6 +379,26 @@ uint32_t WalkCompositeTypeIndices(
return sub_object_type_id;
}
uint32_t GetNumberOfStructMembers(
const opt::Instruction& struct_type_instruction) {
assert(struct_type_instruction.opcode() == SpvOpTypeStruct &&
"An OpTypeStruct instruction is required here.");
return struct_type_instruction.NumInOperands();
}
uint32_t GetArraySize(const opt::Instruction& array_type_instruction,
opt::IRContext* context) {
auto array_length_constant =
context->get_constant_mgr()
->GetConstantFromInst(context->get_def_use_mgr()->GetDef(
array_type_instruction.GetSingleWordInOperand(1)))
->AsIntConstant();
if (array_length_constant->words().size() != 1) {
return 0;
}
return array_length_constant->GetU32();
}
} // namespace fuzzerutil
} // namespace fuzz

View File

@ -94,6 +94,10 @@ bool CanMakeSynonymOf(opt::IRContext* ir_context, opt::Instruction* inst);
// struct or vector.
bool IsCompositeType(const opt::analysis::Type* type);
// Returns a vector containing the same elements as |repeated_field|.
std::vector<uint32_t> RepeatedFieldToVector(
const google::protobuf::RepeatedField<uint32_t>& repeated_field);
// Given a type id, |base_object_type_id|, checks that the given sequence of
// |indices| is suitable for indexing into this type. Returns the id of the
// type of the final sub-object reached via the indices if they are valid, and
@ -102,6 +106,17 @@ uint32_t WalkCompositeTypeIndices(
opt::IRContext* context, uint32_t base_object_type_id,
const google::protobuf::RepeatedField<google::protobuf::uint32>& indices);
// Returns the number of members associated with |struct_type_instruction|,
// which must be an OpStructType instruction.
uint32_t GetNumberOfStructMembers(
const opt::Instruction& struct_type_instruction);
// Returns the constant size of the array associated with
// |array_type_instruction|, which must be an OpArrayType instruction. Returns
// 0 if there is not a static size.
uint32_t GetArraySize(const opt::Instruction& array_type_instruction,
opt::IRContext* context);
} // namespace fuzzerutil
} // namespace fuzz

View File

@ -99,6 +99,8 @@ void TransformationCompositeExtract::Apply(
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
// Add the fact that the id storing the extracted element is synonymous with
// the index into the structure.
std::vector<uint32_t> indices;

View File

@ -43,21 +43,10 @@ TransformationReplaceIdWithSynonym::TransformationReplaceIdWithSynonym(
bool TransformationReplaceIdWithSynonym::IsApplicable(
spvtools::opt::IRContext* context,
const spvtools::fuzz::FactManager& fact_manager) const {
auto id_of_interest = message_.id_use_descriptor().id_of_interest();
// Does the fact manager know about the synonym?
auto ids_with_known_synonyms = fact_manager.GetIdsForWhichSynonymsAreKnown();
if (std::find(ids_with_known_synonyms.begin(), ids_with_known_synonyms.end(),
id_of_interest) == ids_with_known_synonyms.end()) {
return false;
}
auto available_synonyms = fact_manager.GetSynonymsForId(id_of_interest);
if (std::find_if(available_synonyms.begin(), available_synonyms.end(),
[this](const protobufs::DataDescriptor* dd) -> bool {
return DataDescriptorEquals()(dd,
&message_.data_descriptor());
}) == available_synonyms.end()) {
if (!fact_manager.IsSynonymous(
MakeDataDescriptor(message_.id_use_descriptor().id_of_interest(), {}),
message_.data_descriptor(), context)) {
return false;
}

View File

@ -738,6 +738,441 @@ TEST(FactManagerTest, AmbiguousFact) {
uniform_buffer_element_descriptor));
}
TEST(FactManagerTest, DataSynonymFacts) {
// The SPIR-V types and constants come from the following code. The body of
// the SPIR-V function then constructs a composite that is synonymous with
// myT.
//
// #version 310 es
//
// precision highp float;
//
// struct S {
// int a;
// uvec2 b;
// };
//
// struct T {
// bool c[5];
// mat4x2 d;
// S e;
// };
//
// void main() {
// T myT = T(bool[5](true, false, true, false, true),
// mat4x2(vec2(1.0, 2.0), vec2(3.0, 4.0),
// vec2(5.0, 6.0), vec2(7.0, 8.0)),
// S(10, uvec2(100u, 200u)));
// }
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpName %4 "main"
OpName %15 "S"
OpMemberName %15 0 "a"
OpMemberName %15 1 "b"
OpName %16 "T"
OpMemberName %16 0 "c"
OpMemberName %16 1 "d"
OpMemberName %16 2 "e"
OpName %18 "myT"
OpMemberDecorate %15 0 RelaxedPrecision
OpMemberDecorate %15 1 RelaxedPrecision
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeBool
%7 = OpTypeInt 32 0
%8 = OpConstant %7 5
%9 = OpTypeArray %6 %8
%10 = OpTypeFloat 32
%11 = OpTypeVector %10 2
%12 = OpTypeMatrix %11 4
%13 = OpTypeInt 32 1
%14 = OpTypeVector %7 2
%15 = OpTypeStruct %13 %14
%16 = OpTypeStruct %9 %12 %15
%17 = OpTypePointer Function %16
%19 = OpConstantTrue %6
%20 = OpConstantFalse %6
%21 = OpConstantComposite %9 %19 %20 %19 %20 %19
%22 = OpConstant %10 1
%23 = OpConstant %10 2
%24 = OpConstantComposite %11 %22 %23
%25 = OpConstant %10 3
%26 = OpConstant %10 4
%27 = OpConstantComposite %11 %25 %26
%28 = OpConstant %10 5
%29 = OpConstant %10 6
%30 = OpConstantComposite %11 %28 %29
%31 = OpConstant %10 7
%32 = OpConstant %10 8
%33 = OpConstantComposite %11 %31 %32
%34 = OpConstantComposite %12 %24 %27 %30 %33
%35 = OpConstant %13 10
%36 = OpConstant %7 100
%37 = OpConstant %7 200
%38 = OpConstantComposite %14 %36 %37
%39 = OpConstantComposite %15 %35 %38
%40 = OpConstantComposite %16 %21 %34 %39
%4 = OpFunction %2 None %3
%5 = OpLabel
%18 = OpVariable %17 Function
OpStore %18 %40
%100 = OpCompositeConstruct %9 %19 %20 %19 %20 %19
%101 = OpCompositeConstruct %11 %22 %23
%102 = OpCompositeConstruct %11 %25 %26
%103 = OpCompositeConstruct %11 %28 %29
%104 = OpCompositeConstruct %11 %31 %32
%105 = OpCompositeConstruct %12 %101 %102 %103 %104
%106 = OpCompositeConstruct %14 %36 %37
%107 = OpCompositeConstruct %15 %35 %106
%108 = OpCompositeConstruct %16 %100 %105 %107
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()));
FactManager fact_manager;
ASSERT_FALSE(fact_manager.IsSynonymous(
MakeDataDescriptor(24, {}), MakeDataDescriptor(101, {}), context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {0}),
MakeDataDescriptor(101, {0}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {1}),
MakeDataDescriptor(101, {1}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {0}),
MakeDataDescriptor(101, {1}),
context.get()));
fact_manager.AddFactDataSynonym(MakeDataDescriptor(24, {}),
MakeDataDescriptor(101, {}), context.get());
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(24, {}), MakeDataDescriptor(101, {}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {0}),
MakeDataDescriptor(101, {0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {1}),
MakeDataDescriptor(101, {1}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {0}),
MakeDataDescriptor(101, {1}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(
MakeDataDescriptor(27, {}), MakeDataDescriptor(102, {}), context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {0}),
MakeDataDescriptor(102, {0}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {1}),
MakeDataDescriptor(102, {1}),
context.get()));
fact_manager.AddFactDataSynonym(MakeDataDescriptor(27, {0}),
MakeDataDescriptor(102, {0}), context.get());
ASSERT_FALSE(fact_manager.IsSynonymous(
MakeDataDescriptor(27, {}), MakeDataDescriptor(102, {}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {0}),
MakeDataDescriptor(102, {0}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {1}),
MakeDataDescriptor(102, {1}),
context.get()));
fact_manager.AddFactDataSynonym(MakeDataDescriptor(27, {1}),
MakeDataDescriptor(102, {1}), context.get());
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(27, {}), MakeDataDescriptor(102, {}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {0}),
MakeDataDescriptor(102, {0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {1}),
MakeDataDescriptor(102, {1}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(
MakeDataDescriptor(30, {}), MakeDataDescriptor(103, {}), context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(30, {0}),
MakeDataDescriptor(103, {0}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(30, {1}),
MakeDataDescriptor(103, {1}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(
MakeDataDescriptor(33, {}), MakeDataDescriptor(104, {}), context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {0}),
MakeDataDescriptor(104, {0}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {1}),
MakeDataDescriptor(104, {1}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(
MakeDataDescriptor(34, {}), MakeDataDescriptor(105, {}), context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {0}),
MakeDataDescriptor(105, {0}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {1}),
MakeDataDescriptor(105, {1}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {2}),
MakeDataDescriptor(105, {2}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {3}),
MakeDataDescriptor(105, {3}),
context.get()));
fact_manager.AddFactDataSynonym(MakeDataDescriptor(30, {}),
MakeDataDescriptor(103, {}), context.get());
fact_manager.AddFactDataSynonym(MakeDataDescriptor(33, {}),
MakeDataDescriptor(104, {}), context.get());
fact_manager.AddFactDataSynonym(MakeDataDescriptor(34, {0}),
MakeDataDescriptor(105, {0}), context.get());
fact_manager.AddFactDataSynonym(MakeDataDescriptor(34, {1}),
MakeDataDescriptor(105, {1}), context.get());
fact_manager.AddFactDataSynonym(MakeDataDescriptor(34, {2}),
MakeDataDescriptor(105, {2}), context.get());
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(30, {}), MakeDataDescriptor(103, {}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(30, {0}),
MakeDataDescriptor(103, {0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(30, {1}),
MakeDataDescriptor(103, {1}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(33, {}), MakeDataDescriptor(104, {}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {0}),
MakeDataDescriptor(104, {0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {1}),
MakeDataDescriptor(104, {1}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(
MakeDataDescriptor(34, {}), MakeDataDescriptor(105, {}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {0}),
MakeDataDescriptor(105, {0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {1}),
MakeDataDescriptor(105, {1}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {2}),
MakeDataDescriptor(105, {2}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {3}),
MakeDataDescriptor(105, {3}),
context.get()));
fact_manager.AddFactDataSynonym(MakeDataDescriptor(34, {3}),
MakeDataDescriptor(105, {3}), context.get());
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {0}),
MakeDataDescriptor(104, {0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {3}),
MakeDataDescriptor(105, {3}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(
MakeDataDescriptor(21, {}), MakeDataDescriptor(100, {}), context.get()));
fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {0}),
MakeDataDescriptor(100, {0}), context.get());
fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {1}),
MakeDataDescriptor(100, {1}), context.get());
fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {2}),
MakeDataDescriptor(100, {2}), context.get());
fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {3}),
MakeDataDescriptor(100, {3}), context.get());
fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {4}),
MakeDataDescriptor(100, {4}), context.get());
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(21, {}), MakeDataDescriptor(100, {}), context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(39, {0}),
MakeDataDescriptor(107, {0}),
context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(
MakeDataDescriptor(35, {}), MakeDataDescriptor(39, {0}), context.get()));
fact_manager.AddFactDataSynonym(MakeDataDescriptor(39, {0}),
MakeDataDescriptor(35, {}), context.get());
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(39, {0}),
MakeDataDescriptor(107, {0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(35, {}), MakeDataDescriptor(39, {0}), context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(
MakeDataDescriptor(38, {0}), MakeDataDescriptor(36, {}), context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(
MakeDataDescriptor(38, {1}), MakeDataDescriptor(37, {}), context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(
MakeDataDescriptor(106, {0}), MakeDataDescriptor(36, {}), context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(
MakeDataDescriptor(106, {1}), MakeDataDescriptor(37, {}), context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(
MakeDataDescriptor(38, {}), MakeDataDescriptor(106, {}), context.get()));
fact_manager.AddFactDataSynonym(MakeDataDescriptor(38, {0}),
MakeDataDescriptor(36, {}), context.get());
fact_manager.AddFactDataSynonym(MakeDataDescriptor(106, {0}),
MakeDataDescriptor(36, {}), context.get());
fact_manager.AddFactDataSynonym(MakeDataDescriptor(38, {1}),
MakeDataDescriptor(37, {}), context.get());
fact_manager.AddFactDataSynonym(MakeDataDescriptor(106, {1}),
MakeDataDescriptor(37, {}), context.get());
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(38, {0}), MakeDataDescriptor(36, {}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(38, {1}), MakeDataDescriptor(37, {}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(106, {0}), MakeDataDescriptor(36, {}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(106, {1}), MakeDataDescriptor(37, {}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(38, {}), MakeDataDescriptor(106, {}), context.get()));
ASSERT_FALSE(fact_manager.IsSynonymous(
MakeDataDescriptor(40, {}), MakeDataDescriptor(108, {}), context.get()));
fact_manager.AddFactDataSynonym(MakeDataDescriptor(107, {0}),
MakeDataDescriptor(35, {}), context.get());
fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {0}),
MakeDataDescriptor(108, {0}), context.get());
fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {1}),
MakeDataDescriptor(108, {1}), context.get());
fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {2}),
MakeDataDescriptor(108, {2}), context.get());
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(40, {}), MakeDataDescriptor(108, {}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0}),
MakeDataDescriptor(108, {0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1}),
MakeDataDescriptor(108, {1}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {2}),
MakeDataDescriptor(108, {2}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0, 0}),
MakeDataDescriptor(108, {0, 0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0, 1}),
MakeDataDescriptor(108, {0, 1}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0, 2}),
MakeDataDescriptor(108, {0, 2}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0, 3}),
MakeDataDescriptor(108, {0, 3}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0, 4}),
MakeDataDescriptor(108, {0, 4}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 0}),
MakeDataDescriptor(108, {1, 0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 1}),
MakeDataDescriptor(108, {1, 1}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 2}),
MakeDataDescriptor(108, {1, 2}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 3}),
MakeDataDescriptor(108, {1, 3}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 0, 0}),
MakeDataDescriptor(108, {1, 0, 0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 1, 0}),
MakeDataDescriptor(108, {1, 1, 0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 2, 0}),
MakeDataDescriptor(108, {1, 2, 0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 3, 0}),
MakeDataDescriptor(108, {1, 3, 0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 0, 1}),
MakeDataDescriptor(108, {1, 0, 1}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 1, 1}),
MakeDataDescriptor(108, {1, 1, 1}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 2, 1}),
MakeDataDescriptor(108, {1, 2, 1}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 3, 1}),
MakeDataDescriptor(108, {1, 3, 1}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {2, 0}),
MakeDataDescriptor(108, {2, 0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {2, 1}),
MakeDataDescriptor(108, {2, 1}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {2, 1, 0}),
MakeDataDescriptor(108, {2, 1, 0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {2, 1, 1}),
MakeDataDescriptor(108, {2, 1, 1}),
context.get()));
}
TEST(FactManagerTest, RecursiveAdditionOfFacts) {
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 = OpTypeFloat 32
%7 = OpTypeVector %6 4
%8 = OpTypeMatrix %7 4
%9 = OpConstant %6 0
%10 = OpConstantComposite %7 %9 %9 %9 %9
%11 = OpConstantComposite %8 %10 %10 %10 %10
%12 = OpFunction %2 None %3
%13 = 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()));
FactManager fact_manager;
fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}),
MakeDataDescriptor(11, {2}), context.get());
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(10, {}), MakeDataDescriptor(11, {2}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {0}),
MakeDataDescriptor(11, {2, 0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {1}),
MakeDataDescriptor(11, {2, 1}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {2}),
MakeDataDescriptor(11, {2, 2}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {3}),
MakeDataDescriptor(11, {2, 3}),
context.get()));
}
} // namespace
} // namespace fuzz
} // namespace spvtools

View File

@ -144,12 +144,12 @@ TEST(TransformationCompositeConstructTest, ConstructArrays) {
make_vec2_array_length_3_bad.IsApplicable(context.get(), fact_manager));
make_vec2_array_length_3.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(41, {}),
MakeDataDescriptor(200, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(45, {}),
MakeDataDescriptor(200, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {}),
MakeDataDescriptor(200, {2})));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(41, {}), MakeDataDescriptor(200, {0}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(45, {}), MakeDataDescriptor(200, {1}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(27, {}), MakeDataDescriptor(200, {2}), context.get()));
// Make a float[2]
TransformationCompositeConstruct make_float_array_length_2(
@ -163,10 +163,10 @@ TEST(TransformationCompositeConstructTest, ConstructArrays) {
make_float_array_length_2_bad.IsApplicable(context.get(), fact_manager));
make_float_array_length_2.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {}),
MakeDataDescriptor(201, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {}),
MakeDataDescriptor(201, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(24, {}), MakeDataDescriptor(201, {0}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(40, {}), MakeDataDescriptor(201, {1}), context.get()));
// Make a bool[3]
TransformationCompositeConstruct make_bool_array_length_3(
@ -182,12 +182,12 @@ TEST(TransformationCompositeConstructTest, ConstructArrays) {
make_bool_array_length_3_bad.IsApplicable(context.get(), fact_manager));
make_bool_array_length_3.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {}),
MakeDataDescriptor(202, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(50, {}),
MakeDataDescriptor(202, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(50, {}),
MakeDataDescriptor(202, {2})));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(33, {}), MakeDataDescriptor(202, {0}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(50, {}), MakeDataDescriptor(202, {1}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(50, {}), MakeDataDescriptor(202, {2}), context.get()));
// make a uvec3[2][2]
TransformationCompositeConstruct make_uvec3_array_length_2_2(
@ -201,10 +201,11 @@ TEST(TransformationCompositeConstructTest, ConstructArrays) {
fact_manager));
make_uvec3_array_length_2_2.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(69, {}),
MakeDataDescriptor(203, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(69, {}), MakeDataDescriptor(203, {0}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(100, {}),
MakeDataDescriptor(203, {1})));
MakeDataDescriptor(203, {1}),
context.get()));
std::string after_transformation = R"(
OpCapability Shader
@ -403,12 +404,12 @@ TEST(TransformationCompositeConstructTest, ConstructMatrices) {
ASSERT_FALSE(make_mat34_bad.IsApplicable(context.get(), fact_manager));
make_mat34.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(25, {}),
MakeDataDescriptor(200, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(28, {}),
MakeDataDescriptor(200, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(31, {}),
MakeDataDescriptor(200, {2})));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(28, {}), MakeDataDescriptor(200, {1}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(31, {}), MakeDataDescriptor(200, {2}), context.get()));
// make a mat4x3
TransformationCompositeConstruct make_mat43(
@ -420,14 +421,15 @@ TEST(TransformationCompositeConstructTest, ConstructMatrices) {
ASSERT_FALSE(make_mat43_bad.IsApplicable(context.get(), fact_manager));
make_mat43.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(11, {}),
MakeDataDescriptor(201, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(13, {}),
MakeDataDescriptor(201, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(16, {}),
MakeDataDescriptor(201, {2})));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(11, {}), MakeDataDescriptor(201, {0}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(13, {}), MakeDataDescriptor(201, {1}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(16, {}), MakeDataDescriptor(201, {2}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(100, {}),
MakeDataDescriptor(201, {3})));
MakeDataDescriptor(201, {3}),
context.get()));
std::string after_transformation = R"(
OpCapability Shader
@ -611,10 +613,10 @@ TEST(TransformationCompositeConstructTest, ConstructStructs) {
ASSERT_FALSE(make_inner_bad.IsApplicable(context.get(), fact_manager));
make_inner.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(25, {}),
MakeDataDescriptor(200, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(19, {}),
MakeDataDescriptor(200, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(19, {}), MakeDataDescriptor(200, {1}), context.get()));
// make an Outer
TransformationCompositeConstruct make_outer(
@ -628,12 +630,13 @@ TEST(TransformationCompositeConstructTest, ConstructStructs) {
ASSERT_FALSE(make_outer_bad.IsApplicable(context.get(), fact_manager));
make_outer.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(46, {}),
MakeDataDescriptor(201, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(46, {}), MakeDataDescriptor(201, {0}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(200, {}),
MakeDataDescriptor(201, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(56, {}),
MakeDataDescriptor(201, {2})));
MakeDataDescriptor(201, {1}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(56, {}), MakeDataDescriptor(201, {2}), context.get()));
std::string after_transformation = R"(
OpCapability Shader
@ -929,10 +932,10 @@ TEST(TransformationCompositeConstructTest, ConstructVectors) {
ASSERT_FALSE(make_vec2_bad.IsApplicable(context.get(), fact_manager));
make_vec2.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}),
MakeDataDescriptor(200, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(11, {}),
MakeDataDescriptor(200, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(17, {}), MakeDataDescriptor(200, {0}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(11, {}), MakeDataDescriptor(200, {1}), context.get()));
TransformationCompositeConstruct make_vec3(
25, {12, 32}, MakeInstructionDescriptor(35, SpvOpCompositeConstruct, 0),
@ -946,11 +949,13 @@ TEST(TransformationCompositeConstructTest, ConstructVectors) {
make_vec3.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(12, {0}),
MakeDataDescriptor(201, {0})));
MakeDataDescriptor(201, {0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(12, {1}),
MakeDataDescriptor(201, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(32, {}),
MakeDataDescriptor(201, {2})));
MakeDataDescriptor(201, {1}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(32, {}), MakeDataDescriptor(201, {2}), context.get()));
TransformationCompositeConstruct make_vec4(
44, {32, 32, 10, 11}, MakeInstructionDescriptor(75, SpvOpAccessChain, 0),
@ -963,14 +968,14 @@ TEST(TransformationCompositeConstructTest, ConstructVectors) {
ASSERT_FALSE(make_vec4_bad.IsApplicable(context.get(), fact_manager));
make_vec4.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(32, {}),
MakeDataDescriptor(202, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(32, {}),
MakeDataDescriptor(202, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {}),
MakeDataDescriptor(202, {2})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(11, {}),
MakeDataDescriptor(202, {3})));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(32, {}), MakeDataDescriptor(202, {0}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(32, {}), MakeDataDescriptor(202, {1}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(10, {}), MakeDataDescriptor(202, {2}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(11, {}), MakeDataDescriptor(202, {3}), context.get()));
TransformationCompositeConstruct make_ivec2(
51, {126, 120}, MakeInstructionDescriptor(128, SpvOpLoad, 0), 203);
@ -982,9 +987,11 @@ TEST(TransformationCompositeConstructTest, ConstructVectors) {
make_ivec2.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(126, {}),
MakeDataDescriptor(203, {0})));
MakeDataDescriptor(203, {0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(120, {}),
MakeDataDescriptor(203, {1})));
MakeDataDescriptor(203, {1}),
context.get()));
TransformationCompositeConstruct make_ivec3(
114, {56, 117, 56}, MakeInstructionDescriptor(66, SpvOpAccessChain, 0),
@ -997,12 +1004,13 @@ TEST(TransformationCompositeConstructTest, ConstructVectors) {
ASSERT_FALSE(make_ivec3_bad.IsApplicable(context.get(), fact_manager));
make_ivec3.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(56, {}),
MakeDataDescriptor(204, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(56, {}), MakeDataDescriptor(204, {0}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(117, {}),
MakeDataDescriptor(204, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(56, {}),
MakeDataDescriptor(204, {2})));
MakeDataDescriptor(204, {1}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(56, {}), MakeDataDescriptor(204, {2}), context.get()));
TransformationCompositeConstruct make_ivec4(
122, {56, 117, 117, 117}, MakeInstructionDescriptor(66, SpvOpIAdd, 0),
@ -1015,14 +1023,17 @@ TEST(TransformationCompositeConstructTest, ConstructVectors) {
ASSERT_FALSE(make_ivec4_bad.IsApplicable(context.get(), fact_manager));
make_ivec4.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(56, {}),
MakeDataDescriptor(205, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(56, {}), MakeDataDescriptor(205, {0}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(117, {}),
MakeDataDescriptor(205, {1})));
MakeDataDescriptor(205, {1}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(117, {}),
MakeDataDescriptor(205, {2})));
MakeDataDescriptor(205, {2}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(117, {}),
MakeDataDescriptor(205, {3})));
MakeDataDescriptor(205, {3}),
context.get()));
TransformationCompositeConstruct make_uvec2(
86, {18, 38}, MakeInstructionDescriptor(133, SpvOpAccessChain, 0), 206);
@ -1032,10 +1043,10 @@ TEST(TransformationCompositeConstructTest, ConstructVectors) {
ASSERT_FALSE(make_uvec2_bad.IsApplicable(context.get(), fact_manager));
make_uvec2.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(18, {}),
MakeDataDescriptor(206, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(38, {}),
MakeDataDescriptor(206, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(18, {}), MakeDataDescriptor(206, {0}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(38, {}), MakeDataDescriptor(206, {1}), context.get()));
TransformationCompositeConstruct make_uvec3(
59, {14, 18, 136}, MakeInstructionDescriptor(137, SpvOpReturn, 0), 207);
@ -1046,12 +1057,13 @@ TEST(TransformationCompositeConstructTest, ConstructVectors) {
ASSERT_FALSE(make_uvec3_bad.IsApplicable(context.get(), fact_manager));
make_uvec3.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(14, {}),
MakeDataDescriptor(207, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(18, {}),
MakeDataDescriptor(207, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(14, {}), MakeDataDescriptor(207, {0}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(18, {}), MakeDataDescriptor(207, {1}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(136, {}),
MakeDataDescriptor(207, {2})));
MakeDataDescriptor(207, {2}),
context.get()));
TransformationCompositeConstruct make_uvec4(
131, {14, 18, 136, 136},
@ -1064,14 +1076,16 @@ TEST(TransformationCompositeConstructTest, ConstructVectors) {
ASSERT_FALSE(make_uvec4_bad.IsApplicable(context.get(), fact_manager));
make_uvec4.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(14, {}),
MakeDataDescriptor(208, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(18, {}),
MakeDataDescriptor(208, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(14, {}), MakeDataDescriptor(208, {0}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(18, {}), MakeDataDescriptor(208, {1}), context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(136, {}),
MakeDataDescriptor(208, {2})));
MakeDataDescriptor(208, {2}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(136, {}),
MakeDataDescriptor(208, {3})));
MakeDataDescriptor(208, {3}),
context.get()));
TransformationCompositeConstruct make_bvec2(
102,
@ -1093,9 +1107,10 @@ TEST(TransformationCompositeConstructTest, ConstructVectors) {
make_bvec2.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(111, {}),
MakeDataDescriptor(209, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(41, {}),
MakeDataDescriptor(209, {1})));
MakeDataDescriptor(209, {0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(41, {}), MakeDataDescriptor(209, {1}), context.get()));
TransformationCompositeConstruct make_bvec3(
93, {108, 73}, MakeInstructionDescriptor(108, SpvOpStore, 0), 210);
@ -1107,11 +1122,13 @@ TEST(TransformationCompositeConstructTest, ConstructVectors) {
make_bvec3.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {0}),
MakeDataDescriptor(210, {0})));
MakeDataDescriptor(210, {0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {1}),
MakeDataDescriptor(210, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(73, {}),
MakeDataDescriptor(210, {2})));
MakeDataDescriptor(210, {1}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(
MakeDataDescriptor(73, {}), MakeDataDescriptor(210, {2}), context.get()));
TransformationCompositeConstruct make_bvec4(
70, {108, 108}, MakeInstructionDescriptor(108, SpvOpBranch, 0), 211);
@ -1123,13 +1140,17 @@ TEST(TransformationCompositeConstructTest, ConstructVectors) {
make_bvec4.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {0}),
MakeDataDescriptor(211, {0})));
MakeDataDescriptor(211, {0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {1}),
MakeDataDescriptor(211, {1})));
MakeDataDescriptor(211, {1}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {0}),
MakeDataDescriptor(211, {2})));
MakeDataDescriptor(211, {2}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {1}),
MakeDataDescriptor(211, {3})));
MakeDataDescriptor(211, {3}),
context.get()));
std::string after_transformation = R"(
OpCapability Shader

View File

@ -173,17 +173,23 @@ TEST(TransformationCompositeExtractTest, BasicTest) {
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(201, {}),
MakeDataDescriptor(100, {2})));
MakeDataDescriptor(100, {2}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(202, {}),
MakeDataDescriptor(104, {0, 2})));
MakeDataDescriptor(104, {0, 2}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(203, {}),
MakeDataDescriptor(104, {0})));
MakeDataDescriptor(104, {0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(204, {}),
MakeDataDescriptor(101, {0})));
MakeDataDescriptor(101, {0}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(205, {}),
MakeDataDescriptor(102, {2})));
MakeDataDescriptor(102, {2}),
context.get()));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(206, {}),
MakeDataDescriptor(103, {1})));
MakeDataDescriptor(103, {1}),
context.get()));
std::string after_transformation = R"(
OpCapability Shader

View File

@ -52,7 +52,8 @@ TEST(TransformationCopyObjectTest, CopyBooleanConstants) {
FactManager fact_manager;
ASSERT_EQ(0, fact_manager.GetIdsForWhichSynonymsAreKnown().size());
ASSERT_EQ(0,
fact_manager.GetIdsForWhichSynonymsAreKnown(context.get()).size());
{
TransformationCopyObject copy_true(
@ -60,16 +61,16 @@ TEST(TransformationCopyObjectTest, CopyBooleanConstants) {
ASSERT_TRUE(copy_true.IsApplicable(context.get(), fact_manager));
copy_true.Apply(context.get(), &fact_manager);
auto ids_for_which_synonyms_are_known =
fact_manager.GetIdsForWhichSynonymsAreKnown();
std::vector<uint32_t> ids_for_which_synonyms_are_known =
fact_manager.GetIdsForWhichSynonymsAreKnown(context.get());
ASSERT_EQ(2, ids_for_which_synonyms_are_known.size());
ASSERT_TRUE(std::find(ids_for_which_synonyms_are_known.begin(),
ids_for_which_synonyms_are_known.end(),
7) != ids_for_which_synonyms_are_known.end());
ASSERT_EQ(2, fact_manager.GetSynonymsForId(7).size());
ASSERT_EQ(2, fact_manager.GetSynonymsForId(7, context.get()).size());
protobufs::DataDescriptor descriptor_100 = MakeDataDescriptor(100, {});
ASSERT_TRUE(
fact_manager.IsSynonymous(MakeDataDescriptor(7, {}), descriptor_100));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(7, {}),
descriptor_100, context.get()));
}
{
@ -77,16 +78,16 @@ TEST(TransformationCopyObjectTest, CopyBooleanConstants) {
8, MakeInstructionDescriptor(100, SpvOpReturn, 0), 101);
ASSERT_TRUE(copy_false.IsApplicable(context.get(), fact_manager));
copy_false.Apply(context.get(), &fact_manager);
auto ids_for_which_synonyms_are_known =
fact_manager.GetIdsForWhichSynonymsAreKnown();
std::vector<uint32_t> ids_for_which_synonyms_are_known =
fact_manager.GetIdsForWhichSynonymsAreKnown(context.get());
ASSERT_EQ(4, ids_for_which_synonyms_are_known.size());
ASSERT_TRUE(std::find(ids_for_which_synonyms_are_known.begin(),
ids_for_which_synonyms_are_known.end(),
8) != ids_for_which_synonyms_are_known.end());
ASSERT_EQ(2, fact_manager.GetSynonymsForId(8).size());
ASSERT_EQ(2, fact_manager.GetSynonymsForId(8, context.get()).size());
protobufs::DataDescriptor descriptor_101 = MakeDataDescriptor(101, {});
ASSERT_TRUE(
fact_manager.IsSynonymous(MakeDataDescriptor(8, {}), descriptor_101));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(8, {}),
descriptor_101, context.get()));
}
{
@ -94,16 +95,16 @@ TEST(TransformationCopyObjectTest, CopyBooleanConstants) {
101, MakeInstructionDescriptor(5, SpvOpReturn, 0), 102);
ASSERT_TRUE(copy_false_again.IsApplicable(context.get(), fact_manager));
copy_false_again.Apply(context.get(), &fact_manager);
auto ids_for_which_synonyms_are_known =
fact_manager.GetIdsForWhichSynonymsAreKnown();
std::vector<uint32_t> ids_for_which_synonyms_are_known =
fact_manager.GetIdsForWhichSynonymsAreKnown(context.get());
ASSERT_EQ(5, ids_for_which_synonyms_are_known.size());
ASSERT_TRUE(std::find(ids_for_which_synonyms_are_known.begin(),
ids_for_which_synonyms_are_known.end(),
101) != ids_for_which_synonyms_are_known.end());
ASSERT_EQ(3, fact_manager.GetSynonymsForId(101).size());
ASSERT_EQ(3, fact_manager.GetSynonymsForId(101, context.get()).size());
protobufs::DataDescriptor descriptor_102 = MakeDataDescriptor(102, {});
ASSERT_TRUE(
fact_manager.IsSynonymous(MakeDataDescriptor(101, {}), descriptor_102));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(101, {}),
descriptor_102, context.get()));
}
{
@ -111,16 +112,16 @@ TEST(TransformationCopyObjectTest, CopyBooleanConstants) {
7, MakeInstructionDescriptor(102, SpvOpReturn, 0), 103);
ASSERT_TRUE(copy_true_again.IsApplicable(context.get(), fact_manager));
copy_true_again.Apply(context.get(), &fact_manager);
auto ids_for_which_synonyms_are_known =
fact_manager.GetIdsForWhichSynonymsAreKnown();
std::vector<uint32_t> ids_for_which_synonyms_are_known =
fact_manager.GetIdsForWhichSynonymsAreKnown(context.get());
ASSERT_EQ(6, ids_for_which_synonyms_are_known.size());
ASSERT_TRUE(std::find(ids_for_which_synonyms_are_known.begin(),
ids_for_which_synonyms_are_known.end(),
7) != ids_for_which_synonyms_are_known.end());
ASSERT_EQ(3, fact_manager.GetSynonymsForId(7).size());
ASSERT_EQ(3, fact_manager.GetSynonymsForId(7, context.get()).size());
protobufs::DataDescriptor descriptor_103 = MakeDataDescriptor(103, {});
ASSERT_TRUE(
fact_manager.IsSynonymous(MakeDataDescriptor(7, {}), descriptor_103));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(7, {}),
descriptor_103, context.get()));
}
std::string after_transformation = R"(