Updated spirv-tools.

This commit is contained in:
Бранимир Караџић 2019-11-04 20:20:05 -08:00
parent 15a4bcda82
commit 274757090d
24 changed files with 397 additions and 233 deletions

View File

@ -295,6 +295,14 @@ config("spvtools_internal_config") {
}
}
source_set("spv_headers") {
sources = [
"$spirv_headers/include/spirv/1.2/GLSL.std.450.h",
"$spirv_headers/include/spirv/unified1/OpenCL.std.h",
"$spirv_headers/include/spirv/unified1/spirv.h",
]
}
source_set("spvtools_headers") {
sources = [
"include/spirv-tools/instrument.hpp",
@ -324,16 +332,22 @@ static_library("spvtools") {
"source/assembly_grammar.h",
"source/binary.cpp",
"source/binary.h",
"source/cfa.h",
"source/diagnostic.cpp",
"source/diagnostic.h",
"source/disassemble.cpp",
"source/disassemble.h",
"source/enum_set.h",
"source/enum_string_mapping.cpp",
"source/enum_string_mapping.h",
"source/ext_inst.cpp",
"source/ext_inst.h",
"source/extensions.cpp",
"source/extensions.h",
"source/instruction.h",
"source/latest_version_glsl_std_450_header.h",
"source/latest_version_opencl_std_header.h",
"source/latest_version_spirv_header.h",
"source/libspirv.cpp",
"source/macro.h",
"source/name_mapper.cpp",
@ -379,6 +393,7 @@ static_library("spvtools") {
]
public_deps = [
":spv_headers",
":spvtools_core_enums_unified1",
":spvtools_headers",
]
@ -393,8 +408,12 @@ static_library("spvtools") {
static_library("spvtools_val") {
sources = [
"source/val/basic_block.cpp",
"source/val/basic_block.h",
"source/val/construct.cpp",
"source/val/construct.h",
"source/val/decoration.h",
"source/val/function.cpp",
"source/val/function.h",
"source/val/instruction.cpp",
"source/val/validate.cpp",
"source/val/validate.h",
@ -425,14 +444,17 @@ static_library("spvtools_val") {
"source/val/validate_logicals.cpp",
"source/val/validate_memory.cpp",
"source/val/validate_memory_semantics.cpp",
"source/val/validate_memory_semantics.h",
"source/val/validate_misc.cpp",
"source/val/validate_mode_setting.cpp",
"source/val/validate_non_uniform.cpp",
"source/val/validate_primitives.cpp",
"source/val/validate_scopes.cpp",
"source/val/validate_scopes.h",
"source/val/validate_small_type_uses.cpp",
"source/val/validate_type.cpp",
"source/val/validation_state.cpp",
"source/val/validation_state.h",
]
deps = [
@ -720,6 +742,7 @@ static_library("spvtools_reduce") {
"source/reduce/reducer.h",
"source/reduce/reduction_opportunity.cpp",
"source/reduce/reduction_opportunity.h",
"source/reduce/reduction_opportunity_finder.h",
"source/reduce/reduction_pass.cpp",
"source/reduce/reduction_pass.h",
"source/reduce/reduction_util.cpp",
@ -872,7 +895,9 @@ source_set("spvtools_util_cli_consumer") {
"tools/util/cli_consumer.cpp",
"tools/util/cli_consumer.h",
]
deps = [ ":spvtools_headers" ]
deps = [
":spvtools_headers",
]
configs += [ ":spvtools_internal_config" ]
}

View File

@ -1 +1 @@
"v2019.5-dev", "SPIRV-Tools v2019.5-dev v2019.4-144-g42f88523"
"v2019.5-dev", "SPIRV-Tools v2019.5-dev v2019.4-153-ge0d5544c"

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

@ -160,7 +160,6 @@
namespace spvtools {
namespace opt {
using opt::BasicBlock;
using opt::Instruction;
using opt::Operand;
using spvtools::MakeUnique;

View File

@ -81,8 +81,8 @@ class GraphicsRobustAccessPass : public Pass {
// sign extension or zero extension. The new instruction is inserted
// immediately before |before_inst|, and is analyzed for definitions and uses.
// Returns the newly inserted instruction. Assumes the |value| is an integer
// scalar of a narrower type than |bitwidth| bits.
Instruction* WidenInteger(bool sign_extend, uint32_t bitwidth,
// scalar of a narrower type than |bit_width| bits.
Instruction* WidenInteger(bool sign_extend, uint32_t bit_width,
Instruction* value, Instruction* before_inst);
// Returns a new instruction that invokes the UClamp GLSL.std.450 extended
@ -109,7 +109,8 @@ class GraphicsRobustAccessPass : public Pass {
// the module is modified. Returns a status code to indicate success
// or failure. If assumptions are not met, returns an error status code
// and emits a diagnostic.
spv_result_t ClampCoordinateForImageTexelPointer(opt::Instruction* itp);
spv_result_t ClampCoordinateForImageTexelPointer(
opt::Instruction* image_texel_pointer);
// Gets the instruction that defines the given id.
opt::Instruction* GetDef(uint32_t id) {

View File

@ -560,23 +560,26 @@ bool Optimizer::Run(const uint32_t* original_binary,
return false;
}
optimized_binary->clear();
context->module()->ToBinary(optimized_binary, /* skip_nop = */ true);
#ifndef NDEBUG
if (status == opt::Pass::Status::SuccessWithoutChange) {
std::vector<uint32_t> optimized_binary_with_nop;
context->module()->ToBinary(&optimized_binary_with_nop,
/* skip_nop = */ false);
auto changed = optimized_binary_with_nop.size() != original_binary_size ||
memcmp(optimized_binary_with_nop.data(), original_binary,
original_binary_size) != 0;
assert(!changed &&
"Binary unexpectedly changed despite optimizer saying there was no "
"change");
assert(optimized_binary_with_nop.size() == original_binary_size &&
"Binary size unexpectedly changed despite the optimizer saying "
"there was no change");
assert(memcmp(optimized_binary_with_nop.data(), original_binary,
original_binary_size) == 0 &&
"Binary content unexpectedly changed despite the optimizer saying "
"there was no change");
}
#endif // !NDEBUG
// Note that |original_binary| and |optimized_binary| may share the same
// buffer and the below will invalidate |original_binary|.
optimized_binary->clear();
context->module()->ToBinary(optimized_binary, /* skip_nop = */ true);
return true;
}

View File

@ -15,7 +15,7 @@
#include "source/print.h"
#if defined(SPIRV_ANDROID) || defined(SPIRV_LINUX) || defined(SPIRV_MAC) || \
defined(SPIRV_FREEBSD) || defined(SPIRV_EMSCRIPTEN)
defined(SPIRV_IOS) || defined(SPIRV_FREEBSD) || defined(SPIRV_EMSCRIPTEN)
namespace spvtools {
clr::reset::operator const char*() { return "\x1b[0m"; }

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"(

View File

@ -55,8 +55,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
options++) {
spvBinaryToText(context, input.data(), input.size(), options, &text,
&diagnostic);
if (diagnostic) spvDiagnosticDestroy(diagnostic);
if (text) spvTextDestroy(text);
if (diagnostic) {
spvDiagnosticDestroy(diagnostic);
diagnostic = nullptr;
}
if (text) {
spvTextDestroy(text);
text = nullptr;
}
}
spvContextDestroy(context);

View File

@ -199,11 +199,11 @@ std::string ACCheck(const std::string& access_chain_inst,
const std::string& original,
const std::string& transformed) {
return "\n ; CHECK: %ac = " + access_chain_inst + " %ptr_ty %var" +
(transformed.size() ? " " : "") + transformed +
(transformed.empty() ? "" : " ") + transformed +
"\n ; CHECK-NOT: " + access_chain_inst +
"\n ; CHECK-NEXT: OpReturn"
"\n %ac = " +
access_chain_inst + " %ptr_ty %var " + (original.size() ? " " : "") +
access_chain_inst + " %ptr_ty %var " + (original.empty() ? "" : " ") +
original + "\n";
}
@ -211,11 +211,11 @@ std::string ACCheckFail(const std::string& access_chain_inst,
const std::string& original,
const std::string& transformed) {
return "\n ; CHECK: %ac = " + access_chain_inst + " %ptr_ty %var" +
(transformed.size() ? " " : "") + transformed +
(transformed.empty() ? "" : " ") + transformed +
"\n ; CHECK-NOT: " + access_chain_inst +
"\n ; CHECK-NOT: OpReturn"
"\n %ac = " +
access_chain_inst + " %ptr_ty %var " + (original.size() ? " " : "") +
access_chain_inst + " %ptr_ty %var " + (original.empty() ? "" : " ") +
original + "\n";
}

View File

@ -116,7 +116,7 @@ def describe(directory):
# e.g. because the source tree might not be in a git tree.
# In this case, usually use a timestamp. However, to ensure
# reproducible builds, allow the builder to override the wall
# clock time with enviornment variable SOURCE_DATE_EPOCH
# clock time with environment variable SOURCE_DATE_EPOCH
# containing a (presumably) fixed timestamp.
timestamp = int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))
formatted = datetime.datetime.utcfromtimestamp(timestamp).isoformat()

View File

@ -18,7 +18,7 @@
"id": "spirv",
"configuration": "spirv.configuration.json",
"extensions": [
"spirv"
"spvasm"
]
}
],