spirv-fuzz: improvements to representation of data synonym facts (#3006)

This change fixes a bug in EquivalenceRelation, changes the interface
of EquivalenceRelation to avoid exposing (potentially
nondeterministic) unordered sets, and changes the interface of
FactManager to allow querying data synonyms directly. These interface
changes have required a lot of corresponding changes to client code
and tests.
This commit is contained in:
Alastair Donaldson 2019-11-01 17:50:01 +00:00 committed by GitHub
parent cdee051e2c
commit f1e5cd73f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 338 additions and 209 deletions

View File

@ -20,14 +20,12 @@ namespace spvtools {
namespace fuzz {
protobufs::DataDescriptor MakeDataDescriptor(uint32_t object,
std::vector<uint32_t>&& indices,
uint32_t num_contiguous_elements) {
std::vector<uint32_t>&& indices) {
protobufs::DataDescriptor result;
result.set_object(object);
for (auto index : indices) {
result.add_index(index);
}
result.set_num_contiguous_elements(num_contiguous_elements);
return result;
}
@ -50,5 +48,22 @@ bool DataDescriptorEquals::operator()(
second->index().begin());
}
std::ostream& operator<<(std::ostream& out,
const protobufs::DataDescriptor& data_descriptor) {
out << data_descriptor.object();
out << "[";
bool first = true;
for (auto index : data_descriptor.index()) {
if (first) {
first = false;
} else {
out << ", ";
}
out << index;
}
out << "]";
return out;
}
} // namespace fuzz
} // namespace spvtools

View File

@ -17,6 +17,7 @@
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include <ostream>
#include <vector>
namespace spvtools {
@ -25,8 +26,7 @@ namespace fuzz {
// Factory method to create a data descriptor message from an object id and a
// list of indices.
protobufs::DataDescriptor MakeDataDescriptor(uint32_t object,
std::vector<uint32_t>&& indices,
uint32_t num_contiguous_elements);
std::vector<uint32_t>&& indices);
// Hash function for data descriptors.
struct DataDescriptorHash {
@ -39,6 +39,9 @@ struct DataDescriptorEquals {
const protobufs::DataDescriptor* second) const;
};
std::ostream& operator<<(std::ostream& out,
const protobufs::DataDescriptor& data_descriptor);
} // namespace fuzz
} // namespace spvtools

View File

