mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-10-18 11:10:05 +00:00
spirv-fuzz: Split the fact manager into multiple files (#3699)
Part of #3698. This splits various components of the fact manager into multiple files.
This commit is contained in:
parent
5adc5ae643
commit
230f363e6d
@ -32,7 +32,12 @@ if(SPIRV_BUILD_FUZZER)
|
||||
call_graph.h
|
||||
data_descriptor.h
|
||||
equivalence_relation.h
|
||||
fact_manager.h
|
||||
fact_manager/constant_uniform_facts.h
|
||||
fact_manager/data_synonym_and_id_equation_facts.h
|
||||
fact_manager/dead_block_facts.h
|
||||
fact_manager/fact_manager.h
|
||||
fact_manager/irrelevant_value_facts.h
|
||||
fact_manager/livesafe_function_facts.h
|
||||
force_render_red.h
|
||||
fuzzer.h
|
||||
fuzzer_context.h
|
||||
@ -176,7 +181,12 @@ if(SPIRV_BUILD_FUZZER)
|
||||
|
||||
call_graph.cpp
|
||||
data_descriptor.cpp
|
||||
fact_manager.cpp
|
||||
fact_manager/constant_uniform_facts.cpp
|
||||
fact_manager/data_synonym_and_id_equation_facts.cpp
|
||||
fact_manager/dead_block_facts.cpp
|
||||
fact_manager/fact_manager.cpp
|
||||
fact_manager/irrelevant_value_facts.cpp
|
||||
fact_manager/livesafe_function_facts.cpp
|
||||
force_render_red.cpp
|
||||
fuzzer.cpp
|
||||
fuzzer_context.cpp
|
||||
|
235
source/fuzz/fact_manager/constant_uniform_facts.cpp
Normal file
235
source/fuzz/fact_manager/constant_uniform_facts.cpp
Normal file
@ -0,0 +1,235 @@
|
||||
// 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 "source/fuzz/fact_manager/constant_uniform_facts.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/uniform_buffer_element_descriptor.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace fact_manager {
|
||||
|
||||
uint32_t ConstantUniformFacts::GetConstantId(
|
||||
opt::IRContext* context,
|
||||
const protobufs::FactConstantUniform& constant_uniform_fact,
|
||||
uint32_t type_id) {
|
||||
auto type = context->get_type_mgr()->GetType(type_id);
|
||||
assert(type != nullptr && "Unknown type id.");
|
||||
const opt::analysis::Constant* known_constant;
|
||||
if (type->AsInteger()) {
|
||||
opt::analysis::IntConstant candidate_constant(
|
||||
type->AsInteger(), GetConstantWords(constant_uniform_fact));
|
||||
known_constant =
|
||||
context->get_constant_mgr()->FindConstant(&candidate_constant);
|
||||
} else {
|
||||
assert(
|
||||
type->AsFloat() &&
|
||||
"Uniform constant facts are only supported for int and float types.");
|
||||
opt::analysis::FloatConstant candidate_constant(
|
||||
type->AsFloat(), GetConstantWords(constant_uniform_fact));
|
||||
known_constant =
|
||||
context->get_constant_mgr()->FindConstant(&candidate_constant);
|
||||
}
|
||||
if (!known_constant) {
|
||||
return 0;
|
||||
}
|
||||
return context->get_constant_mgr()->FindDeclaredConstant(known_constant,
|
||||
type_id);
|
||||
}
|
||||
|
||||
std::vector<uint32_t> ConstantUniformFacts::GetConstantWords(
|
||||
const protobufs::FactConstantUniform& constant_uniform_fact) {
|
||||
std::vector<uint32_t> result;
|
||||
for (auto constant_word : constant_uniform_fact.constant_word()) {
|
||||
result.push_back(constant_word);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ConstantUniformFacts::DataMatches(
|
||||
const opt::Instruction& constant_instruction,
|
||||
const protobufs::FactConstantUniform& constant_uniform_fact) {
|
||||
assert(constant_instruction.opcode() == SpvOpConstant);
|
||||
std::vector<uint32_t> data_in_constant;
|
||||
for (uint32_t i = 0; i < constant_instruction.NumInOperands(); i++) {
|
||||
data_in_constant.push_back(constant_instruction.GetSingleWordInOperand(i));
|
||||
}
|
||||
return data_in_constant == GetConstantWords(constant_uniform_fact);
|
||||
}
|
||||
|
||||
std::vector<uint32_t>
|
||||
ConstantUniformFacts::GetConstantsAvailableFromUniformsForType(
|
||||
opt::IRContext* ir_context, uint32_t type_id) const {
|
||||
std::vector<uint32_t> result;
|
||||
std::set<uint32_t> already_seen;
|
||||
for (auto& fact_and_type_id : facts_and_type_ids_) {
|
||||
if (fact_and_type_id.second != type_id) {
|
||||
continue;
|
||||
}
|
||||
if (auto constant_id =
|
||||
GetConstantId(ir_context, fact_and_type_id.first, type_id)) {
|
||||
if (already_seen.find(constant_id) == already_seen.end()) {
|
||||
result.push_back(constant_id);
|
||||
already_seen.insert(constant_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<protobufs::UniformBufferElementDescriptor>
|
||||
ConstantUniformFacts::GetUniformDescriptorsForConstant(
|
||||
opt::IRContext* ir_context, uint32_t constant_id) const {
|
||||
std::vector<protobufs::UniformBufferElementDescriptor> result;
|
||||
auto constant_inst = ir_context->get_def_use_mgr()->GetDef(constant_id);
|
||||
assert(constant_inst->opcode() == SpvOpConstant &&
|
||||
"The given id must be that of a constant");
|
||||
auto type_id = constant_inst->type_id();
|
||||
for (auto& fact_and_type_id : facts_and_type_ids_) {
|
||||
if (fact_and_type_id.second != type_id) {
|
||||
continue;
|
||||
}
|
||||
if (DataMatches(*constant_inst, fact_and_type_id.first)) {
|
||||
result.emplace_back(
|
||||
fact_and_type_id.first.uniform_buffer_element_descriptor());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t ConstantUniformFacts::GetConstantFromUniformDescriptor(
|
||||
opt::IRContext* context,
|
||||
const protobufs::UniformBufferElementDescriptor& uniform_descriptor) const {
|
||||
// Consider each fact.
|
||||
for (auto& fact_and_type : facts_and_type_ids_) {
|
||||
// Check whether the uniform descriptor associated with the fact matches
|
||||
// |uniform_descriptor|.
|
||||
if (UniformBufferElementDescriptorEquals()(
|
||||
&uniform_descriptor,
|
||||
&fact_and_type.first.uniform_buffer_element_descriptor())) {
|
||||
return GetConstantId(context, fact_and_type.first, fact_and_type.second);
|
||||
}
|
||||
}
|
||||
// No fact associated with the given uniform descriptor was found.
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<uint32_t>
|
||||
ConstantUniformFacts::GetTypesForWhichUniformValuesAreKnown() const {
|
||||
std::vector<uint32_t> result;
|
||||
for (auto& fact_and_type : facts_and_type_ids_) {
|
||||
if (std::find(result.begin(), result.end(), fact_and_type.second) ==
|
||||
result.end()) {
|
||||
result.push_back(fact_and_type.second);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ConstantUniformFacts::FloatingPointValueIsSuitable(
|
||||
const protobufs::FactConstantUniform& fact, uint32_t width) {
|
||||
const uint32_t kFloatWidth = 32;
|
||||
const uint32_t kDoubleWidth = 64;
|
||||
if (width != kFloatWidth && width != kDoubleWidth) {
|
||||
// Only 32- and 64-bit floating-point types are handled.
|
||||
return false;
|
||||
}
|
||||
std::vector<uint32_t> words = GetConstantWords(fact);
|
||||
if (width == 32) {
|
||||
float value;
|
||||
memcpy(&value, words.data(), sizeof(float));
|
||||
if (!std::isfinite(value)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
double value;
|
||||
memcpy(&value, words.data(), sizeof(double));
|
||||
if (!std::isfinite(value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConstantUniformFacts::AddFact(const protobufs::FactConstantUniform& fact,
|
||||
opt::IRContext* context) {
|
||||
// Try to find a unique instruction that declares a variable such that the
|
||||
// variable is decorated with the descriptor set and binding associated with
|
||||
// the constant uniform fact.
|
||||
opt::Instruction* uniform_variable = FindUniformVariable(
|
||||
fact.uniform_buffer_element_descriptor(), context, true);
|
||||
|
||||
if (!uniform_variable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(SpvOpVariable == uniform_variable->opcode());
|
||||
assert(SpvStorageClassUniform == uniform_variable->GetSingleWordInOperand(0));
|
||||
|
||||
auto should_be_uniform_pointer_type =
|
||||
context->get_type_mgr()->GetType(uniform_variable->type_id());
|
||||
if (!should_be_uniform_pointer_type->AsPointer()) {
|
||||
return false;
|
||||
}
|
||||
if (should_be_uniform_pointer_type->AsPointer()->storage_class() !=
|
||||
SpvStorageClassUniform) {
|
||||
return false;
|
||||
}
|
||||
auto should_be_uniform_pointer_instruction =
|
||||
context->get_def_use_mgr()->GetDef(uniform_variable->type_id());
|
||||
auto composite_type =
|
||||
should_be_uniform_pointer_instruction->GetSingleWordInOperand(1);
|
||||
|
||||
auto final_element_type_id = fuzzerutil::WalkCompositeTypeIndices(
|
||||
context, composite_type,
|
||||
fact.uniform_buffer_element_descriptor().index());
|
||||
if (!final_element_type_id) {
|
||||
return false;
|
||||
}
|
||||
auto final_element_type =
|
||||
context->get_type_mgr()->GetType(final_element_type_id);
|
||||
assert(final_element_type &&
|
||||
"There should be a type corresponding to this id.");
|
||||
|
||||
if (!(final_element_type->AsFloat() || final_element_type->AsInteger())) {
|
||||
return false;
|
||||
}
|
||||
auto width = final_element_type->AsFloat()
|
||||
? final_element_type->AsFloat()->width()
|
||||
: final_element_type->AsInteger()->width();
|
||||
|
||||
if (final_element_type->AsFloat() &&
|
||||
!FloatingPointValueIsSuitable(fact, width)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto required_words = (width + 32 - 1) / 32;
|
||||
if (static_cast<uint32_t>(fact.constant_word().size()) != required_words) {
|
||||
return false;
|
||||
}
|
||||
facts_and_type_ids_.emplace_back(
|
||||
std::pair<protobufs::FactConstantUniform, uint32_t>(
|
||||
fact, final_element_type_id));
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>&
|
||||
ConstantUniformFacts::GetConstantUniformFactsAndTypes() const {
|
||||
return facts_and_type_ids_;
|
||||
}
|
||||
|
||||
} // namespace fact_manager
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
90
source/fuzz/fact_manager/constant_uniform_facts.h
Normal file
90
source/fuzz/fact_manager/constant_uniform_facts.h
Normal file
@ -0,0 +1,90 @@
|
||||
// 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.
|
||||
|
||||
#ifndef SOURCE_FUZZ_FACT_MANAGER_CONSTANT_UNIFORM_FACTS_H_
|
||||
#define SOURCE_FUZZ_FACT_MANAGER_CONSTANT_UNIFORM_FACTS_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace fact_manager {
|
||||
|
||||
// The purpose of this class is to group the fields and data used to represent
|
||||
// facts about uniform constants.
|
||||
class ConstantUniformFacts {
|
||||
public:
|
||||
// See method in FactManager which delegates to this method.
|
||||
bool AddFact(const protobufs::FactConstantUniform& fact,
|
||||
opt::IRContext* context);
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
std::vector<uint32_t> GetConstantsAvailableFromUniformsForType(
|
||||
opt::IRContext* ir_context, uint32_t type_id) const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
std::vector<protobufs::UniformBufferElementDescriptor>
|
||||
GetUniformDescriptorsForConstant(opt::IRContext* ir_context,
|
||||
uint32_t constant_id) const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
uint32_t GetConstantFromUniformDescriptor(
|
||||
opt::IRContext* context,
|
||||
const protobufs::UniformBufferElementDescriptor& uniform_descriptor)
|
||||
const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
std::vector<uint32_t> GetTypesForWhichUniformValuesAreKnown() const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
const std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>&
|
||||
GetConstantUniformFactsAndTypes() const;
|
||||
|
||||
private:
|
||||
// Returns true if and only if the words associated with
|
||||
// |constant_instruction| exactly match the words for the constant associated
|
||||
// with |constant_uniform_fact|.
|
||||
static bool DataMatches(
|
||||
const opt::Instruction& constant_instruction,
|
||||
const protobufs::FactConstantUniform& constant_uniform_fact);
|
||||
|
||||
// Yields the constant words associated with |constant_uniform_fact|.
|
||||
static std::vector<uint32_t> GetConstantWords(
|
||||
const protobufs::FactConstantUniform& constant_uniform_fact);
|
||||
|
||||
// Yields the id of a constant of type |type_id| whose data matches the
|
||||
// constant data in |constant_uniform_fact|, or 0 if no such constant is
|
||||
// declared.
|
||||
static uint32_t GetConstantId(
|
||||
opt::IRContext* context,
|
||||
const protobufs::FactConstantUniform& constant_uniform_fact,
|
||||
uint32_t type_id);
|
||||
|
||||
// Checks that the width of a floating-point constant is supported, and that
|
||||
// the constant is finite.
|
||||
static bool FloatingPointValueIsSuitable(
|
||||
const protobufs::FactConstantUniform& fact, uint32_t width);
|
||||
|
||||
std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>
|
||||
facts_and_type_ids_;
|
||||
};
|
||||
|
||||
} // namespace fact_manager
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_FACT_MANAGER_CONSTANT_UNIFORM_FACTS_H_
|
@ -12,529 +12,60 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/fact_manager/data_synonym_and_id_equation_facts.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "source/fuzz/equivalence_relation.h"
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/uniform_buffer_element_descriptor.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace fact_manager {
|
||||
|
||||
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<SpvOp>(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
|
||||
|
||||
//=======================
|
||||
// Constant uniform facts
|
||||
|
||||
// The purpose of this class is to group the fields and data used to represent
|
||||
// facts about uniform constants.
|
||||
class FactManager::ConstantUniformFacts {
|
||||
public:
|
||||
// See method in FactManager which delegates to this method.
|
||||
bool AddFact(const protobufs::FactConstantUniform& fact,
|
||||
opt::IRContext* context);
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
std::vector<uint32_t> GetConstantsAvailableFromUniformsForType(
|
||||
opt::IRContext* ir_context, uint32_t type_id) const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
const std::vector<protobufs::UniformBufferElementDescriptor>
|
||||
GetUniformDescriptorsForConstant(opt::IRContext* ir_context,
|
||||
uint32_t constant_id) const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
uint32_t GetConstantFromUniformDescriptor(
|
||||
opt::IRContext* context,
|
||||
const protobufs::UniformBufferElementDescriptor& uniform_descriptor)
|
||||
const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
std::vector<uint32_t> GetTypesForWhichUniformValuesAreKnown() const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
const std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>&
|
||||
GetConstantUniformFactsAndTypes() const;
|
||||
|
||||
private:
|
||||
// Returns true if and only if the words associated with
|
||||
// |constant_instruction| exactly match the words for the constant associated
|
||||
// with |constant_uniform_fact|.
|
||||
bool DataMatches(
|
||||
const opt::Instruction& constant_instruction,
|
||||
const protobufs::FactConstantUniform& constant_uniform_fact) const;
|
||||
|
||||
// Yields the constant words associated with |constant_uniform_fact|.
|
||||
std::vector<uint32_t> GetConstantWords(
|
||||
const protobufs::FactConstantUniform& constant_uniform_fact) const;
|
||||
|
||||
// Yields the id of a constant of type |type_id| whose data matches the
|
||||
// constant data in |constant_uniform_fact|, or 0 if no such constant is
|
||||
// declared.
|
||||
uint32_t GetConstantId(
|
||||
opt::IRContext* context,
|
||||
const protobufs::FactConstantUniform& constant_uniform_fact,
|
||||
uint32_t type_id) const;
|
||||
|
||||
// Checks that the width of a floating-point constant is supported, and that
|
||||
// the constant is finite.
|
||||
bool FloatingPointValueIsSuitable(const protobufs::FactConstantUniform& fact,
|
||||
uint32_t width) const;
|
||||
|
||||
std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>
|
||||
facts_and_type_ids_;
|
||||
};
|
||||
|
||||
uint32_t FactManager::ConstantUniformFacts::GetConstantId(
|
||||
opt::IRContext* context,
|
||||
const protobufs::FactConstantUniform& constant_uniform_fact,
|
||||
uint32_t type_id) const {
|
||||
auto type = context->get_type_mgr()->GetType(type_id);
|
||||
assert(type != nullptr && "Unknown type id.");
|
||||
const opt::analysis::Constant* known_constant;
|
||||
if (type->AsInteger()) {
|
||||
opt::analysis::IntConstant candidate_constant(
|
||||
type->AsInteger(), GetConstantWords(constant_uniform_fact));
|
||||
known_constant =
|
||||
context->get_constant_mgr()->FindConstant(&candidate_constant);
|
||||
} else {
|
||||
assert(
|
||||
type->AsFloat() &&
|
||||
"Uniform constant facts are only supported for int and float types.");
|
||||
opt::analysis::FloatConstant candidate_constant(
|
||||
type->AsFloat(), GetConstantWords(constant_uniform_fact));
|
||||
known_constant =
|
||||
context->get_constant_mgr()->FindConstant(&candidate_constant);
|
||||
}
|
||||
if (!known_constant) {
|
||||
return 0;
|
||||
}
|
||||
return context->get_constant_mgr()->FindDeclaredConstant(known_constant,
|
||||
type_id);
|
||||
}
|
||||
|
||||
std::vector<uint32_t> FactManager::ConstantUniformFacts::GetConstantWords(
|
||||
const protobufs::FactConstantUniform& constant_uniform_fact) const {
|
||||
std::vector<uint32_t> result;
|
||||
for (auto constant_word : constant_uniform_fact.constant_word()) {
|
||||
result.push_back(constant_word);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FactManager::ConstantUniformFacts::DataMatches(
|
||||
const opt::Instruction& constant_instruction,
|
||||
const protobufs::FactConstantUniform& constant_uniform_fact) const {
|
||||
assert(constant_instruction.opcode() == SpvOpConstant);
|
||||
std::vector<uint32_t> data_in_constant;
|
||||
for (uint32_t i = 0; i < constant_instruction.NumInOperands(); i++) {
|
||||
data_in_constant.push_back(constant_instruction.GetSingleWordInOperand(i));
|
||||
}
|
||||
return data_in_constant == GetConstantWords(constant_uniform_fact);
|
||||
}
|
||||
|
||||
std::vector<uint32_t>
|
||||
FactManager::ConstantUniformFacts::GetConstantsAvailableFromUniformsForType(
|
||||
opt::IRContext* ir_context, uint32_t type_id) const {
|
||||
std::vector<uint32_t> result;
|
||||
std::set<uint32_t> already_seen;
|
||||
for (auto& fact_and_type_id : facts_and_type_ids_) {
|
||||
if (fact_and_type_id.second != type_id) {
|
||||
continue;
|
||||
}
|
||||
if (auto constant_id =
|
||||
GetConstantId(ir_context, fact_and_type_id.first, type_id)) {
|
||||
if (already_seen.find(constant_id) == already_seen.end()) {
|
||||
result.push_back(constant_id);
|
||||
already_seen.insert(constant_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::vector<protobufs::UniformBufferElementDescriptor>
|
||||
FactManager::ConstantUniformFacts::GetUniformDescriptorsForConstant(
|
||||
opt::IRContext* ir_context, uint32_t constant_id) const {
|
||||
std::vector<protobufs::UniformBufferElementDescriptor> result;
|
||||
auto constant_inst = ir_context->get_def_use_mgr()->GetDef(constant_id);
|
||||
assert(constant_inst->opcode() == SpvOpConstant &&
|
||||
"The given id must be that of a constant");
|
||||
auto type_id = constant_inst->type_id();
|
||||
for (auto& fact_and_type_id : facts_and_type_ids_) {
|
||||
if (fact_and_type_id.second != type_id) {
|
||||
continue;
|
||||
}
|
||||
if (DataMatches(*constant_inst, fact_and_type_id.first)) {
|
||||
result.emplace_back(
|
||||
fact_and_type_id.first.uniform_buffer_element_descriptor());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t FactManager::ConstantUniformFacts::GetConstantFromUniformDescriptor(
|
||||
opt::IRContext* context,
|
||||
const protobufs::UniformBufferElementDescriptor& uniform_descriptor) const {
|
||||
// Consider each fact.
|
||||
for (auto& fact_and_type : facts_and_type_ids_) {
|
||||
// Check whether the uniform descriptor associated with the fact matches
|
||||
// |uniform_descriptor|.
|
||||
if (UniformBufferElementDescriptorEquals()(
|
||||
&uniform_descriptor,
|
||||
&fact_and_type.first.uniform_buffer_element_descriptor())) {
|
||||
return GetConstantId(context, fact_and_type.first, fact_and_type.second);
|
||||
}
|
||||
}
|
||||
// No fact associated with the given uniform descriptor was found.
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<uint32_t>
|
||||
FactManager::ConstantUniformFacts::GetTypesForWhichUniformValuesAreKnown()
|
||||
const {
|
||||
std::vector<uint32_t> result;
|
||||
for (auto& fact_and_type : facts_and_type_ids_) {
|
||||
if (std::find(result.begin(), result.end(), fact_and_type.second) ==
|
||||
result.end()) {
|
||||
result.push_back(fact_and_type.second);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FactManager::ConstantUniformFacts::FloatingPointValueIsSuitable(
|
||||
const protobufs::FactConstantUniform& fact, uint32_t width) const {
|
||||
const uint32_t kFloatWidth = 32;
|
||||
const uint32_t kDoubleWidth = 64;
|
||||
if (width != kFloatWidth && width != kDoubleWidth) {
|
||||
// Only 32- and 64-bit floating-point types are handled.
|
||||
return false;
|
||||
}
|
||||
std::vector<uint32_t> words = GetConstantWords(fact);
|
||||
if (width == 32) {
|
||||
float value;
|
||||
memcpy(&value, words.data(), sizeof(float));
|
||||
if (!std::isfinite(value)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
double value;
|
||||
memcpy(&value, words.data(), sizeof(double));
|
||||
if (!std::isfinite(value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FactManager::ConstantUniformFacts::AddFact(
|
||||
const protobufs::FactConstantUniform& fact, opt::IRContext* context) {
|
||||
// Try to find a unique instruction that declares a variable such that the
|
||||
// variable is decorated with the descriptor set and binding associated with
|
||||
// the constant uniform fact.
|
||||
opt::Instruction* uniform_variable = FindUniformVariable(
|
||||
fact.uniform_buffer_element_descriptor(), context, true);
|
||||
|
||||
if (!uniform_variable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(SpvOpVariable == uniform_variable->opcode());
|
||||
assert(SpvStorageClassUniform == uniform_variable->GetSingleWordInOperand(0));
|
||||
|
||||
auto should_be_uniform_pointer_type =
|
||||
context->get_type_mgr()->GetType(uniform_variable->type_id());
|
||||
if (!should_be_uniform_pointer_type->AsPointer()) {
|
||||
return false;
|
||||
}
|
||||
if (should_be_uniform_pointer_type->AsPointer()->storage_class() !=
|
||||
SpvStorageClassUniform) {
|
||||
return false;
|
||||
}
|
||||
auto should_be_uniform_pointer_instruction =
|
||||
context->get_def_use_mgr()->GetDef(uniform_variable->type_id());
|
||||
auto composite_type =
|
||||
should_be_uniform_pointer_instruction->GetSingleWordInOperand(1);
|
||||
|
||||
auto final_element_type_id = fuzzerutil::WalkCompositeTypeIndices(
|
||||
context, composite_type,
|
||||
fact.uniform_buffer_element_descriptor().index());
|
||||
if (!final_element_type_id) {
|
||||
return false;
|
||||
}
|
||||
auto final_element_type =
|
||||
context->get_type_mgr()->GetType(final_element_type_id);
|
||||
assert(final_element_type &&
|
||||
"There should be a type corresponding to this id.");
|
||||
|
||||
if (!(final_element_type->AsFloat() || final_element_type->AsInteger())) {
|
||||
return false;
|
||||
}
|
||||
auto width = final_element_type->AsFloat()
|
||||
? final_element_type->AsFloat()->width()
|
||||
: final_element_type->AsInteger()->width();
|
||||
|
||||
if (final_element_type->AsFloat() &&
|
||||
!FloatingPointValueIsSuitable(fact, width)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto required_words = (width + 32 - 1) / 32;
|
||||
if (static_cast<uint32_t>(fact.constant_word().size()) != required_words) {
|
||||
return false;
|
||||
}
|
||||
facts_and_type_ids_.emplace_back(
|
||||
std::pair<protobufs::FactConstantUniform, uint32_t>(
|
||||
fact, final_element_type_id));
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>&
|
||||
FactManager::ConstantUniformFacts::GetConstantUniformFactsAndTypes() const {
|
||||
return facts_and_type_ids_;
|
||||
}
|
||||
|
||||
// End of uniform constant facts
|
||||
//==============================
|
||||
|
||||
//==============================
|
||||
// Data synonym and id equation facts
|
||||
|
||||
// This helper struct represents the right hand side of an equation as an
|
||||
// operator applied to a number of data descriptor operands.
|
||||
struct Operation {
|
||||
SpvOp opcode;
|
||||
std::vector<const protobufs::DataDescriptor*> operands;
|
||||
};
|
||||
|
||||
// Hashing for operations, to allow deterministic unordered sets.
|
||||
struct OperationHash {
|
||||
size_t operator()(const Operation& operation) const {
|
||||
std::u32string hash;
|
||||
hash.push_back(operation.opcode);
|
||||
for (auto operand : operation.operands) {
|
||||
hash.push_back(static_cast<uint32_t>(DataDescriptorHash()(operand)));
|
||||
}
|
||||
return std::hash<std::u32string>()(hash);
|
||||
}
|
||||
};
|
||||
|
||||
// Equality for operations, to allow deterministic unordered sets.
|
||||
struct OperationEquals {
|
||||
bool operator()(const Operation& first, const Operation& second) const {
|
||||
// Equal operations require...
|
||||
//
|
||||
// Equal opcodes.
|
||||
if (first.opcode != second.opcode) {
|
||||
return false;
|
||||
}
|
||||
// Matching operand counds.
|
||||
if (first.operands.size() != second.operands.size()) {
|
||||
return false;
|
||||
}
|
||||
// Equal operands.
|
||||
for (uint32_t i = 0; i < first.operands.size(); i++) {
|
||||
if (!DataDescriptorEquals()(first.operands[i], second.operands[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// A helper, for debugging, to represent an operation as a string.
|
||||
std::string ToString(const Operation& operation) {
|
||||
std::stringstream stream;
|
||||
stream << operation.opcode;
|
||||
size_t DataSynonymAndIdEquationFacts::OperationHash::operator()(
|
||||
const Operation& operation) const {
|
||||
std::u32string hash;
|
||||
hash.push_back(operation.opcode);
|
||||
for (auto operand : operation.operands) {
|
||||
stream << " " << *operand;
|
||||
hash.push_back(static_cast<uint32_t>(DataDescriptorHash()(operand)));
|
||||
}
|
||||
return stream.str();
|
||||
return std::hash<std::u32string>()(hash);
|
||||
}
|
||||
|
||||
// The purpose of this class is to group the fields and data used to represent
|
||||
// facts about data synonyms and id equations.
|
||||
class FactManager::DataSynonymAndIdEquationFacts {
|
||||
public:
|
||||
// See method in FactManager which delegates to this method.
|
||||
void AddFact(const protobufs::FactDataSynonym& fact, opt::IRContext* context);
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
void AddFact(const protobufs::FactIdEquation& fact, opt::IRContext* context);
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
std::vector<const protobufs::DataDescriptor*> GetSynonymsForDataDescriptor(
|
||||
const protobufs::DataDescriptor& data_descriptor) const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
std::vector<uint32_t> GetIdsForWhichSynonymsAreKnown() const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
bool IsSynonymous(const protobufs::DataDescriptor& data_descriptor1,
|
||||
const protobufs::DataDescriptor& data_descriptor2) const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
void ComputeClosureOfFacts(opt::IRContext* context,
|
||||
uint32_t maximum_equivalence_class_size);
|
||||
|
||||
private:
|
||||
using OperationSet =
|
||||
std::unordered_set<Operation, OperationHash, OperationEquals>;
|
||||
|
||||
// Adds the synonym |dd1| = |dd2| to the set of managed facts, and recurses
|
||||
// into sub-components of the data descriptors, if they are composites, to
|
||||
// record that their components are pairwise-synonymous.
|
||||
void AddDataSynonymFactRecursive(const protobufs::DataDescriptor& dd1,
|
||||
const protobufs::DataDescriptor& dd2,
|
||||
opt::IRContext* context);
|
||||
|
||||
// Computes various corollary facts from the data descriptor |dd| if members
|
||||
// of its equivalence class participate in equation facts with OpConvert*
|
||||
// opcodes. The descriptor should be registered in the equivalence relation.
|
||||
void ComputeConversionDataSynonymFacts(const protobufs::DataDescriptor& dd,
|
||||
opt::IRContext* context);
|
||||
|
||||
// Recurses into sub-components of the data descriptors, if they are
|
||||
// composites, to record that their components are pairwise-synonymous.
|
||||
void ComputeCompositeDataSynonymFacts(const protobufs::DataDescriptor& dd1,
|
||||
const protobufs::DataDescriptor& dd2,
|
||||
opt::IRContext* context);
|
||||
|
||||
// Records the fact that |dd1| and |dd2| are equivalent, and merges the sets
|
||||
// of equations that are known about them.
|
||||
void MakeEquivalent(const protobufs::DataDescriptor& dd1,
|
||||
const protobufs::DataDescriptor& dd2);
|
||||
|
||||
// Registers a data descriptor in the equivalence relation if it hasn't been
|
||||
// registered yet, and returns its representative.
|
||||
const protobufs::DataDescriptor* RegisterDataDescriptor(
|
||||
const protobufs::DataDescriptor& dd);
|
||||
|
||||
// Returns true if and only if |dd1| and |dd2| are valid data descriptors
|
||||
// whose associated data have compatible types. Two types are compatible if:
|
||||
// - they are the same
|
||||
// - they both are numerical or vectors of numerical components with the same
|
||||
// number of components and the same bit count per component
|
||||
static bool DataDescriptorsAreWellFormedAndComparable(
|
||||
opt::IRContext* context, const protobufs::DataDescriptor& dd1,
|
||||
const protobufs::DataDescriptor& dd2);
|
||||
|
||||
OperationSet GetEquations(const protobufs::DataDescriptor* lhs) const;
|
||||
|
||||
// Requires that |lhs_dd| and every element of |rhs_dds| is present in the
|
||||
// |synonymous_| equivalence relation, but is not necessarily its own
|
||||
// representative. Records the fact that the equation
|
||||
// "|lhs_dd| |opcode| |rhs_dds_non_canonical|" holds, and adds any
|
||||
// corollaries, in the form of data synonym or equation facts, that follow
|
||||
// from this and other known facts.
|
||||
void AddEquationFactRecursive(
|
||||
const protobufs::DataDescriptor& lhs_dd, SpvOp opcode,
|
||||
const std::vector<const protobufs::DataDescriptor*>& rhs_dds,
|
||||
opt::IRContext* context);
|
||||
|
||||
// The data descriptors that are known to be synonymous with one another are
|
||||
// captured by this equivalence relation.
|
||||
EquivalenceRelation<protobufs::DataDescriptor, DataDescriptorHash,
|
||||
DataDescriptorEquals>
|
||||
synonymous_;
|
||||
|
||||
// When a new synonym fact is added, it may be possible to deduce further
|
||||
// synonym facts by computing a closure of all known facts. However, this is
|
||||
// an expensive operation, so it should be performed sparingly and only there
|
||||
// is some chance of new facts being deduced. This boolean tracks whether a
|
||||
// closure computation is required - i.e., whether a new fact has been added
|
||||
// since the last time such a computation was performed.
|
||||
bool closure_computation_required_ = false;
|
||||
|
||||
// Represents a set of equations on data descriptors as a map indexed by
|
||||
// left-hand-side, mapping a left-hand-side to a set of operations, each of
|
||||
// which (together with the left-hand-side) defines an equation.
|
||||
bool DataSynonymAndIdEquationFacts::OperationEquals::operator()(
|
||||
const Operation& first, const Operation& second) const {
|
||||
// Equal operations require...
|
||||
//
|
||||
// All data descriptors occurring in equations are required to be present in
|
||||
// the |synonymous_| equivalence relation, and to be their own representatives
|
||||
// in that relation.
|
||||
std::unordered_map<const protobufs::DataDescriptor*, OperationSet>
|
||||
id_equations_;
|
||||
};
|
||||
// Equal opcodes.
|
||||
if (first.opcode != second.opcode) {
|
||||
return false;
|
||||
}
|
||||
// Matching operand counts.
|
||||
if (first.operands.size() != second.operands.size()) {
|
||||
return false;
|
||||
}
|
||||
// Equal operands.
|
||||
for (uint32_t i = 0; i < first.operands.size(); i++) {
|
||||
if (!DataDescriptorEquals()(first.operands[i], second.operands[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void FactManager::DataSynonymAndIdEquationFacts::AddFact(
|
||||
void DataSynonymAndIdEquationFacts::AddFact(
|
||||
const protobufs::FactDataSynonym& fact, opt::IRContext* context) {
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3550)
|
||||
// Assert that ids are not irrelevant.
|
||||
|
||||
// Add the fact, including all facts relating sub-components of the data
|
||||
// descriptors that are involved.
|
||||
AddDataSynonymFactRecursive(fact.data1(), fact.data2(), context);
|
||||
}
|
||||
|
||||
void FactManager::DataSynonymAndIdEquationFacts::AddFact(
|
||||
void DataSynonymAndIdEquationFacts::AddFact(
|
||||
const protobufs::FactIdEquation& fact, opt::IRContext* context) {
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3550)
|
||||
// Assert that ids are not irrelevant.
|
||||
|
||||
protobufs::DataDescriptor lhs_dd = MakeDataDescriptor(fact.lhs_id(), {});
|
||||
|
||||
// Register the LHS in the equivalence relation if needed.
|
||||
@ -542,21 +73,23 @@ void FactManager::DataSynonymAndIdEquationFacts::AddFact(
|
||||
|
||||
// Get equivalence class representatives for all ids used on the RHS of the
|
||||
// equation.
|
||||
std::vector<const protobufs::DataDescriptor*> rhs_dd_ptrs;
|
||||
std::vector<const protobufs::DataDescriptor*> rhs_dds;
|
||||
for (auto rhs_id : fact.rhs_id()) {
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3550)
|
||||
// Assert that ids are not irrelevant.
|
||||
|
||||
// Register a data descriptor based on this id in the equivalence relation
|
||||
// if needed, and then record the equivalence class representative.
|
||||
rhs_dd_ptrs.push_back(
|
||||
RegisterDataDescriptor(MakeDataDescriptor(rhs_id, {})));
|
||||
rhs_dds.push_back(RegisterDataDescriptor(MakeDataDescriptor(rhs_id, {})));
|
||||
}
|
||||
|
||||
// Now add the fact.
|
||||
AddEquationFactRecursive(lhs_dd, static_cast<SpvOp>(fact.opcode()),
|
||||
rhs_dd_ptrs, context);
|
||||
AddEquationFactRecursive(lhs_dd, static_cast<SpvOp>(fact.opcode()), rhs_dds,
|
||||
context);
|
||||
}
|
||||
|
||||
FactManager::DataSynonymAndIdEquationFacts::OperationSet
|
||||
FactManager::DataSynonymAndIdEquationFacts::GetEquations(
|
||||
DataSynonymAndIdEquationFacts::OperationSet
|
||||
DataSynonymAndIdEquationFacts::GetEquations(
|
||||
const protobufs::DataDescriptor* lhs) const {
|
||||
auto existing = id_equations_.find(lhs);
|
||||
if (existing == id_equations_.end()) {
|
||||
@ -565,7 +98,7 @@ FactManager::DataSynonymAndIdEquationFacts::GetEquations(
|
||||
return existing->second;
|
||||
}
|
||||
|
||||
void FactManager::DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
|
||||
void DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
|
||||
const protobufs::DataDescriptor& lhs_dd, SpvOp opcode,
|
||||
const std::vector<const protobufs::DataDescriptor*>& rhs_dds,
|
||||
opt::IRContext* context) {
|
||||
@ -717,7 +250,7 @@ void FactManager::DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
|
||||
}
|
||||
}
|
||||
|
||||
void FactManager::DataSynonymAndIdEquationFacts::AddDataSynonymFactRecursive(
|
||||
void DataSynonymAndIdEquationFacts::AddDataSynonymFactRecursive(
|
||||
const protobufs::DataDescriptor& dd1, const protobufs::DataDescriptor& dd2,
|
||||
opt::IRContext* context) {
|
||||
assert(DataDescriptorsAreWellFormedAndComparable(context, dd1, dd2));
|
||||
@ -736,9 +269,8 @@ void FactManager::DataSynonymAndIdEquationFacts::AddDataSynonymFactRecursive(
|
||||
ComputeCompositeDataSynonymFacts(dd1, dd2, context);
|
||||
}
|
||||
|
||||
void FactManager::DataSynonymAndIdEquationFacts::
|
||||
ComputeConversionDataSynonymFacts(const protobufs::DataDescriptor& dd,
|
||||
opt::IRContext* context) {
|
||||
void DataSynonymAndIdEquationFacts::ComputeConversionDataSynonymFacts(
|
||||
const protobufs::DataDescriptor& dd, opt::IRContext* context) {
|
||||
assert(synonymous_.Exists(dd) &&
|
||||
"|dd| should've been registered in the equivalence relation");
|
||||
|
||||
@ -789,10 +321,9 @@ void FactManager::DataSynonymAndIdEquationFacts::
|
||||
}
|
||||
}
|
||||
|
||||
void FactManager::DataSynonymAndIdEquationFacts::
|
||||
ComputeCompositeDataSynonymFacts(const protobufs::DataDescriptor& dd1,
|
||||
const protobufs::DataDescriptor& dd2,
|
||||
opt::IRContext* context) {
|
||||
void DataSynonymAndIdEquationFacts::ComputeCompositeDataSynonymFacts(
|
||||
const protobufs::DataDescriptor& dd1, const protobufs::DataDescriptor& dd2,
|
||||
opt::IRContext* context) {
|
||||
// Check whether this is a synonym about composite objects. If it is,
|
||||
// we can recursively add synonym facts about their associated sub-components.
|
||||
|
||||
@ -862,7 +393,7 @@ void FactManager::DataSynonymAndIdEquationFacts::
|
||||
}
|
||||
}
|
||||
|
||||
void FactManager::DataSynonymAndIdEquationFacts::ComputeClosureOfFacts(
|
||||
void DataSynonymAndIdEquationFacts::ComputeClosureOfFacts(
|
||||
opt::IRContext* context, uint32_t maximum_equivalence_class_size) {
|
||||
// Suppose that obj_1[a_1, ..., a_m] and obj_2[b_1, ..., b_n] are distinct
|
||||
// data descriptors that describe objects of the same composite type, and that
|
||||
@ -1144,7 +675,7 @@ void FactManager::DataSynonymAndIdEquationFacts::ComputeClosureOfFacts(
|
||||
}
|
||||
}
|
||||
|
||||
void FactManager::DataSynonymAndIdEquationFacts::MakeEquivalent(
|
||||
void DataSynonymAndIdEquationFacts::MakeEquivalent(
|
||||
const protobufs::DataDescriptor& dd1,
|
||||
const protobufs::DataDescriptor& dd2) {
|
||||
// Register the data descriptors if they are not already known to the
|
||||
@ -1218,16 +749,15 @@ void FactManager::DataSynonymAndIdEquationFacts::MakeEquivalent(
|
||||
}
|
||||
|
||||
const protobufs::DataDescriptor*
|
||||
FactManager::DataSynonymAndIdEquationFacts::RegisterDataDescriptor(
|
||||
DataSynonymAndIdEquationFacts::RegisterDataDescriptor(
|
||||
const protobufs::DataDescriptor& dd) {
|
||||
return synonymous_.Exists(dd) ? synonymous_.Find(&dd)
|
||||
: synonymous_.Register(dd);
|
||||
}
|
||||
|
||||
bool FactManager::DataSynonymAndIdEquationFacts::
|
||||
DataDescriptorsAreWellFormedAndComparable(
|
||||
opt::IRContext* context, const protobufs::DataDescriptor& dd1,
|
||||
const protobufs::DataDescriptor& dd2) {
|
||||
bool DataSynonymAndIdEquationFacts::DataDescriptorsAreWellFormedAndComparable(
|
||||
opt::IRContext* context, const protobufs::DataDescriptor& dd1,
|
||||
const protobufs::DataDescriptor& dd2) {
|
||||
auto end_type_id_1 = fuzzerutil::WalkCompositeTypeIndices(
|
||||
context, context->get_def_use_mgr()->GetDef(dd1.object())->type_id(),
|
||||
dd1.index());
|
||||
@ -1292,17 +822,16 @@ bool FactManager::DataSynonymAndIdEquationFacts::
|
||||
}
|
||||
|
||||
std::vector<const protobufs::DataDescriptor*>
|
||||
FactManager::DataSynonymAndIdEquationFacts::GetSynonymsForDataDescriptor(
|
||||
DataSynonymAndIdEquationFacts::GetSynonymsForDataDescriptor(
|
||||
const protobufs::DataDescriptor& data_descriptor) const {
|
||||
if (synonymous_.Exists(data_descriptor)) {
|
||||
return synonymous_.GetEquivalenceClass(data_descriptor);
|
||||
}
|
||||
return std::vector<const protobufs::DataDescriptor*>();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint32_t>
|
||||
FactManager::DataSynonymAndIdEquationFacts::GetIdsForWhichSynonymsAreKnown()
|
||||
const {
|
||||
DataSynonymAndIdEquationFacts::GetIdsForWhichSynonymsAreKnown() const {
|
||||
std::vector<uint32_t> result;
|
||||
for (auto& data_descriptor : synonymous_.GetAllKnownValues()) {
|
||||
if (data_descriptor->index().empty()) {
|
||||
@ -1312,7 +841,7 @@ FactManager::DataSynonymAndIdEquationFacts::GetIdsForWhichSynonymsAreKnown()
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FactManager::DataSynonymAndIdEquationFacts::IsSynonymous(
|
||||
bool DataSynonymAndIdEquationFacts::IsSynonymous(
|
||||
const protobufs::DataDescriptor& data_descriptor1,
|
||||
const protobufs::DataDescriptor& data_descriptor2) const {
|
||||
return synonymous_.Exists(data_descriptor1) &&
|
||||
@ -1320,284 +849,6 @@ bool FactManager::DataSynonymAndIdEquationFacts::IsSynonymous(
|
||||
synonymous_.IsEquivalent(data_descriptor1, data_descriptor2);
|
||||
}
|
||||
|
||||
// End of data synonym facts
|
||||
//==============================
|
||||
|
||||
//==============================
|
||||
// Dead block facts
|
||||
|
||||
// The purpose of this class is to group the fields and data used to represent
|
||||
// facts about data blocks.
|
||||
class FactManager::DeadBlockFacts {
|
||||
public:
|
||||
// See method in FactManager which delegates to this method.
|
||||
void AddFact(const protobufs::FactBlockIsDead& fact);
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
bool BlockIsDead(uint32_t block_id) const;
|
||||
|
||||
private:
|
||||
std::set<uint32_t> dead_block_ids_;
|
||||
};
|
||||
|
||||
void FactManager::DeadBlockFacts::AddFact(
|
||||
const protobufs::FactBlockIsDead& fact) {
|
||||
dead_block_ids_.insert(fact.block_id());
|
||||
}
|
||||
|
||||
bool FactManager::DeadBlockFacts::BlockIsDead(uint32_t block_id) const {
|
||||
return dead_block_ids_.count(block_id) != 0;
|
||||
}
|
||||
|
||||
// End of dead block facts
|
||||
//==============================
|
||||
|
||||
//==============================
|
||||
// Livesafe function facts
|
||||
|
||||
// The purpose of this class is to group the fields and data used to represent
|
||||
// facts about livesafe functions.
|
||||
class FactManager::LivesafeFunctionFacts {
|
||||
public:
|
||||
// See method in FactManager which delegates to this method.
|
||||
void AddFact(const protobufs::FactFunctionIsLivesafe& fact);
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
bool FunctionIsLivesafe(uint32_t function_id) const;
|
||||
|
||||
private:
|
||||
std::set<uint32_t> livesafe_function_ids_;
|
||||
};
|
||||
|
||||
void FactManager::LivesafeFunctionFacts::AddFact(
|
||||
const protobufs::FactFunctionIsLivesafe& fact) {
|
||||
livesafe_function_ids_.insert(fact.function_id());
|
||||
}
|
||||
|
||||
bool FactManager::LivesafeFunctionFacts::FunctionIsLivesafe(
|
||||
uint32_t function_id) const {
|
||||
return livesafe_function_ids_.count(function_id) != 0;
|
||||
}
|
||||
|
||||
// End of livesafe function facts
|
||||
//==============================
|
||||
|
||||
//==============================
|
||||
// Irrelevant value facts
|
||||
|
||||
// The purpose of this class is to group the fields and data used to represent
|
||||
// facts about various irrelevant values in the module.
|
||||
class FactManager::IrrelevantValueFacts {
|
||||
public:
|
||||
// See method in FactManager which delegates to this method.
|
||||
void AddFact(const protobufs::FactPointeeValueIsIrrelevant& fact);
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
void AddFact(const protobufs::FactIdIsIrrelevant& fact);
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
bool PointeeValueIsIrrelevant(uint32_t pointer_id) const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
bool IdIsIrrelevant(uint32_t pointer_id) const;
|
||||
|
||||
private:
|
||||
std::unordered_set<uint32_t> pointers_to_irrelevant_pointees_ids_;
|
||||
std::unordered_set<uint32_t> irrelevant_ids_;
|
||||
};
|
||||
|
||||
void FactManager::IrrelevantValueFacts::AddFact(
|
||||
const protobufs::FactPointeeValueIsIrrelevant& fact) {
|
||||
pointers_to_irrelevant_pointees_ids_.insert(fact.pointer_id());
|
||||
}
|
||||
|
||||
void FactManager::IrrelevantValueFacts::AddFact(
|
||||
const protobufs::FactIdIsIrrelevant& fact) {
|
||||
irrelevant_ids_.insert(fact.result_id());
|
||||
}
|
||||
|
||||
bool FactManager::IrrelevantValueFacts::PointeeValueIsIrrelevant(
|
||||
uint32_t pointer_id) const {
|
||||
return pointers_to_irrelevant_pointees_ids_.count(pointer_id) != 0;
|
||||
}
|
||||
|
||||
bool FactManager::IrrelevantValueFacts::IdIsIrrelevant(
|
||||
uint32_t pointer_id) const {
|
||||
return irrelevant_ids_.count(pointer_id) != 0;
|
||||
}
|
||||
|
||||
// End of arbitrarily-valued variable facts
|
||||
//==============================
|
||||
|
||||
FactManager::FactManager()
|
||||
: uniform_constant_facts_(MakeUnique<ConstantUniformFacts>()),
|
||||
data_synonym_and_id_equation_facts_(
|
||||
MakeUnique<DataSynonymAndIdEquationFacts>()),
|
||||
dead_block_facts_(MakeUnique<DeadBlockFacts>()),
|
||||
livesafe_function_facts_(MakeUnique<LivesafeFunctionFacts>()),
|
||||
irrelevant_value_facts_(MakeUnique<IrrelevantValueFacts>()) {}
|
||||
|
||||
FactManager::~FactManager() = default;
|
||||
|
||||
void FactManager::AddFacts(const MessageConsumer& message_consumer,
|
||||
const protobufs::FactSequence& initial_facts,
|
||||
opt::IRContext* context) {
|
||||
for (auto& fact : initial_facts.fact()) {
|
||||
if (!AddFact(fact, context)) {
|
||||
message_consumer(
|
||||
SPV_MSG_WARNING, nullptr, {},
|
||||
("Invalid fact " + ToString(fact) + " ignored.").c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FactManager::AddFact(const fuzz::protobufs::Fact& fact,
|
||||
opt::IRContext* context) {
|
||||
switch (fact.fact_case()) {
|
||||
case protobufs::Fact::kConstantUniformFact:
|
||||
return uniform_constant_facts_->AddFact(fact.constant_uniform_fact(),
|
||||
context);
|
||||
case protobufs::Fact::kDataSynonymFact:
|
||||
data_synonym_and_id_equation_facts_->AddFact(fact.data_synonym_fact(),
|
||||
context);
|
||||
return true;
|
||||
case protobufs::Fact::kBlockIsDeadFact:
|
||||
dead_block_facts_->AddFact(fact.block_is_dead_fact());
|
||||
return true;
|
||||
case protobufs::Fact::kFunctionIsLivesafeFact:
|
||||
livesafe_function_facts_->AddFact(fact.function_is_livesafe_fact());
|
||||
return true;
|
||||
default:
|
||||
assert(false && "Unknown fact type.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void FactManager::AddFactDataSynonym(const protobufs::DataDescriptor& data1,
|
||||
const protobufs::DataDescriptor& data2,
|
||||
opt::IRContext* context) {
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3550):
|
||||
// assert that neither |data1| nor |data2| are irrelevant.
|
||||
protobufs::FactDataSynonym fact;
|
||||
*fact.mutable_data1() = data1;
|
||||
*fact.mutable_data2() = data2;
|
||||
data_synonym_and_id_equation_facts_->AddFact(fact, context);
|
||||
}
|
||||
|
||||
std::vector<uint32_t> FactManager::GetConstantsAvailableFromUniformsForType(
|
||||
opt::IRContext* ir_context, uint32_t type_id) const {
|
||||
return uniform_constant_facts_->GetConstantsAvailableFromUniformsForType(
|
||||
ir_context, type_id);
|
||||
}
|
||||
|
||||
const std::vector<protobufs::UniformBufferElementDescriptor>
|
||||
FactManager::GetUniformDescriptorsForConstant(opt::IRContext* ir_context,
|
||||
uint32_t constant_id) const {
|
||||
return uniform_constant_facts_->GetUniformDescriptorsForConstant(ir_context,
|
||||
constant_id);
|
||||
}
|
||||
|
||||
uint32_t FactManager::GetConstantFromUniformDescriptor(
|
||||
opt::IRContext* context,
|
||||
const protobufs::UniformBufferElementDescriptor& uniform_descriptor) const {
|
||||
return uniform_constant_facts_->GetConstantFromUniformDescriptor(
|
||||
context, uniform_descriptor);
|
||||
}
|
||||
|
||||
std::vector<uint32_t> FactManager::GetTypesForWhichUniformValuesAreKnown()
|
||||
const {
|
||||
return uniform_constant_facts_->GetTypesForWhichUniformValuesAreKnown();
|
||||
}
|
||||
|
||||
const std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>&
|
||||
FactManager::GetConstantUniformFactsAndTypes() const {
|
||||
return uniform_constant_facts_->GetConstantUniformFactsAndTypes();
|
||||
}
|
||||
|
||||
std::vector<uint32_t> FactManager::GetIdsForWhichSynonymsAreKnown() const {
|
||||
return data_synonym_and_id_equation_facts_->GetIdsForWhichSynonymsAreKnown();
|
||||
}
|
||||
|
||||
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 GetSynonymsForDataDescriptor(MakeDataDescriptor(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);
|
||||
dead_block_facts_->AddFact(fact);
|
||||
}
|
||||
|
||||
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);
|
||||
livesafe_function_facts_->AddFact(fact);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void FactManager::AddFactValueOfPointeeIsIrrelevant(uint32_t pointer_id) {
|
||||
protobufs::FactPointeeValueIsIrrelevant fact;
|
||||
fact.set_pointer_id(pointer_id);
|
||||
irrelevant_value_facts_->AddFact(fact);
|
||||
}
|
||||
|
||||
void FactManager::AddFactIdIsIrrelevant(uint32_t result_id) {
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3550):
|
||||
// assert that |result_id| is not a part of any DataSynonym fact.
|
||||
protobufs::FactIdIsIrrelevant fact;
|
||||
fact.set_result_id(result_id);
|
||||
irrelevant_value_facts_->AddFact(fact);
|
||||
}
|
||||
|
||||
void FactManager::AddFactIdEquation(uint32_t lhs_id, SpvOp opcode,
|
||||
const std::vector<uint32_t>& rhs_id,
|
||||
opt::IRContext* context) {
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3550):
|
||||
// assert that elements of |rhs_id| and |lhs_id| are not irrelevant.
|
||||
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);
|
||||
}
|
||||
data_synonym_and_id_equation_facts_->AddFact(fact, context);
|
||||
}
|
||||
|
||||
void FactManager::ComputeClosureOfFacts(
|
||||
opt::IRContext* ir_context, uint32_t maximum_equivalence_class_size) {
|
||||
data_synonym_and_id_equation_facts_->ComputeClosureOfFacts(
|
||||
ir_context, maximum_equivalence_class_size);
|
||||
}
|
||||
|
||||
} // namespace fact_manager
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
156
source/fuzz/fact_manager/data_synonym_and_id_equation_facts.h
Normal file
156
source/fuzz/fact_manager/data_synonym_and_id_equation_facts.h
Normal file
@ -0,0 +1,156 @@
|
||||
// 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.
|
||||
|
||||
#ifndef SOURCE_FUZZ_FACT_MANAGER_DATA_SYNONYM_AND_ID_EQUATION_FACTS_H_
|
||||
#define SOURCE_FUZZ_FACT_MANAGER_DATA_SYNONYM_AND_ID_EQUATION_FACTS_H_
|
||||
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "source/fuzz/data_descriptor.h"
|
||||
#include "source/fuzz/equivalence_relation.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace fact_manager {
|
||||
|
||||
// The purpose of this class is to group the fields and data used to represent
|
||||
// facts about data synonyms and id equations.
|
||||
class DataSynonymAndIdEquationFacts {
|
||||
public:
|
||||
// See method in FactManager which delegates to this method.
|
||||
void AddFact(const protobufs::FactDataSynonym& fact, opt::IRContext* context);
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
void AddFact(const protobufs::FactIdEquation& fact, opt::IRContext* context);
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
std::vector<const protobufs::DataDescriptor*> GetSynonymsForDataDescriptor(
|
||||
const protobufs::DataDescriptor& data_descriptor) const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
std::vector<uint32_t> GetIdsForWhichSynonymsAreKnown() const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
bool IsSynonymous(const protobufs::DataDescriptor& data_descriptor1,
|
||||
const protobufs::DataDescriptor& data_descriptor2) const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
void ComputeClosureOfFacts(opt::IRContext* context,
|
||||
uint32_t maximum_equivalence_class_size);
|
||||
|
||||
private:
|
||||
// This helper struct represents the right hand side of an equation as an
|
||||
// operator applied to a number of data descriptor operands.
|
||||
struct Operation {
|
||||
SpvOp opcode;
|
||||
std::vector<const protobufs::DataDescriptor*> operands;
|
||||
};
|
||||
|
||||
// Hashing for operations, to allow deterministic unordered sets.
|
||||
struct OperationHash {
|
||||
size_t operator()(const Operation& operation) const;
|
||||
};
|
||||
|
||||
// Equality for operations, to allow deterministic unordered sets.
|
||||
struct OperationEquals {
|
||||
bool operator()(const Operation& first, const Operation& second) const;
|
||||
};
|
||||
|
||||
using OperationSet =
|
||||
std::unordered_set<Operation, OperationHash, OperationEquals>;
|
||||
|
||||
// Adds the synonym |dd1| = |dd2| to the set of managed facts, and recurses
|
||||
// into sub-components of the data descriptors, if they are composites, to
|
||||
// record that their components are pairwise-synonymous.
|
||||
void AddDataSynonymFactRecursive(const protobufs::DataDescriptor& dd1,
|
||||
const protobufs::DataDescriptor& dd2,
|
||||
opt::IRContext* context);
|
||||
|
||||
// Computes various corollary facts from the data descriptor |dd| if members
|
||||
// of its equivalence class participate in equation facts with OpConvert*
|
||||
// opcodes. The descriptor should be registered in the equivalence relation.
|
||||
void ComputeConversionDataSynonymFacts(const protobufs::DataDescriptor& dd,
|
||||
opt::IRContext* context);
|
||||
|
||||
// Recurses into sub-components of the data descriptors, if they are
|
||||
// composites, to record that their components are pairwise-synonymous.
|
||||
void ComputeCompositeDataSynonymFacts(const protobufs::DataDescriptor& dd1,
|
||||
const protobufs::DataDescriptor& dd2,
|
||||
opt::IRContext* context);
|
||||
|
||||
// Records the fact that |dd1| and |dd2| are equivalent, and merges the sets
|
||||
// of equations that are known about them.
|
||||
void MakeEquivalent(const protobufs::DataDescriptor& dd1,
|
||||
const protobufs::DataDescriptor& dd2);
|
||||
|
||||
// Registers a data descriptor in the equivalence relation if it hasn't been
|
||||
// registered yet, and returns its representative.
|
||||
const protobufs::DataDescriptor* RegisterDataDescriptor(
|
||||
const protobufs::DataDescriptor& dd);
|
||||
|
||||
// Returns true if and only if |dd1| and |dd2| are valid data descriptors
|
||||
// whose associated data have compatible types. Two types are compatible if:
|
||||
// - they are the same
|
||||
// - they both are numerical or vectors of numerical components with the same
|
||||
// number of components and the same bit count per component
|
||||
static bool DataDescriptorsAreWellFormedAndComparable(
|
||||
opt::IRContext* context, const protobufs::DataDescriptor& dd1,
|
||||
const protobufs::DataDescriptor& dd2);
|
||||
|
||||
OperationSet GetEquations(const protobufs::DataDescriptor* lhs) const;
|
||||
|
||||
// Requires that |lhs_dd| and every element of |rhs_dds| is present in the
|
||||
// |synonymous_| equivalence relation, but is not necessarily its own
|
||||
// representative. Records the fact that the equation
|
||||
// "|lhs_dd| |opcode| |rhs_dds_non_canonical|" holds, and adds any
|
||||
// corollaries, in the form of data synonym or equation facts, that follow
|
||||
// from this and other known facts.
|
||||
void AddEquationFactRecursive(
|
||||
const protobufs::DataDescriptor& lhs_dd, SpvOp opcode,
|
||||
const std::vector<const protobufs::DataDescriptor*>& rhs_dds,
|
||||
opt::IRContext* context);
|
||||
|
||||
// The data descriptors that are known to be synonymous with one another are
|
||||
// captured by this equivalence relation.
|
||||
EquivalenceRelation<protobufs::DataDescriptor, DataDescriptorHash,
|
||||
DataDescriptorEquals>
|
||||
synonymous_;
|
||||
|
||||
// When a new synonym fact is added, it may be possible to deduce further
|
||||
// synonym facts by computing a closure of all known facts. However, this is
|
||||
// an expensive operation, so it should be performed sparingly and only there
|
||||
// is some chance of new facts being deduced. This boolean tracks whether a
|
||||
// closure computation is required - i.e., whether a new fact has been added
|
||||
// since the last time such a computation was performed.
|
||||
bool closure_computation_required_ = false;
|
||||
|
||||
// Represents a set of equations on data descriptors as a map indexed by
|
||||
// left-hand-side, mapping a left-hand-side to a set of operations, each of
|
||||
// which (together with the left-hand-side) defines an equation.
|
||||
//
|
||||
// All data descriptors occurring in equations are required to be present in
|
||||
// the |synonymous_| equivalence relation, and to be their own representatives
|
||||
// in that relation.
|
||||
std::unordered_map<const protobufs::DataDescriptor*, OperationSet>
|
||||
id_equations_;
|
||||
};
|
||||
|
||||
} // namespace fact_manager
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_FACT_MANAGER_DATA_SYNONYM_AND_ID_EQUATION_FACTS_H_
|
31
source/fuzz/fact_manager/dead_block_facts.cpp
Normal file
31
source/fuzz/fact_manager/dead_block_facts.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
// 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 "source/fuzz/fact_manager/dead_block_facts.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace fact_manager {
|
||||
|
||||
void DeadBlockFacts::AddFact(const protobufs::FactBlockIsDead& fact) {
|
||||
dead_block_ids_.insert(fact.block_id());
|
||||
}
|
||||
|
||||
bool DeadBlockFacts::BlockIsDead(uint32_t block_id) const {
|
||||
return dead_block_ids_.count(block_id) != 0;
|
||||
}
|
||||
|
||||
} // namespace fact_manager
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
44
source/fuzz/fact_manager/dead_block_facts.h
Normal file
44
source/fuzz/fact_manager/dead_block_facts.h
Normal file
@ -0,0 +1,44 @@
|
||||
// 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.
|
||||
|
||||
#ifndef SOURCE_FUZZ_FACT_MANAGER_DEAD_BLOCK_FACTS_H_
|
||||
#define SOURCE_FUZZ_FACT_MANAGER_DEAD_BLOCK_FACTS_H_
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace fact_manager {
|
||||
|
||||
// The purpose of this class is to group the fields and data used to represent
|
||||
// facts about data blocks.
|
||||
class DeadBlockFacts {
|
||||
public:
|
||||
// See method in FactManager which delegates to this method.
|
||||
void AddFact(const protobufs::FactBlockIsDead& fact);
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
bool BlockIsDead(uint32_t block_id) const;
|
||||
|
||||
private:
|
||||
std::unordered_set<uint32_t> dead_block_ids_;
|
||||
};
|
||||
|
||||
} // namespace fact_manager
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_FACT_MANAGER_DEAD_BLOCK_FACTS_H_
|
244
source/fuzz/fact_manager/fact_manager.cpp
Normal file
244
source/fuzz/fact_manager/fact_manager.cpp
Normal file
@ -0,0 +1,244 @@
|
||||
// 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 << " " << static_cast<SpvOp>(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
|
||||
|
||||
void FactManager::AddFacts(const MessageConsumer& message_consumer,
|
||||
const protobufs::FactSequence& initial_facts,
|
||||
opt::IRContext* context) {
|
||||
for (auto& fact : initial_facts.fact()) {
|
||||
if (!AddFact(fact, context)) {
|
||||
auto message = "Invalid fact " + ToString(fact) + " ignored.";
|
||||
message_consumer(SPV_MSG_WARNING, nullptr, {}, message.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FactManager::AddFact(const fuzz::protobufs::Fact& fact,
|
||||
opt::IRContext* context) {
|
||||
switch (fact.fact_case()) {
|
||||
case protobufs::Fact::kConstantUniformFact:
|
||||
return constant_uniform_facts_.AddFact(fact.constant_uniform_fact(),
|
||||
context);
|
||||
case protobufs::Fact::kDataSynonymFact:
|
||||
data_synonym_and_id_equation_facts_.AddFact(fact.data_synonym_fact(),
|
||||
context);
|
||||
return true;
|
||||
case protobufs::Fact::kBlockIsDeadFact:
|
||||
dead_block_facts_.AddFact(fact.block_is_dead_fact());
|
||||
return true;
|
||||
case protobufs::Fact::kFunctionIsLivesafeFact:
|
||||
livesafe_function_facts_.AddFact(fact.function_is_livesafe_fact());
|
||||
return true;
|
||||
default:
|
||||
assert(false && "Unknown fact type.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void FactManager::AddFactDataSynonym(const protobufs::DataDescriptor& data1,
|
||||
const protobufs::DataDescriptor& data2,
|
||||
opt::IRContext* context) {
|
||||
protobufs::FactDataSynonym fact;
|
||||
*fact.mutable_data1() = data1;
|
||||
*fact.mutable_data2() = data2;
|
||||
data_synonym_and_id_equation_facts_.AddFact(fact, context);
|
||||
}
|
||||
|
||||
std::vector<uint32_t> FactManager::GetConstantsAvailableFromUniformsForType(
|
||||
opt::IRContext* ir_context, uint32_t type_id) const {
|
||||
return constant_uniform_facts_.GetConstantsAvailableFromUniformsForType(
|
||||
ir_context, type_id);
|
||||
}
|
||||
|
||||
std::vector<protobufs::UniformBufferElementDescriptor>
|
||||
FactManager::GetUniformDescriptorsForConstant(opt::IRContext* ir_context,
|
||||
uint32_t constant_id) const {
|
||||
return constant_uniform_facts_.GetUniformDescriptorsForConstant(ir_context,
|
||||
constant_id);
|
||||
}
|
||||
|
||||
uint32_t FactManager::GetConstantFromUniformDescriptor(
|
||||
opt::IRContext* context,
|
||||
const protobufs::UniformBufferElementDescriptor& uniform_descriptor) const {
|
||||
return constant_uniform_facts_.GetConstantFromUniformDescriptor(
|
||||
context, 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::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 GetSynonymsForDataDescriptor(MakeDataDescriptor(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);
|
||||
dead_block_facts_.AddFact(fact);
|
||||
}
|
||||
|
||||
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);
|
||||
livesafe_function_facts_.AddFact(fact);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void FactManager::AddFactValueOfPointeeIsIrrelevant(uint32_t pointer_id) {
|
||||
protobufs::FactPointeeValueIsIrrelevant fact;
|
||||
fact.set_pointer_id(pointer_id);
|
||||
irrelevant_value_facts_.AddFact(fact);
|
||||
}
|
||||
|
||||
void FactManager::AddFactIdIsIrrelevant(uint32_t result_id) {
|
||||
protobufs::FactIdIsIrrelevant fact;
|
||||
fact.set_result_id(result_id);
|
||||
irrelevant_value_facts_.AddFact(fact);
|
||||
}
|
||||
|
||||
void FactManager::AddFactIdEquation(uint32_t lhs_id, SpvOp opcode,
|
||||
const std::vector<uint32_t>& rhs_id,
|
||||
opt::IRContext* context) {
|
||||
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);
|
||||
}
|
||||
data_synonym_and_id_equation_facts_.AddFact(fact, context);
|
||||
}
|
||||
|
||||
void FactManager::ComputeClosureOfFacts(
|
||||
opt::IRContext* ir_context, uint32_t maximum_equivalence_class_size) {
|
||||
data_synonym_and_id_equation_facts_.ComputeClosureOfFacts(
|
||||
ir_context, maximum_equivalence_class_size);
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
@ -12,15 +12,19 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_FUZZ_FACT_MANAGER_H_
|
||||
#define SOURCE_FUZZ_FACT_MANAGER_H_
|
||||
#ifndef SOURCE_FUZZ_FACT_MANAGER_FACT_MANAGER_H_
|
||||
#define SOURCE_FUZZ_FACT_MANAGER_FACT_MANAGER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "source/fuzz/data_descriptor.h"
|
||||
#include "source/fuzz/fact_manager/constant_uniform_facts.h"
|
||||
#include "source/fuzz/fact_manager/data_synonym_and_id_equation_facts.h"
|
||||
#include "source/fuzz/fact_manager/dead_block_facts.h"
|
||||
#include "source/fuzz/fact_manager/irrelevant_value_facts.h"
|
||||
#include "source/fuzz/fact_manager/livesafe_function_facts.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/opt/constants.h"
|
||||
|
||||
@ -38,10 +42,6 @@ namespace fuzz {
|
||||
// the module.
|
||||
class FactManager {
|
||||
public:
|
||||
FactManager();
|
||||
|
||||
~FactManager();
|
||||
|
||||
// Adds all the facts from |facts|, checking them for validity with respect to
|
||||
// |context|. Warnings about invalid facts are communicated via
|
||||
// |message_consumer|; such facts are otherwise ignored.
|
||||
@ -117,7 +117,7 @@ class FactManager {
|
||||
|
||||
// Provides details of all uniform elements that are known to be equal to the
|
||||
// constant associated with |constant_id| in |ir_context|.
|
||||
const std::vector<protobufs::UniformBufferElementDescriptor>
|
||||
std::vector<protobufs::UniformBufferElementDescriptor>
|
||||
GetUniformDescriptorsForConstant(opt::IRContext* ir_context,
|
||||
uint32_t constant_id) const;
|
||||
|
||||
@ -198,35 +198,16 @@ class FactManager {
|
||||
//==============================
|
||||
|
||||
private:
|
||||
// For each distinct kind of fact to be managed, we use a separate opaque
|
||||
// class type.
|
||||
|
||||
class ConstantUniformFacts; // Opaque class for management of
|
||||
// constant uniform facts.
|
||||
std::unique_ptr<ConstantUniformFacts>
|
||||
uniform_constant_facts_; // Unique pointer to internal data.
|
||||
|
||||
class DataSynonymAndIdEquationFacts; // Opaque class for management of data
|
||||
// synonym and id equation facts.
|
||||
std::unique_ptr<DataSynonymAndIdEquationFacts>
|
||||
data_synonym_and_id_equation_facts_; // Unique pointer to internal data.
|
||||
|
||||
class DeadBlockFacts; // Opaque class for management of dead block facts.
|
||||
std::unique_ptr<DeadBlockFacts>
|
||||
dead_block_facts_; // Unique pointer to internal data.
|
||||
|
||||
class LivesafeFunctionFacts; // Opaque class for management of livesafe
|
||||
// function facts.
|
||||
std::unique_ptr<LivesafeFunctionFacts>
|
||||
livesafe_function_facts_; // Unique pointer to internal data.
|
||||
|
||||
class IrrelevantValueFacts; // Opaque class for management of
|
||||
// facts about various irrelevant values in the module.
|
||||
std::unique_ptr<IrrelevantValueFacts>
|
||||
irrelevant_value_facts_; // Unique pointer to internal data.
|
||||
// Keep these in alphabetical order.
|
||||
fact_manager::ConstantUniformFacts constant_uniform_facts_;
|
||||
fact_manager::DataSynonymAndIdEquationFacts
|
||||
data_synonym_and_id_equation_facts_;
|
||||
fact_manager::DeadBlockFacts dead_block_facts_;
|
||||
fact_manager::LivesafeFunctionFacts livesafe_function_facts_;
|
||||
fact_manager::IrrelevantValueFacts irrelevant_value_facts_;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_FACT_MANAGER_H_
|
||||
#endif // SOURCE_FUZZ_FACT_MANAGER_FACT_MANAGER_H_
|
51
source/fuzz/fact_manager/irrelevant_value_facts.cpp
Normal file
51
source/fuzz/fact_manager/irrelevant_value_facts.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
// 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 "source/fuzz/fact_manager/irrelevant_value_facts.h"
|
||||
|
||||
#include "source/fuzz/data_descriptor.h"
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace fact_manager {
|
||||
|
||||
void IrrelevantValueFacts::AddFact(
|
||||
const protobufs::FactPointeeValueIsIrrelevant& fact) {
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3550)
|
||||
// Assert that the id does not participate in DataSynonym facts and is a
|
||||
// pointer.
|
||||
|
||||
pointers_to_irrelevant_pointees_ids_.insert(fact.pointer_id());
|
||||
}
|
||||
|
||||
void IrrelevantValueFacts::AddFact(const protobufs::FactIdIsIrrelevant& fact) {
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3550)
|
||||
// Assert that the id does not participate in DataSynonym facts and is not a
|
||||
// pointer.
|
||||
|
||||
irrelevant_ids_.insert(fact.result_id());
|
||||
}
|
||||
|
||||
bool IrrelevantValueFacts::PointeeValueIsIrrelevant(uint32_t pointer_id) const {
|
||||
return pointers_to_irrelevant_pointees_ids_.count(pointer_id) != 0;
|
||||
}
|
||||
|
||||
bool IrrelevantValueFacts::IdIsIrrelevant(uint32_t pointer_id) const {
|
||||
return irrelevant_ids_.count(pointer_id) != 0;
|
||||
}
|
||||
|
||||
} // namespace fact_manager
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
52
source/fuzz/fact_manager/irrelevant_value_facts.h
Normal file
52
source/fuzz/fact_manager/irrelevant_value_facts.h
Normal file
@ -0,0 +1,52 @@
|
||||
// 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.
|
||||
|
||||
#ifndef SOURCE_FUZZ_FACT_MANAGER_IRRELEVANT_VALUE_FACTS_H_
|
||||
#define SOURCE_FUZZ_FACT_MANAGER_IRRELEVANT_VALUE_FACTS_H_
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace fact_manager {
|
||||
|
||||
// The purpose of this class is to group the fields and data used to represent
|
||||
// facts about various irrelevant values in the module.
|
||||
class IrrelevantValueFacts {
|
||||
public:
|
||||
// See method in FactManager which delegates to this method.
|
||||
void AddFact(const protobufs::FactPointeeValueIsIrrelevant& fact);
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
void AddFact(const protobufs::FactIdIsIrrelevant& fact);
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
bool PointeeValueIsIrrelevant(uint32_t pointer_id) const;
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
bool IdIsIrrelevant(uint32_t pointer_id) const;
|
||||
|
||||
private:
|
||||
std::unordered_set<uint32_t> pointers_to_irrelevant_pointees_ids_;
|
||||
std::unordered_set<uint32_t> irrelevant_ids_;
|
||||
};
|
||||
|
||||
} // namespace fact_manager
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_FACT_MANAGER_IRRELEVANT_VALUE_FACTS_H_
|
32
source/fuzz/fact_manager/livesafe_function_facts.cpp
Normal file
32
source/fuzz/fact_manager/livesafe_function_facts.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
// 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 "source/fuzz/fact_manager/livesafe_function_facts.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace fact_manager {
|
||||
|
||||
void LivesafeFunctionFacts::AddFact(
|
||||
const protobufs::FactFunctionIsLivesafe& fact) {
|
||||
livesafe_function_ids_.insert(fact.function_id());
|
||||
}
|
||||
|
||||
bool LivesafeFunctionFacts::FunctionIsLivesafe(uint32_t function_id) const {
|
||||
return livesafe_function_ids_.count(function_id) != 0;
|
||||
}
|
||||
|
||||
} // namespace fact_manager
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
44
source/fuzz/fact_manager/livesafe_function_facts.h
Normal file
44
source/fuzz/fact_manager/livesafe_function_facts.h
Normal file
@ -0,0 +1,44 @@
|
||||
// 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.
|
||||
|
||||
#ifndef SOURCE_FUZZ_FACT_MANAGER_LIVESAFE_FUNCTION_FACTS_H_
|
||||
#define SOURCE_FUZZ_FACT_MANAGER_LIVESAFE_FUNCTION_FACTS_H_
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace fact_manager {
|
||||
|
||||
// The purpose of this class is to group the fields and data used to represent
|
||||
// facts about livesafe functions.
|
||||
class LivesafeFunctionFacts {
|
||||
public:
|
||||
// See method in FactManager which delegates to this method.
|
||||
void AddFact(const protobufs::FactFunctionIsLivesafe& fact);
|
||||
|
||||
// See method in FactManager which delegates to this method.
|
||||
bool FunctionIsLivesafe(uint32_t function_id) const;
|
||||
|
||||
private:
|
||||
std::unordered_set<uint32_t> livesafe_function_ids_;
|
||||
};
|
||||
|
||||
} // namespace fact_manager
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_FACT_MANAGER_LIVESAFE_FUNCTION_FACTS_H_
|
@ -14,7 +14,7 @@
|
||||
|
||||
#include "source/fuzz/force_render_red.h"
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/fact_manager/fact_manager.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation_context.h"
|
||||
@ -26,9 +26,6 @@
|
||||
#include "source/util/make_unique.h"
|
||||
#include "tools/util/cli_consumer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/fact_manager/fact_manager.h"
|
||||
#include "source/fuzz/fuzzer_context.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_access_chains.h"
|
||||
#include "source/fuzz/fuzzer_pass_add_composite_inserts.h"
|
||||
|
@ -16,21 +16,10 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/fact_manager/fact_manager.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/fuzz/transformation_add_constant_boolean.h"
|
||||
#include "source/fuzz/transformation_add_constant_scalar.h"
|
||||
#include "source/fuzz/transformation_add_dead_break.h"
|
||||
#include "source/fuzz/transformation_add_type_boolean.h"
|
||||
#include "source/fuzz/transformation_add_type_float.h"
|
||||
#include "source/fuzz/transformation_add_type_int.h"
|
||||
#include "source/fuzz/transformation_add_type_pointer.h"
|
||||
#include "source/fuzz/transformation_context.h"
|
||||
#include "source/fuzz/transformation_move_block_down.h"
|
||||
#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
|
||||
#include "source/fuzz/transformation_replace_constant_with_uniform.h"
|
||||
#include "source/fuzz/transformation_split_block.h"
|
||||
#include "source/opt/build_module.h"
|
||||
#include "source/util/make_unique.h"
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
#ifndef SOURCE_FUZZ_TRANSFORMATION_CONTEXT_H_
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_CONTEXT_H_
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/fact_manager/fact_manager.h"
|
||||
#include "spirv-tools/libspirv.hpp"
|
||||
|
||||
namespace spvtools {
|
||||
|
@ -17,7 +17,6 @@
|
||||
#ifndef SOURCE_FUZZ_TRANSFORMATION_REPLACE_CONSTANT_WITH_UNIFORM_H_
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_REPLACE_CONSTANT_WITH_UNIFORM_H_
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/id_use_descriptor.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
|
@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/fact_manager/fact_manager.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user