// Copyright (c) 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "fact_manager.h" #include #include #include "source/fuzz/uniform_buffer_element_descriptor.h" #include "source/opt/ir_context.h" namespace spvtools { namespace fuzz { namespace { std::string ToString(const protobufs::FactConstantUniform& fact) { std::stringstream stream; stream << "(" << fact.uniform_buffer_element_descriptor().descriptor_set() << ", " << fact.uniform_buffer_element_descriptor().binding() << ")["; bool first = true; for (auto index : fact.uniform_buffer_element_descriptor().index()) { if (first) { first = false; } else { stream << ", "; } stream << index; } stream << "] == ["; first = true; for (auto constant_word : fact.constant_word()) { if (first) { first = false; } else { stream << ", "; } stream << constant_word; } stream << "]"; return stream.str(); } std::string ToString(const protobufs::FactDataSynonym& fact) { std::stringstream stream; stream << fact.data1() << " = " << fact.data2(); return stream.str(); } std::string ToString(const protobufs::FactIdEquation& fact) { std::stringstream stream; stream << fact.lhs_id(); stream << " " << static_cast(fact.opcode()); for (auto rhs_id : fact.rhs_id()) { stream << " " << rhs_id; } return stream.str(); } std::string ToString(const protobufs::Fact& fact) { switch (fact.fact_case()) { case protobufs::Fact::kConstantUniformFact: return ToString(fact.constant_uniform_fact()); case protobufs::Fact::kDataSynonymFact: return ToString(fact.data_synonym_fact()); case protobufs::Fact::kIdEquationFact: return ToString(fact.id_equation_fact()); default: assert(false && "Stringification not supported for this fact."); return ""; } } } // namespace FactManager::FactManager(opt::IRContext* ir_context) : constant_uniform_facts_(ir_context), data_synonym_and_id_equation_facts_(ir_context), dead_block_facts_(ir_context), livesafe_function_facts_(ir_context), irrelevant_value_facts_(ir_context) {} void FactManager::AddInitialFacts(const MessageConsumer& message_consumer, const protobufs::FactSequence& facts) { for (auto& fact : facts.fact()) { if (!MaybeAddFact(fact)) { auto message = "Invalid fact " + ToString(fact) + " ignored."; message_consumer(SPV_MSG_WARNING, nullptr, {}, message.c_str()); } } } bool FactManager::MaybeAddFact(const fuzz::protobufs::Fact& fact) { switch (fact.fact_case()) { case protobufs::Fact::kBlockIsDeadFact: return dead_block_facts_.MaybeAddFact(fact.block_is_dead_fact()); case protobufs::Fact::kConstantUniformFact: return constant_uniform_facts_.MaybeAddFact(fact.constant_uniform_fact()); case protobufs::Fact::kDataSynonymFact: return data_synonym_and_id_equation_facts_.MaybeAddFact( fact.data_synonym_fact(), dead_block_facts_, irrelevant_value_facts_); case protobufs::Fact::kFunctionIsLivesafeFact: return livesafe_function_facts_.MaybeAddFact( fact.function_is_livesafe_fact()); case protobufs::Fact::kIdEquationFact: return data_synonym_and_id_equation_facts_.MaybeAddFact( fact.id_equation_fact(), dead_block_facts_, irrelevant_value_facts_); case protobufs::Fact::kIdIsIrrelevant: return irrelevant_value_facts_.MaybeAddFact( fact.id_is_irrelevant(), data_synonym_and_id_equation_facts_); case protobufs::Fact::kPointeeValueIsIrrelevantFact: return irrelevant_value_facts_.MaybeAddFact( fact.pointee_value_is_irrelevant_fact(), data_synonym_and_id_equation_facts_); case protobufs::Fact::FACT_NOT_SET: assert(false && "The fact must be set"); return false; } assert(false && "Unreachable"); return false; } void FactManager::AddFactDataSynonym(const protobufs::DataDescriptor& data1, const protobufs::DataDescriptor& data2) { protobufs::FactDataSynonym fact; *fact.mutable_data1() = data1; *fact.mutable_data2() = data2; auto success = data_synonym_and_id_equation_facts_.MaybeAddFact( fact, dead_block_facts_, irrelevant_value_facts_); (void)success; // Keep compilers happy in release mode. assert(success && "Unable to create DataSynonym fact"); } std::vector FactManager::GetConstantsAvailableFromUniformsForType( uint32_t type_id) const { return constant_uniform_facts_.GetConstantsAvailableFromUniformsForType( type_id); } std::vector FactManager::GetUniformDescriptorsForConstant(uint32_t constant_id) const { return constant_uniform_facts_.GetUniformDescriptorsForConstant(constant_id); } uint32_t FactManager::GetConstantFromUniformDescriptor( const protobufs::UniformBufferElementDescriptor& uniform_descriptor) const { return constant_uniform_facts_.GetConstantFromUniformDescriptor( uniform_descriptor); } std::vector FactManager::GetTypesForWhichUniformValuesAreKnown() const { return constant_uniform_facts_.GetTypesForWhichUniformValuesAreKnown(); } const std::vector>& FactManager::GetConstantUniformFactsAndTypes() const { return constant_uniform_facts_.GetConstantUniformFactsAndTypes(); } std::vector FactManager::GetIdsForWhichSynonymsAreKnown() const { return data_synonym_and_id_equation_facts_.GetIdsForWhichSynonymsAreKnown(); } std::vector FactManager::GetAllSynonyms() const { return data_synonym_and_id_equation_facts_.GetAllKnownSynonyms(); } std::vector FactManager::GetSynonymsForDataDescriptor( const protobufs::DataDescriptor& data_descriptor) const { return data_synonym_and_id_equation_facts_.GetSynonymsForDataDescriptor( data_descriptor); } std::vector FactManager::GetSynonymsForId( uint32_t id) const { return data_synonym_and_id_equation_facts_.GetSynonymsForId(id); } bool FactManager::IsSynonymous( const protobufs::DataDescriptor& data_descriptor1, const protobufs::DataDescriptor& data_descriptor2) const { return data_synonym_and_id_equation_facts_.IsSynonymous(data_descriptor1, data_descriptor2); } bool FactManager::BlockIsDead(uint32_t block_id) const { return dead_block_facts_.BlockIsDead(block_id); } void FactManager::AddFactBlockIsDead(uint32_t block_id) { protobufs::FactBlockIsDead fact; fact.set_block_id(block_id); auto success = dead_block_facts_.MaybeAddFact(fact); (void)success; // Keep compilers happy in release mode. assert(success && "|block_id| is invalid"); } bool FactManager::FunctionIsLivesafe(uint32_t function_id) const { return livesafe_function_facts_.FunctionIsLivesafe(function_id); } void FactManager::AddFactFunctionIsLivesafe(uint32_t function_id) { protobufs::FactFunctionIsLivesafe fact; fact.set_function_id(function_id); auto success = livesafe_function_facts_.MaybeAddFact(fact); (void)success; // Keep compilers happy in release mode. assert(success && "|function_id| is invalid"); } bool FactManager::PointeeValueIsIrrelevant(uint32_t pointer_id) const { return irrelevant_value_facts_.PointeeValueIsIrrelevant(pointer_id); } bool FactManager::IdIsIrrelevant(uint32_t result_id) const { return irrelevant_value_facts_.IdIsIrrelevant(result_id, dead_block_facts_); } std::unordered_set FactManager::GetIrrelevantIds() const { return irrelevant_value_facts_.GetIrrelevantIds(dead_block_facts_); } void FactManager::AddFactValueOfPointeeIsIrrelevant(uint32_t pointer_id) { protobufs::FactPointeeValueIsIrrelevant fact; fact.set_pointer_id(pointer_id); auto success = irrelevant_value_facts_.MaybeAddFact( fact, data_synonym_and_id_equation_facts_); (void)success; // Keep compilers happy in release mode. assert(success && "|pointer_id| is invalid"); } void FactManager::AddFactIdIsIrrelevant(uint32_t result_id) { protobufs::FactIdIsIrrelevant fact; fact.set_result_id(result_id); auto success = irrelevant_value_facts_.MaybeAddFact( fact, data_synonym_and_id_equation_facts_); (void)success; // Keep compilers happy in release mode. assert(success && "|result_id| is invalid"); } void FactManager::AddFactIdEquation(uint32_t lhs_id, SpvOp opcode, const std::vector& rhs_id) { protobufs::FactIdEquation fact; fact.set_lhs_id(lhs_id); fact.set_opcode(opcode); for (auto an_rhs_id : rhs_id) { fact.add_rhs_id(an_rhs_id); } auto success = data_synonym_and_id_equation_facts_.MaybeAddFact( fact, dead_block_facts_, irrelevant_value_facts_); (void)success; // Keep compilers happy in release mode. assert(success && "Can't create IdIsIrrelevant fact"); } void FactManager::ComputeClosureOfFacts( uint32_t maximum_equivalence_class_size) { data_synonym_and_id_equation_facts_.ComputeClosureOfFacts( maximum_equivalence_class_size); } } // namespace fuzz } // namespace spvtools