@ -68,8 +68,6 @@ namespace fuzz {
template <typename T, typename PointerHashT, typename PointerEqualsT>
class EquivalenceRelation {
public:
using ValueSet = std::unordered_set<const T*, PointerHashT, PointerEqualsT>;
// Merges the equivalence classes associated with |value1| and |value2|.
// If any of these values was not previously in the equivalence relation, it
// is added to the pool of values known to be in the relation.
@ -86,6 +84,7 @@ class EquivalenceRelation {
// Initially say that the value is its own parent and that it has no
// children.
assert(pointer_to_value && "Representatives should never be null.");
parent_[pointer_to_value] = pointer_to_value;
children_[pointer_to_value] = std::unordered_set<const T*>();
}
@ -105,18 +104,31 @@ class EquivalenceRelation {
// are not already in the same class, make one the parent of the other.
const T* representative1 = Find(value1_ptr);
const T* representative2 = Find(value2_ptr);
assert(representative1 && "Representatives should never be null.");
assert(representative2 && "Representatives should never be null.");
if (representative1 != representative2) {
parent_[representative1] = representative2;
children_[representative2].insert(representative1);
}
}
// Returns exactly one representative per equivalence class.
std::vector<const T*> GetEquivalenceClassRepresentatives() const {
std::vector<const T*> result;
for (auto& value : owned_values_) {
if (parent_[value.get()] == value.get()) {
result.push_back(value.get());
}
}
return result;
}
// Returns pointers to all values in the equivalence class of |value|, which
// must already be part of the equivalence relation.
ValueSet GetEquivalenceClass(const T& value) const {
std::vector<const T*> GetEquivalenceClass(const T& value) const {
assert(Exists(value));
ValueSet result;
std::vector<const T*> result;
// Traverse the tree of values rooted at the representative of the
// equivalence class to which |value| belongs, and collect up all the values
@ -125,7 +137,7 @@ class EquivalenceRelation {
stack.push_back(Find(*value_set_.find(&value)));
while (!stack.empty()) {
const T* item = stack.back();
result.insert(item);
result.push_back(item);
stack.pop_back();
for (auto child : children_[item]) {
stack.push_back(child);
@ -141,40 +153,45 @@ class EquivalenceRelation {
return Find(&value1) == Find(&value2);
}
// Returns the set of all values known to be part of the equivalence relation.
ValueSet GetAllKnownValues() const {
ValueSet result;
// Returns all values known to be part of the equivalence relation.
std::vector<const T*> GetAllKnownValues() const {
std::vector<const T*> result;
for (auto& value : owned_values_) {
result.insert(value.get());
result.push_back(value.get());
}
return result;
}
private:
// Returns true if and only if |value| is known to be part of the equivalence
// relation.
bool Exists(const T& value) const {
return value_set_.find(&value) != value_set_.end();
}
private:
// Returns the representative of the equivalence class of |value|, which must
// already be known to the equivalence relation. This is the 'Find' operation
// in a classic union-find data structure.
const T* Find(const T* value) const {
assert(Exists(*value));
// Get the canonical pointer to the value from the value pool.
const T* known_value = *value_set_.find(value);
assert(parent_[known_value] && "Every known value should have a parent.");
// Compute the result by chasing parents until we find a value that is its
// own parent.
const T* result = value;
const T* result = known_value;
while (parent_[result] != result) {
result = parent_[result];
}
assert(result && "Representatives should never be null.");
// At this point, |result| is the representative of the equivalence class.
// Now perform the 'path compression' optimization by doing another pass up
// the parent chain, setting the parent of each node to be the
// representative, and rewriting children correspondingly.
const T* current = value;
const T* current = known_value;
while (parent_[current] != result) {
const T* next = parent_[current];
parent_[current] = result;
@ -205,7 +222,7 @@ class EquivalenceRelation {
// |owned_values_|, and |value_pool_| provides (via |PointerHashT| and
// |PointerEqualsT|) a means for mapping a value of interest to a pointer
// into an equivalent value in |owned_values_|.
ValueSet value_set_;
std::unordered_set<const T*, PointerHashT, PointerEqualsT> value_set_;
std::vector<std::unique_ptr<T>> owned_values_;
};

View File

@ -16,7 +16,6 @@
#include <map>
#include <sstream>
#include <unordered_set>
#include "source/fuzz/equivalence_relation.h"
#include "source/fuzz/fuzzer_util.h"
@ -328,6 +327,10 @@ struct FactManager::DataSynonymFacts {
// See method in FactManager which delegates to this method.
void AddFact(const protobufs::FactDataSynonym& fact);
// See method in FactManager which delegates to this method.
bool IsSynonymous(const protobufs::DataDescriptor& data_descriptor1,
const protobufs::DataDescriptor& data_descriptor2) const;
EquivalenceRelation<protobufs::DataDescriptor, DataDescriptorHash,
DataDescriptorEquals>
synonymous;
@ -338,6 +341,14 @@ void FactManager::DataSynonymFacts::AddFact(
synonymous.MakeEquivalent(fact.data1(), fact.data2());
}
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);
}
// End of data synonym facts
//==============================
@ -375,7 +386,8 @@ bool FactManager::AddFact(const fuzz::protobufs::Fact& fact,
}
void FactManager::AddFactDataSynonym(const protobufs::DataDescriptor& data1,
const protobufs::DataDescriptor& data2) {
const protobufs::DataDescriptor& data2,
opt::IRContext* /*unused*/) {
protobufs::FactDataSynonym fact;
*fact.mutable_data1() = data1;
*fact.mutable_data2() = data2;
@ -412,27 +424,28 @@ FactManager::GetConstantUniformFactsAndTypes() const {
return uniform_constant_facts_->facts_and_type_ids;
}
std::set<uint32_t> FactManager::GetIdsForWhichSynonymsAreKnown() const {
std::set<uint32_t> result;
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()) {
assert(data_descriptor->num_contiguous_elements() == 1 &&
"Multiple contiguous elements are only allowed for data "
"descriptors that "
"are indices into vectors.");
result.insert(data_descriptor->object());
result.push_back(data_descriptor->object());
}
}
return result;
}
std::unordered_set<const protobufs::DataDescriptor*, DataDescriptorHash,
DataDescriptorEquals>
FactManager::GetSynonymsForId(uint32_t id) const {
std::vector<const protobufs::DataDescriptor*> FactManager::GetSynonymsForId(
uint32_t id) const {
return data_synonym_facts_->synonymous.GetEquivalenceClass(
MakeDataDescriptor(id, {}, 1));
MakeDataDescriptor(id, {}));
}
bool FactManager::IsSynonymous(
const protobufs::DataDescriptor& data_descriptor1,
const protobufs::DataDescriptor& data_descriptor2) const {
return data_synonym_facts_->IsSynonymous(data_descriptor1, data_descriptor2);
};
} // namespace fuzz
} // namespace spvtools

View File

@ -55,7 +55,8 @@ class FactManager {
// Record the fact that |data1| and |data2| are synonymous.
void AddFactDataSynonym(const protobufs::DataDescriptor& data1,
const protobufs::DataDescriptor& data2);
const protobufs::DataDescriptor& data2,
opt::IRContext* context);
// The fact manager is responsible for managing a few distinct categories of
// facts. In principle there could be different fact managers for each kind
@ -106,13 +107,17 @@ class FactManager {
// Returns every id for which a fact of the form "this id is synonymous
// with this piece of data" is known.
std::set<uint32_t> GetIdsForWhichSynonymsAreKnown() const;
std::vector<uint32_t> GetIdsForWhichSynonymsAreKnown() const;
// Requires that at least one synonym for |id| is known, and returns the
// equivalence class of all known synonyms.
std::unordered_set<const protobufs::DataDescriptor*, DataDescriptorHash,
DataDescriptorEquals>
GetSynonymsForId(uint32_t id) 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;
// Return 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;
// End of id synonym facts
//==============================
@ -121,13 +126,13 @@ class FactManager {
// For each distinct kind of fact to be managed, we use a separate opaque
// struct type.
struct ConstantUniformFacts; // Opaque struct for holding data about uniform
// buffer elements.
struct ConstantUniformFacts; // Opaque class for management of
// constant uniform facts.
std::unique_ptr<ConstantUniformFacts>
uniform_constant_facts_; // Unique pointer to internal data.
struct DataSynonymFacts; // Opaque struct for holding data about data
// synonyms.
struct DataSynonymFacts; // Opaque class for management of data synonym
// facts.
std::unique_ptr<DataSynonymFacts>
data_synonym_facts_; // Unique pointer to internal data.
};

View File

@ -82,10 +82,6 @@ message DataDescriptor {
// 0 or more indices, used to index into a composite object
repeated uint32 index = 2;
// The number of contiguous elements. This will typically be 1, but e.g. 2 or
// 3 can be used to describe the 'xy' or 'xyz' portion of a vec4.
uint32 num_contiguous_elements = 3;
}
message UniformBufferElementDescriptor {

View File

@ -133,45 +133,45 @@ void TransformationCompositeConstruct::Apply(opt::IRContext* context,
context, SpvOpCompositeConstruct, message_.composite_type_id(),
message_.fresh_id(), in_operands));
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
// Inform the fact manager that we now have new synonyms: every component of
// the composite is synonymous with the id used to construct that component.
// the composite is synonymous with the id used to construct that component,
// except in the case of a vector where a single vector id can span multiple
// components.
auto composite_type =
context->get_type_mgr()->GetType(message_.composite_type_id());
uint32_t index = 0;
for (auto component : message_.component()) {
// Decide how many contiguous composite elements are represented by the
// components. This is always 1, except in the case of a vector that is
// constructed by smaller vectors.
uint32_t num_contiguous_elements;
if (composite_type->AsVector()) {
// The vector case is a bit fiddly, because one argument to a vector
// constructor can cover more than one element.
auto component_type = context->get_type_mgr()->GetType(
context->get_def_use_mgr()->GetDef(component)->type_id());
if (component_type->AsVector()) {
assert(component_type->AsVector()->element_type() ==
composite_type->AsVector()->element_type());
num_contiguous_elements = component_type->AsVector()->element_count();
} else {
assert(component_type == composite_type->AsVector()->element_type());
num_contiguous_elements = 1;
auto component_type = context->get_type_mgr()->GetType(
context->get_def_use_mgr()->GetDef(component)->type_id());
if (composite_type->AsVector() && component_type->AsVector()) {
// The case where the composite being constructed is a vector and the
// component provided for construction is also a vector is special. It
// requires adding a synonym fact relating each element of the sub-vector
// to the corresponding element of the composite being constructed.
assert(component_type->AsVector()->element_type() ==
composite_type->AsVector()->element_type());
assert(component_type->AsVector()->element_count() <
composite_type->AsVector()->element_count());
for (uint32_t subvector_index = 0;
subvector_index < component_type->AsVector()->element_count();
subvector_index++) {
fact_manager->AddFactDataSynonym(
MakeDataDescriptor(component, {subvector_index}),
MakeDataDescriptor(message_.fresh_id(), {index}), context);
index++;
}
} else {
// The non-vector cases are all easy: the constructor has exactly the same
// number of arguments as the number of sub-components, so we can just
// increment the index.
num_contiguous_elements = 1;
// The other cases are simple: the component is made directly synonymous
// with the element of the composite being constructed.
fact_manager->AddFactDataSynonym(
MakeDataDescriptor(component, {}),
MakeDataDescriptor(message_.fresh_id(), {index}), context);
index++;
}
fact_manager->AddFactDataSynonym(
MakeDataDescriptor(component, {}, 1),
MakeDataDescriptor(message_.fresh_id(), {index},
num_contiguous_elements));
index += num_contiguous_elements;
}
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
}
bool TransformationCompositeConstruct::ComponentsForArrayConstructionAreOK(

View File

@ -106,11 +106,11 @@ void TransformationCompositeExtract::Apply(
indices.push_back(an_index);
}
protobufs::DataDescriptor data_descriptor_for_extracted_element =
MakeDataDescriptor(message_.composite_id(), std::move(indices), 1);
MakeDataDescriptor(message_.composite_id(), std::move(indices));
protobufs::DataDescriptor data_descriptor_for_result_id =
MakeDataDescriptor(message_.fresh_id(), {}, 1);
MakeDataDescriptor(message_.fresh_id(), {});
fact_manager->AddFactDataSynonym(data_descriptor_for_extracted_element,
data_descriptor_for_result_id);
data_descriptor_for_result_id, context);
}
protobufs::Transformation TransformationCompositeExtract::ToMessage() const {

View File

@ -102,9 +102,9 @@ void TransformationCopyObject::Apply(opt::IRContext* context,
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
fact_manager->AddFactDataSynonym(
MakeDataDescriptor(message_.object(), {}, 1),
MakeDataDescriptor(message_.fresh_id(), {}, 1));
fact_manager->AddFactDataSynonym(MakeDataDescriptor(message_.object(), {}),
MakeDataDescriptor(message_.fresh_id(), {}),
context);
}
protobufs::Transformation TransformationCopyObject::ToMessage() const {

View File

@ -46,8 +46,9 @@ bool TransformationReplaceIdWithSynonym::IsApplicable(
auto id_of_interest = message_.id_use_descriptor().id_of_interest();
// Does the fact manager know about the synonym?
if (fact_manager.GetIdsForWhichSynonymsAreKnown().count(id_of_interest) ==
0) {
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;
}

View File

@ -14,6 +14,7 @@
#include <set>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "source/fuzz/equivalence_relation.h"
@ -33,12 +34,11 @@ struct UInt32Hash {
}
};
std::set<uint32_t> ToUIntSet(
EquivalenceRelation<uint32_t, UInt32Hash, UInt32Equals>::ValueSet
pointers) {
std::set<uint32_t> result;
std::vector<uint32_t> ToUIntVector(
const std::vector<const uint32_t*>& pointers) {
std::vector<uint32_t> result;
for (auto pointer : pointers) {
result.insert(*pointer);
result.push_back(*pointer);
}
return result;
}
@ -59,38 +59,63 @@ TEST(EquivalenceRelationTest, BasicTest) {
relation.MakeEquivalent(78, 80);
std::set<uint32_t> class1;
std::vector<uint32_t> class1;
for (uint32_t element = 0; element < 98; element += 2) {
ASSERT_TRUE(relation.IsEquivalent(0, element));
ASSERT_TRUE(relation.IsEquivalent(element, element + 2));
class1.insert(element);
class1.push_back(element);
}
class1.insert(98);
ASSERT_TRUE(class1 == ToUIntSet(relation.GetEquivalenceClass(0)));
ASSERT_TRUE(class1 == ToUIntSet(relation.GetEquivalenceClass(4)));
ASSERT_TRUE(class1 == ToUIntSet(relation.GetEquivalenceClass(40)));
class1.push_back(98);
std::set<uint32_t> class2;
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(0)),
testing::WhenSorted(class1));
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(4)),
testing::WhenSorted(class1));
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(40)),
testing::WhenSorted(class1));
std::vector<uint32_t> class2;
for (uint32_t element = 1; element < 79; element += 2) {
ASSERT_TRUE(relation.IsEquivalent(1, element));
ASSERT_TRUE(relation.IsEquivalent(element, element + 2));
class2.insert(element);
class2.push_back(element);
}
class2.insert(79);
ASSERT_TRUE(class2 == ToUIntSet(relation.GetEquivalenceClass(1)));
ASSERT_TRUE(class2 == ToUIntSet(relation.GetEquivalenceClass(11)));
ASSERT_TRUE(class2 == ToUIntSet(relation.GetEquivalenceClass(31)));
class2.push_back(79);
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(1)),
testing::WhenSorted(class2));
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(11)),
testing::WhenSorted(class2));
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(31)),
testing::WhenSorted(class2));
std::set<uint32_t> class3;
std::vector<uint32_t> class3;
for (uint32_t element = 81; element < 99; element += 2) {
ASSERT_TRUE(relation.IsEquivalent(81, element));
ASSERT_TRUE(relation.IsEquivalent(element, element + 2));
class3.insert(element);
class3.push_back(element);
}
class3.push_back(99);
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(81)),
testing::WhenSorted(class3));
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(91)),
testing::WhenSorted(class3));
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(99)),
testing::WhenSorted(class3));
bool first = true;
std::vector<const uint32_t*> previous_class;
for (auto representative : relation.GetEquivalenceClassRepresentatives()) {
std::vector<const uint32_t*> current_class =
relation.GetEquivalenceClass(*representative);
ASSERT_TRUE(std::find(current_class.begin(), current_class.end(),
representative) != current_class.end());
if (!first) {
ASSERT_TRUE(std::find(previous_class.begin(), previous_class.end(),
representative) == previous_class.end());
}
previous_class = current_class;
first = false;
}
class3.insert(99);
ASSERT_TRUE(class3 == ToUIntSet(relation.GetEquivalenceClass(81)));
ASSERT_TRUE(class3 == ToUIntSet(relation.GetEquivalenceClass(91)));
ASSERT_TRUE(class3 == ToUIntSet(relation.GetEquivalenceClass(99)));
}
} // namespace

