mirror of
https://github.com/RPCSX/SPIRV-Tools.git
synced 2024-12-03 17:01:06 +00:00
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:
parent
fb6bac889e
commit
3724cfbea8
@ -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
|
||||
|
@ -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.
|
||||
};
|
||||
|
@ -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()) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"(
|
||||
|
Loading…
Reference in New Issue
Block a user