SPIRV-Tools/source/fuzz/fact_manager/fact_manager.cpp
alan-baker d35a78db57
Switch SPIRV-Tools to use spirv.hpp11 internally (#4981)
Fixes #4960

* Switches to using enum classes with an underlying type to avoid
  undefined behaviour
2022-11-04 17:27:10 -04:00

280 lines
9.6 KiB
C++

// 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 <sstream>
#include <unordered_map>
#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 << " " << 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<uint32_t> FactManager::GetConstantsAvailableFromUniformsForType(
uint32_t type_id) const {
return constant_uniform_facts_.GetConstantsAvailableFromUniformsForType(
type_id);
}
std::vector<protobufs::UniformBufferElementDescriptor>
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<uint32_t> FactManager::GetTypesForWhichUniformValuesAreKnown()
const {
return constant_uniform_facts_.GetTypesForWhichUniformValuesAreKnown();
}
const std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>&
FactManager::GetConstantUniformFactsAndTypes() const {
return constant_uniform_facts_.GetConstantUniformFactsAndTypes();
}
std::vector<uint32_t> FactManager::GetIdsForWhichSynonymsAreKnown() const {
return data_synonym_and_id_equation_facts_.GetIdsForWhichSynonymsAreKnown();
}
std::vector<const protobufs::DataDescriptor*> FactManager::GetAllSynonyms()
const {
return data_synonym_and_id_equation_facts_.GetAllKnownSynonyms();
}
std::vector<const protobufs::DataDescriptor*>
FactManager::GetSynonymsForDataDescriptor(
const protobufs::DataDescriptor& data_descriptor) const {
return data_synonym_and_id_equation_facts_.GetSynonymsForDataDescriptor(
data_descriptor);
}
std::vector<const protobufs::DataDescriptor*> 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<uint32_t> 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, spv::Op opcode,
const std::vector<uint32_t>& rhs_id) {
protobufs::FactIdEquation fact;
fact.set_lhs_id(lhs_id);
fact.set_opcode(uint32_t(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