View File

@ -21,21 +21,6 @@ namespace spvtools {
namespace fuzz {
namespace {
bool SynonymFactHolds(const FactManager& fact_manager, uint32_t id,
uint32_t synonym_base_id,
std::vector<uint32_t>&& synonym_indices) {
if (fact_manager.GetIdsForWhichSynonymsAreKnown().count(id) == 0) {
return false;
}
auto synonyms = fact_manager.GetSynonymsForId(id);
auto temp =
MakeDataDescriptor(synonym_base_id, std::move(synonym_indices), 1);
return std::find_if(synonyms.begin(), synonyms.end(),
[&temp](const protobufs::DataDescriptor* dd) -> bool {
return DataDescriptorEquals()(dd, &temp);
}) != synonyms.end();
}
TEST(TransformationCompositeConstructTest, ConstructArrays) {
std::string shader = R"(
OpCapability Shader
@ -159,9 +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(SynonymFactHolds(fact_manager, 41, 200, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 45, 200, {1}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 27, 200, {2}));
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})));
// Make a float[2]
TransformationCompositeConstruct make_float_array_length_2(
@ -175,8 +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(SynonymFactHolds(fact_manager, 24, 201, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 40, 201, {1}));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {}),
MakeDataDescriptor(201, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {}),
MakeDataDescriptor(201, {1})));
// Make a bool[3]
TransformationCompositeConstruct make_bool_array_length_3(
@ -192,9 +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(SynonymFactHolds(fact_manager, 33, 202, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 50, 202, {1}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 50, 202, {2}));
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})));
// make a uvec3[2][2]
TransformationCompositeConstruct make_uvec3_array_length_2_2(
@ -208,8 +201,10 @@ TEST(TransformationCompositeConstructTest, ConstructArrays) {
fact_manager));
make_uvec3_array_length_2_2.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 69, 203, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 100, 203, {1}));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(69, {}),
MakeDataDescriptor(203, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(100, {}),
MakeDataDescriptor(203, {1})));
std::string after_transformation = R"(
OpCapability Shader
@ -408,9 +403,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(SynonymFactHolds(fact_manager, 25, 200, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 28, 200, {1}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 31, 200, {2}));
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})));
// make a mat4x3
TransformationCompositeConstruct make_mat43(
@ -422,10 +420,14 @@ 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(SynonymFactHolds(fact_manager, 11, 201, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 13, 201, {1}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 16, 201, {2}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 100, 201, {3}));
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(100, {}),
MakeDataDescriptor(201, {3})));
std::string after_transformation = R"(
OpCapability Shader
@ -609,8 +611,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(SynonymFactHolds(fact_manager, 25, 200, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 19, 200, {1}));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(25, {}),
MakeDataDescriptor(200, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(19, {}),
MakeDataDescriptor(200, {1})));
// make an Outer
TransformationCompositeConstruct make_outer(
@ -624,9 +628,12 @@ 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(SynonymFactHolds(fact_manager, 46, 201, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 200, 201, {1}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 56, 201, {2}));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(46, {}),
MakeDataDescriptor(201, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(200, {}),
MakeDataDescriptor(201, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(56, {}),
MakeDataDescriptor(201, {2})));
std::string after_transformation = R"(
OpCapability Shader
@ -922,8 +929,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(SynonymFactHolds(fact_manager, 17, 200, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 11, 200, {1}));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}),
MakeDataDescriptor(200, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(11, {}),
MakeDataDescriptor(200, {1})));
TransformationCompositeConstruct make_vec3(
25, {12, 32}, MakeInstructionDescriptor(35, SpvOpCompositeConstruct, 0),
@ -936,8 +945,12 @@ TEST(TransformationCompositeConstructTest, ConstructVectors) {
ASSERT_FALSE(make_vec3_bad.IsApplicable(context.get(), fact_manager));
make_vec3.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 12, 201, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 32, 201, {2}));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(12, {0}),
MakeDataDescriptor(201, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(12, {1}),
MakeDataDescriptor(201, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(32, {}),
MakeDataDescriptor(201, {2})));
TransformationCompositeConstruct make_vec4(
44, {32, 32, 10, 11}, MakeInstructionDescriptor(75, SpvOpAccessChain, 0),
@ -950,10 +963,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(SynonymFactHolds(fact_manager, 32, 202, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 32, 202, {1}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 10, 202, {2}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 11, 202, {3}));
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})));
TransformationCompositeConstruct make_ivec2(
51, {126, 120}, MakeInstructionDescriptor(128, SpvOpLoad, 0), 203);
@ -964,8 +981,10 @@ TEST(TransformationCompositeConstructTest, ConstructVectors) {
ASSERT_FALSE(make_ivec2_bad.IsApplicable(context.get(), fact_manager));
make_ivec2.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 126, 203, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 120, 203, {1}));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(126, {}),
MakeDataDescriptor(203, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(120, {}),
MakeDataDescriptor(203, {1})));
TransformationCompositeConstruct make_ivec3(
114, {56, 117, 56}, MakeInstructionDescriptor(66, SpvOpAccessChain, 0),
@ -978,9 +997,12 @@ 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(SynonymFactHolds(fact_manager, 56, 204, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 117, 204, {1}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 56, 204, {2}));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(56, {}),
MakeDataDescriptor(204, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(117, {}),
MakeDataDescriptor(204, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(56, {}),
MakeDataDescriptor(204, {2})));
TransformationCompositeConstruct make_ivec4(
122, {56, 117, 117, 117}, MakeInstructionDescriptor(66, SpvOpIAdd, 0),
@ -993,10 +1015,14 @@ 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(SynonymFactHolds(fact_manager, 56, 205, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 117, 205, {1}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 117, 205, {2}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 117, 205, {3}));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(56, {}),
MakeDataDescriptor(205, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(117, {}),
MakeDataDescriptor(205, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(117, {}),
MakeDataDescriptor(205, {2})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(117, {}),
MakeDataDescriptor(205, {3})));
TransformationCompositeConstruct make_uvec2(
86, {18, 38}, MakeInstructionDescriptor(133, SpvOpAccessChain, 0), 206);
@ -1006,8 +1032,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(SynonymFactHolds(fact_manager, 18, 206, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 38, 206, {1}));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(18, {}),
MakeDataDescriptor(206, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(38, {}),
MakeDataDescriptor(206, {1})));
TransformationCompositeConstruct make_uvec3(
59, {14, 18, 136}, MakeInstructionDescriptor(137, SpvOpReturn, 0), 207);
@ -1018,9 +1046,12 @@ 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(SynonymFactHolds(fact_manager, 14, 207, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 18, 207, {1}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 136, 207, {2}));
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(136, {}),
MakeDataDescriptor(207, {2})));
TransformationCompositeConstruct make_uvec4(
131, {14, 18, 136, 136},
@ -1033,10 +1064,14 @@ 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(SynonymFactHolds(fact_manager, 14, 208, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 18, 208, {1}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 136, 208, {2}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 136, 208, {3}));
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(136, {}),
MakeDataDescriptor(208, {2})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(136, {}),
MakeDataDescriptor(208, {3})));
TransformationCompositeConstruct make_bvec2(
102,
@ -1057,8 +1092,10 @@ TEST(TransformationCompositeConstructTest, ConstructVectors) {
ASSERT_FALSE(make_bvec2_bad.IsApplicable(context.get(), fact_manager));
make_bvec2.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 111, 209, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 41, 209, {1}));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(111, {}),
MakeDataDescriptor(209, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(41, {}),
MakeDataDescriptor(209, {1})));
TransformationCompositeConstruct make_bvec3(
93, {108, 73}, MakeInstructionDescriptor(108, SpvOpStore, 0), 210);
@ -1069,8 +1106,12 @@ TEST(TransformationCompositeConstructTest, ConstructVectors) {
ASSERT_FALSE(make_bvec3_bad.IsApplicable(context.get(), fact_manager));
make_bvec3.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 108, 210, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 73, 210, {2}));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {0}),
MakeDataDescriptor(210, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {1}),
MakeDataDescriptor(210, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(73, {}),
MakeDataDescriptor(210, {2})));
TransformationCompositeConstruct make_bvec4(
70, {108, 108}, MakeInstructionDescriptor(108, SpvOpBranch, 0), 211);
@ -1081,8 +1122,14 @@ TEST(TransformationCompositeConstructTest, ConstructVectors) {
ASSERT_FALSE(make_bvec4_bad.IsApplicable(context.get(), fact_manager));
make_bvec4.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 108, 211, {0}));
ASSERT_TRUE(SynonymFactHolds(fact_manager, 108, 211, {2}));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {0}),
MakeDataDescriptor(211, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {1}),
MakeDataDescriptor(211, {1})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {0}),
MakeDataDescriptor(211, {2})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {1}),
MakeDataDescriptor(211, {3})));
std::string after_transformation = R"(
OpCapability Shader

View File

@ -20,13 +20,6 @@ namespace spvtools {
namespace fuzz {
namespace {
bool IsSynonymous(const FactManager& fact_manager, uint32_t id,
uint32_t composite_id, std::vector<uint32_t>&& indices) {
protobufs::DataDescriptor data_descriptor =
MakeDataDescriptor(composite_id, std::move(indices), 1);
return fact_manager.GetSynonymsForId(id).count(&data_descriptor) == 1;
}
TEST(TransformationCompositeExtractTest, BasicTest) {
std::string shader = R"(
OpCapability Shader
@ -179,12 +172,18 @@ TEST(TransformationCompositeExtractTest, BasicTest) {
transformation_6.Apply(context.get(), &fact_manager);
ASSERT_TRUE(IsValid(env, context.get()));
ASSERT_TRUE(IsSynonymous(fact_manager, 201, 100, {2}));
ASSERT_TRUE(IsSynonymous(fact_manager, 202, 104, {0, 2}));
ASSERT_TRUE(IsSynonymous(fact_manager, 203, 104, {0}));
ASSERT_TRUE(IsSynonymous(fact_manager, 204, 101, {0}));
ASSERT_TRUE(IsSynonymous(fact_manager, 205, 102, {2}));
ASSERT_TRUE(IsSynonymous(fact_manager, 206, 103, {1}));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(201, {}),
MakeDataDescriptor(100, {2})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(202, {}),
MakeDataDescriptor(104, {0, 2})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(203, {}),
MakeDataDescriptor(104, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(204, {}),
MakeDataDescriptor(101, {0})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(205, {}),
MakeDataDescriptor(102, {2})));
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(206, {}),
MakeDataDescriptor(103, {1})));
std::string after_transformation = R"(
OpCapability Shader

View File

@ -60,14 +60,16 @@ TEST(TransformationCopyObjectTest, CopyBooleanConstants) {
ASSERT_TRUE(copy_true.IsApplicable(context.get(), fact_manager));
copy_true.Apply(context.get(), &fact_manager);
std::set<uint32_t> ids_for_which_synonyms_are_known =
auto ids_for_which_synonyms_are_known =
fact_manager.GetIdsForWhichSynonymsAreKnown();
ASSERT_EQ(2, ids_for_which_synonyms_are_known.size());
ASSERT_TRUE(ids_for_which_synonyms_are_known.find(7) !=
ids_for_which_synonyms_are_known.end());
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());
protobufs::DataDescriptor descriptor_100 = MakeDataDescriptor(100, {}, 1);
ASSERT_TRUE(fact_manager.GetSynonymsForId(7).count(&descriptor_100) > 0);
protobufs::DataDescriptor descriptor_100 = MakeDataDescriptor(100, {});
ASSERT_TRUE(
fact_manager.IsSynonymous(MakeDataDescriptor(7, {}), descriptor_100));
}
{
@ -75,14 +77,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);
std::set<uint32_t> ids_for_which_synonyms_are_known =
auto ids_for_which_synonyms_are_known =
fact_manager.GetIdsForWhichSynonymsAreKnown();
ASSERT_EQ(4, ids_for_which_synonyms_are_known.size());
ASSERT_TRUE(ids_for_which_synonyms_are_known.find(8) !=
ids_for_which_synonyms_are_known.end());
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());
protobufs::DataDescriptor descriptor_101 = MakeDataDescriptor(101, {}, 1);
ASSERT_TRUE(fact_manager.GetSynonymsForId(8).count(&descriptor_101) > 0);
protobufs::DataDescriptor descriptor_101 = MakeDataDescriptor(101, {});
ASSERT_TRUE(
fact_manager.IsSynonymous(MakeDataDescriptor(8, {}), descriptor_101));
}
{
@ -90,14 +94,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);
std::set<uint32_t> ids_for_which_synonyms_are_known =
auto ids_for_which_synonyms_are_known =
fact_manager.GetIdsForWhichSynonymsAreKnown();
ASSERT_EQ(5, ids_for_which_synonyms_are_known.size());
ASSERT_TRUE(ids_for_which_synonyms_are_known.find(101) !=
ids_for_which_synonyms_are_known.end());
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());
protobufs::DataDescriptor descriptor_102 = MakeDataDescriptor(102, {}, 1);
ASSERT_TRUE(fact_manager.GetSynonymsForId(101).count(&descriptor_102) > 0);
protobufs::DataDescriptor descriptor_102 = MakeDataDescriptor(102, {});
ASSERT_TRUE(
fact_manager.IsSynonymous(MakeDataDescriptor(101, {}), descriptor_102));
}
{
@ -105,14 +111,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);
std::set<uint32_t> ids_for_which_synonyms_are_known =
auto ids_for_which_synonyms_are_known =
fact_manager.GetIdsForWhichSynonymsAreKnown();
ASSERT_EQ(6, ids_for_which_synonyms_are_known.size());
ASSERT_TRUE(ids_for_which_synonyms_are_known.find(7) !=
ids_for_which_synonyms_are_known.end());
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());
protobufs::DataDescriptor descriptor_103 = MakeDataDescriptor(103, {}, 1);
ASSERT_TRUE(fact_manager.GetSynonymsForId(7).count(&descriptor_103) > 0);
protobufs::DataDescriptor descriptor_103 = MakeDataDescriptor(103, {});
ASSERT_TRUE(
fact_manager.IsSynonymous(MakeDataDescriptor(7, {}), descriptor_103));
}
std::string after_transformation = R"(