spirv-fuzz: Refactor conditions in the fact manager (#3867)

Refactors conditions and names of some methods in the fact manager. Part of #3698.
This commit is contained in:
Vasyl Teliman 2020-10-01 13:48:47 +03:00 committed by GitHub
parent 615fbe6cbc
commit 16cc197c8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 362 additions and 237 deletions

View File

@ -163,7 +163,8 @@ bool ConstantUniformFacts::FloatingPointValueIsSuitable(
return true;
}
bool ConstantUniformFacts::AddFact(const protobufs::FactConstantUniform& fact) {
bool ConstantUniformFacts::MaybeAddFact(
const protobufs::FactConstantUniform& fact) {
// 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.

View File

@ -31,7 +31,7 @@ class ConstantUniformFacts {
explicit ConstantUniformFacts(opt::IRContext* ir_context);
// See method in FactManager which delegates to this method.
bool AddFact(const protobufs::FactConstantUniform& fact);
bool MaybeAddFact(const protobufs::FactConstantUniform& fact);
// See method in FactManager which delegates to this method.
std::vector<uint32_t> GetConstantsAvailableFromUniformsForType(

View File

@ -55,32 +55,39 @@ DataSynonymAndIdEquationFacts::DataSynonymAndIdEquationFacts(
opt::IRContext* ir_context)
: ir_context_(ir_context) {}
void DataSynonymAndIdEquationFacts::AddFact(
bool DataSynonymAndIdEquationFacts::MaybeAddFact(
const protobufs::FactDataSynonym& fact,
const DeadBlockFacts& dead_block_facts,
const IrrelevantValueFacts& irrelevant_value_facts) {
(void)dead_block_facts; // Keep release compilers happy.
(void)irrelevant_value_facts; // Keep release compilers happy.
assert(!irrelevant_value_facts.IdIsIrrelevant(fact.data1().object(),
dead_block_facts) &&
!irrelevant_value_facts.IdIsIrrelevant(fact.data2().object(),
dead_block_facts) &&
"Irrelevant ids cannot be synonymous with other ids.");
if (irrelevant_value_facts.IdIsIrrelevant(fact.data1().object(),
dead_block_facts) ||
irrelevant_value_facts.IdIsIrrelevant(fact.data2().object(),
dead_block_facts)) {
// Irrelevant ids cannot be synonymous with other ids.
return false;
}
// Add the fact, including all facts relating sub-components of the data
// descriptors that are involved.
AddDataSynonymFactRecursive(fact.data1(), fact.data2());
return true;
}
void DataSynonymAndIdEquationFacts::AddFact(
bool DataSynonymAndIdEquationFacts::MaybeAddFact(
const protobufs::FactIdEquation& fact,
const DeadBlockFacts& dead_block_facts,
const IrrelevantValueFacts& irrelevant_value_facts) {
(void)dead_block_facts; // Keep release compilers happy.
(void)irrelevant_value_facts; // Keep release compilers happy.
assert(
!irrelevant_value_facts.IdIsIrrelevant(fact.lhs_id(), dead_block_facts) &&
"Irrelevant ids are not allowed.");
if (irrelevant_value_facts.IdIsIrrelevant(fact.lhs_id(), dead_block_facts)) {
// Irrelevant ids cannot participate in IdEquation facts.
return false;
}
for (auto id : fact.rhs_id()) {
if (irrelevant_value_facts.IdIsIrrelevant(id, dead_block_facts)) {
// Irrelevant ids cannot participate in IdEquation facts.
return false;
}
}
protobufs::DataDescriptor lhs_dd = MakeDataDescriptor(fact.lhs_id(), {});
@ -91,9 +98,6 @@ void DataSynonymAndIdEquationFacts::AddFact(
// equation.
std::vector<const protobufs::DataDescriptor*> rhs_dds;
for (auto rhs_id : fact.rhs_id()) {
assert(!irrelevant_value_facts.IdIsIrrelevant(rhs_id, dead_block_facts) &&
"Irrelevant ids are not allowed.");
// Register a data descriptor based on this id in the equivalence relation
// if needed, and then record the equivalence class representative.
rhs_dds.push_back(RegisterDataDescriptor(MakeDataDescriptor(rhs_id, {})));
@ -101,6 +105,7 @@ void DataSynonymAndIdEquationFacts::AddFact(
// Now add the fact.
AddEquationFactRecursive(lhs_dd, static_cast<SpvOp>(fact.opcode()), rhs_dds);
return true;
}
DataSynonymAndIdEquationFacts::OperationSet

View File

@ -38,19 +38,21 @@ class DataSynonymAndIdEquationFacts {
public:
explicit DataSynonymAndIdEquationFacts(opt::IRContext* ir_context);
// See method in FactManager which delegates to this method.
// |dead_block_facts| and |irrelevant_value_facts| are passed for consistency
// checks.
void AddFact(const protobufs::FactDataSynonym& fact,
const DeadBlockFacts& dead_block_facts,
const IrrelevantValueFacts& irrelevant_value_facts);
// See method in FactManager which delegates to this method. Returns true if
// neither |fact.data1()| nor |fact.data2()| contain an
// irrelevant id. Otherwise, returns false. |dead_block_facts| and
// |irrelevant_value_facts| are passed for consistency checks.
bool MaybeAddFact(const protobufs::FactDataSynonym& fact,
const DeadBlockFacts& dead_block_facts,
const IrrelevantValueFacts& irrelevant_value_facts);
// See method in FactManager which delegates to this method.
// |dead_block_facts| and |irrelevant_value_facts| are passed for consistency
// checks.
void AddFact(const protobufs::FactIdEquation& fact,
const DeadBlockFacts& dead_block_facts,
const IrrelevantValueFacts& irrelevant_value_facts);
// See method in FactManager which delegates to this method. Returns true if
// neither |fact.lhs_id()| nor any of |fact.rhs_id()| is irrelevant. Returns
// false otherwise. |dead_block_facts| and |irrelevant_value_facts| are passed
// for consistency checks.
bool MaybeAddFact(const protobufs::FactIdEquation& fact,
const DeadBlockFacts& dead_block_facts,
const IrrelevantValueFacts& irrelevant_value_facts);
// See method in FactManager which delegates to this method.
std::vector<const protobufs::DataDescriptor*> GetSynonymsForId(

View File

@ -14,12 +14,22 @@
#include "source/fuzz/fact_manager/dead_block_facts.h"
#include "source/fuzz/fuzzer_util.h"
namespace spvtools {
namespace fuzz {
namespace fact_manager {
void DeadBlockFacts::AddFact(const protobufs::FactBlockIsDead& fact) {
DeadBlockFacts::DeadBlockFacts(opt::IRContext* ir_context)
: ir_context_(ir_context) {}
bool DeadBlockFacts::MaybeAddFact(const protobufs::FactBlockIsDead& fact) {
if (!fuzzerutil::MaybeFindBlock(ir_context_, fact.block_id())) {
return false;
}
dead_block_ids_.insert(fact.block_id());
return true;
}
bool DeadBlockFacts::BlockIsDead(uint32_t block_id) const {

View File

@ -18,6 +18,7 @@
#include <unordered_set>
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/opt/ir_context.h"
namespace spvtools {
namespace fuzz {
@ -27,8 +28,12 @@ namespace fact_manager {
// facts about data blocks.
class DeadBlockFacts {
public:
// See method in FactManager which delegates to this method.
void AddFact(const protobufs::FactBlockIsDead& fact);
explicit DeadBlockFacts(opt::IRContext* ir_context);
// Marks |fact.block_id()| as being dead. Returns true if |fact.block_id()|
// represents a result id of some OpLabel instruction in |ir_context_|.
// Returns false otherwise.
bool MaybeAddFact(const protobufs::FactBlockIsDead& fact);
// See method in FactManager which delegates to this method.
bool BlockIsDead(uint32_t block_id) const;
@ -38,6 +43,7 @@ class DeadBlockFacts {
private:
std::unordered_set<uint32_t> dead_block_ids_;
opt::IRContext* ir_context_;
};
} // namespace fact_manager

View File

@ -90,38 +90,49 @@ std::string ToString(const protobufs::Fact& fact) {
FactManager::FactManager(opt::IRContext* ir_context)
: constant_uniform_facts_(ir_context),
data_synonym_and_id_equation_facts_(ir_context),
dead_block_facts_(),
livesafe_function_facts_(),
dead_block_facts_(ir_context),
livesafe_function_facts_(ir_context),
irrelevant_value_facts_(ir_context) {}
void FactManager::AddFacts(const MessageConsumer& message_consumer,
const protobufs::FactSequence& initial_facts) {
for (auto& fact : initial_facts.fact()) {
if (!AddFact(fact)) {
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::AddFact(const fuzz::protobufs::Fact& fact) {
bool FactManager::MaybeAddFact(const fuzz::protobufs::Fact& fact) {
switch (fact.fact_case()) {
case protobufs::Fact::kConstantUniformFact:
return constant_uniform_facts_.AddFact(fact.constant_uniform_fact());
case protobufs::Fact::kDataSynonymFact:
data_synonym_and_id_equation_facts_.AddFact(
fact.data_synonym_fact(), dead_block_facts_, irrelevant_value_facts_);
return true;
case protobufs::Fact::kBlockIsDeadFact:
dead_block_facts_.AddFact(fact.block_is_dead_fact());
return true;
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:
livesafe_function_facts_.AddFact(fact.function_is_livesafe_fact());
return true;
default:
assert(false && "Unknown fact type.");
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,
@ -129,8 +140,10 @@ void FactManager::AddFactDataSynonym(const protobufs::DataDescriptor& data1,
protobufs::FactDataSynonym fact;
*fact.mutable_data1() = data1;
*fact.mutable_data2() = data2;
data_synonym_and_id_equation_facts_.AddFact(fact, dead_block_facts_,
irrelevant_value_facts_);
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(
@ -190,7 +203,9 @@ bool FactManager::BlockIsDead(uint32_t block_id) const {
void FactManager::AddFactBlockIsDead(uint32_t block_id) {
protobufs::FactBlockIsDead fact;
fact.set_block_id(block_id);
dead_block_facts_.AddFact(fact);
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 {
@ -200,7 +215,9 @@ bool FactManager::FunctionIsLivesafe(uint32_t function_id) const {
void FactManager::AddFactFunctionIsLivesafe(uint32_t function_id) {
protobufs::FactFunctionIsLivesafe fact;
fact.set_function_id(function_id);
livesafe_function_facts_.AddFact(fact);
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 {
@ -218,13 +235,19 @@ std::unordered_set<uint32_t> FactManager::GetIrrelevantIds() const {
void FactManager::AddFactValueOfPointeeIsIrrelevant(uint32_t pointer_id) {
protobufs::FactPointeeValueIsIrrelevant fact;
fact.set_pointer_id(pointer_id);
irrelevant_value_facts_.AddFact(fact, data_synonym_and_id_equation_facts_);
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);
irrelevant_value_facts_.AddFact(fact, data_synonym_and_id_equation_facts_);
auto success = irrelevant_value_facts_.MaybeAddFact(
fact, data_synonym_and_id_equation_facts_);
(void)success; // Keep compilers happy in release mode.
assert(success && "|result_id| is invalid");
}
void FactManager::AddFactIdEquation(uint32_t lhs_id, SpvOp opcode,
@ -235,8 +258,10 @@ void FactManager::AddFactIdEquation(uint32_t lhs_id, SpvOp opcode,
for (auto an_rhs_id : rhs_id) {
fact.add_rhs_id(an_rhs_id);
}
data_synonym_and_id_equation_facts_.AddFact(fact, dead_block_facts_,
irrelevant_value_facts_);
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(

View File

@ -45,24 +45,27 @@ class FactManager {
explicit FactManager(opt::IRContext* ir_context);
// Adds all the facts from |facts|, checking them for validity with respect to
// |context|. Warnings about invalid facts are communicated via
// |ir_context_|. Warnings about invalid facts are communicated via
// |message_consumer|; such facts are otherwise ignored.
void AddFacts(const MessageConsumer& message_consumer,
const protobufs::FactSequence& facts);
void AddInitialFacts(const MessageConsumer& message_consumer,
const protobufs::FactSequence& facts);
// Checks the fact for validity with respect to |context|. Returns false,
// with no side effects, if the fact is invalid. Otherwise adds |fact| to the
// Checks the fact for validity with respect to |ir_context_|. Returns false,
// with no side effects, if the fact is invalid. Otherwise adds |fact| to the
// fact manager.
bool AddFact(const protobufs::Fact& fact);
bool MaybeAddFact(const protobufs::Fact& fact);
// Record the fact that |data1| and |data2| are synonymous.
// Record the fact that |data1| and |data2| are synonymous. Neither |data1|
// nor |data2| may contain an irrelevant id.
void AddFactDataSynonym(const protobufs::DataDescriptor& data1,
const protobufs::DataDescriptor& data2);
// Records the fact that |block_id| is dead.
// Records the fact that |block_id| is dead. |block_id| must be a result id
// of some OpLabel instruction in the |ir_context_|.
void AddFactBlockIsDead(uint32_t block_id);
// Records the fact that |function_id| is livesafe.
// Records the fact that |function_id| is livesafe. |function_id| must be a
// result id of some non-entry-point function in the module.
void AddFactFunctionIsLivesafe(uint32_t function_id);
// Records the fact that the value of the pointee associated with |pointer_id|
@ -72,13 +75,14 @@ class FactManager {
// Records a fact that the |result_id| is irrelevant (i.e. it doesn't affect
// the semantics of the module).
// |result_id| must exist in the module and actually be a pointer.
// |result_id| must exist in the module and it may not be a pointer.
void AddFactIdIsIrrelevant(uint32_t result_id);
// Records the fact that |lhs_id| is defined by the equation:
//
// |lhs_id| = |opcode| |rhs_id[0]| ... |rhs_id[N-1]|
//
// Neither |lhs_id| nor any of |rhs_id| may be irrelevant.
void AddFactIdEquation(uint32_t lhs_id, SpvOp opcode,
const std::vector<uint32_t>& rhs_id);
@ -117,7 +121,7 @@ class FactManager {
uint32_t type_id) const;
// Provides details of all uniform elements that are known to be equal to the
// constant associated with |constant_id| in |ir_context|.
// constant associated with |constant_id| in |ir_context_|.
std::vector<protobufs::UniformBufferElementDescriptor>
GetUniformDescriptorsForConstant(uint32_t constant_id) const;

View File

@ -27,36 +27,52 @@ namespace fact_manager {
IrrelevantValueFacts::IrrelevantValueFacts(opt::IRContext* ir_context)
: ir_context_(ir_context) {}
void IrrelevantValueFacts::AddFact(
bool IrrelevantValueFacts::MaybeAddFact(
const protobufs::FactPointeeValueIsIrrelevant& fact,
const DataSynonymAndIdEquationFacts& data_synonym_and_id_equation_facts) {
(void)data_synonym_and_id_equation_facts; // Keep release compilers happy.
assert(data_synonym_and_id_equation_facts.GetSynonymsForId(fact.pointer_id())
.empty() &&
"The id cannot participate in DataSynonym facts.");
auto pointer_def = ir_context_->get_def_use_mgr()->GetDef(fact.pointer_id());
assert(pointer_def && "The id must exist in the module.");
auto type = ir_context_->get_type_mgr()->GetType(pointer_def->type_id());
(void)type; // Keep release compilers happy.
assert(type && type->AsPointer() && "The id must be a pointer.");
const auto* inst = ir_context_->get_def_use_mgr()->GetDef(fact.pointer_id());
if (!inst || !inst->type_id()) {
// The id must exist in the module and have type id.
return false;
}
if (!ir_context_->get_type_mgr()->GetType(inst->type_id())->AsPointer()) {
// The id must be a pointer.
return false;
}
if (!data_synonym_and_id_equation_facts.GetSynonymsForId(fact.pointer_id())
.empty()) {
// Irrelevant id cannot participate in DataSynonym facts.
return false;
}
pointers_to_irrelevant_pointees_ids_.insert(fact.pointer_id());
return true;
}
void IrrelevantValueFacts::AddFact(
bool IrrelevantValueFacts::MaybeAddFact(
const protobufs::FactIdIsIrrelevant& fact,
const DataSynonymAndIdEquationFacts& data_synonym_and_id_equation_facts) {
(void)data_synonym_and_id_equation_facts; // Keep release compilers happy.
assert(data_synonym_and_id_equation_facts.GetSynonymsForId(fact.result_id())
.empty() &&
"The id cannot participate in DataSynonym facts.");
auto pointer_def = ir_context_->get_def_use_mgr()->GetDef(fact.result_id());
assert(pointer_def && "The id must exist in the module.");
auto type = ir_context_->get_type_mgr()->GetType(pointer_def->type_id());
(void)type; // Keep release compilers happy.
assert(type && !type->AsPointer() && "The id must not be a pointer.");
const auto* inst = ir_context_->get_def_use_mgr()->GetDef(fact.result_id());
if (!inst || !inst->type_id()) {
// The id must exist in the module and have type id.
return false;
}
if (ir_context_->get_type_mgr()->GetType(inst->type_id())->AsPointer()) {
// The id may not be a pointer.
return false;
}
if (!data_synonym_and_id_equation_facts.GetSynonymsForId(fact.result_id())
.empty()) {
// Irrelevant id cannot participate in DataSynonym facts.
return false;
}
irrelevant_ids_.insert(fact.result_id());
return true;
}
bool IrrelevantValueFacts::PointeeValueIsIrrelevant(uint32_t pointer_id) const {

View File

@ -35,17 +35,21 @@ class IrrelevantValueFacts {
public:
explicit IrrelevantValueFacts(opt::IRContext* ir_context);
// See method in FactManager which delegates to this method.
// |data_synonym_and_id_equation_facts| and |context| are passed for
// consistency checks.
void AddFact(
// See method in FactManager which delegates to this method. Returns true if
// |fact.pointer_id()| is a result id of pointer type in the |ir_context_| and
// |fact.pointer_id()| does not participate in DataSynonym facts. Returns
// false otherwise. |data_synonym_and_id_equation_facts| and |context| are
// passed for consistency checks.
bool MaybeAddFact(
const protobufs::FactPointeeValueIsIrrelevant& fact,
const DataSynonymAndIdEquationFacts& data_synonym_and_id_equation_facts);
// See method in FactManager which delegates to this method.
// |data_synonym_and_id_equation_facts| and |context| are passed for
// consistency checks.
void AddFact(
// See method in FactManager which delegates to this method. Returns true if
// |fact.result_id()| is a result id of non-pointer type in the |ir_context_|
// and |fact.result_id()| does not participate in DataSynonym facts. Returns
// false otherwise. |data_synonym_and_id_equation_facts| and |context| are
// passed for consistency checks.
bool MaybeAddFact(
const protobufs::FactIdIsIrrelevant& fact,
const DataSynonymAndIdEquationFacts& data_synonym_and_id_equation_facts);

View File

@ -14,13 +14,27 @@
#include "source/fuzz/fact_manager/livesafe_function_facts.h"
#include "source/fuzz/fuzzer_util.h"
namespace spvtools {
namespace fuzz {
namespace fact_manager {
void LivesafeFunctionFacts::AddFact(
LivesafeFunctionFacts::LivesafeFunctionFacts(opt::IRContext* ir_context)
: ir_context_(ir_context) {}
bool LivesafeFunctionFacts::MaybeAddFact(
const protobufs::FactFunctionIsLivesafe& fact) {
if (!fuzzerutil::FindFunction(ir_context_, fact.function_id())) {
return false;
}
if (fuzzerutil::FunctionIsEntryPoint(ir_context_, fact.function_id())) {
return false;
}
livesafe_function_ids_.insert(fact.function_id());
return true;
}
bool LivesafeFunctionFacts::FunctionIsLivesafe(uint32_t function_id) const {

View File

@ -18,6 +18,7 @@
#include <unordered_set>
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/opt/ir_context.h"
namespace spvtools {
namespace fuzz {
@ -27,14 +28,19 @@ namespace fact_manager {
// facts about livesafe functions.
class LivesafeFunctionFacts {
public:
// See method in FactManager which delegates to this method.
void AddFact(const protobufs::FactFunctionIsLivesafe& fact);
explicit LivesafeFunctionFacts(opt::IRContext* ir_context);
// See method in FactManager which delegates to this method. Returns true if
// |fact.function_id()| is a result id of some non-entry-point function in
// |ir_context_|. Returns false otherwise.
bool MaybeAddFact(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_;
opt::IRContext* ir_context_;
};
} // namespace fact_manager

View File

@ -185,7 +185,7 @@ bool ForceRenderRed(
TransformationContext transformation_context(
MakeUnique<FactManager>(ir_context.get()), validator_options);
for (auto& fact : initial_facts.fact()) {
transformation_context.GetFactManager()->AddFact(fact);
transformation_context.GetFactManager()->MaybeAddFact(fact);
}
auto entry_point_function =

View File

@ -216,8 +216,8 @@ Fuzzer::FuzzerResult Fuzzer::Run() {
transformation_context_ = MakeUnique<TransformationContext>(
MakeUnique<FactManager>(ir_context_.get()), validator_options_);
transformation_context_->GetFactManager()->AddFacts(consumer_,
initial_facts_);
transformation_context_->GetFactManager()->AddInitialFacts(consumer_,
initial_facts_);
RepeatedPassInstances pass_instances{};

View File

@ -108,7 +108,8 @@ Replayer::ReplayerResult Replayer::Run() {
MakeUnique<TransformationContext>(
MakeUnique<FactManager>(ir_context.get()), validator_options_,
MakeUnique<CounterOverflowIdSource>(first_overflow_id));
transformation_context->GetFactManager()->AddFacts(consumer_, initial_facts_);
transformation_context->GetFactManager()->AddInitialFacts(consumer_,
initial_facts_);
// We track the largest id bound observed, to ensure that it only increases
// as transformations are applied.

View File

@ -157,10 +157,6 @@ void TransformationAddDeadBlock::Apply(
enclosing_function->InsertBasicBlockAfter(std::move(new_block),
existing_block);
// Record the fact that the new block is dead.
transformation_context->GetFactManager()->AddFactBlockIsDead(
message_.fresh_id());
// Fix up OpPhi instructions in the successor block, so that the values they
// yield when control has transferred from the new block are the same as if
// control had transferred from |message_.existing_block|. This is guaranteed
@ -181,6 +177,10 @@ void TransformationAddDeadBlock::Apply(
// Do not rely on any existing analysis results since the control flow graph
// of the module has changed.
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
// Record the fact that the new block is dead.
transformation_context->GetFactManager()->AddFactBlockIsDead(
message_.fresh_id());
}
protobufs::Transformation TransformationAddDeadBlock::ToMessage() const {

View File

@ -173,11 +173,15 @@ void TransformationAddFunction::Apply(
success = TryToMakeFunctionLivesafe(ir_context, *transformation_context);
assert(success && "It should be possible to make the function livesafe.");
(void)(success); // Keep release builds happy.
}
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
assert(message_.instruction(0).opcode() == SpvOpFunction &&
"The first instruction of an 'add function' transformation must be "
"OpFunction.");
if (message_.is_livesafe()) {
// Inform the fact manager that the function is livesafe.
assert(message_.instruction(0).opcode() == SpvOpFunction &&
"The first instruction of an 'add function' transformation must be "
"OpFunction.");
transformation_context->GetFactManager()->AddFactFunctionIsLivesafe(
message_.instruction(0).result_id());
} else {
@ -189,7 +193,6 @@ void TransformationAddFunction::Apply(
}
}
}
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
// Record the fact that all pointer parameters and variables declared in the
// function should be regarded as having irrelevant values. This allows other

View File

@ -358,14 +358,6 @@ void TransformationOutlineFunction::Apply(
region_input_ids, region_output_ids, input_id_to_fresh_id_map, ir_context,
transformation_context);
// If the original function was livesafe, the new function should also be
// livesafe.
if (transformation_context->GetFactManager()->FunctionIsLivesafe(
original_region_entry_block->GetParent()->result_id())) {
transformation_context->GetFactManager()->AddFactFunctionIsLivesafe(
message_.new_function_id());
}
// Adapt the region to be outlined so that its input ids are replaced with the
// ids of the outlined function's input parameters, and so that output ids
// are similarly remapped.
@ -375,10 +367,10 @@ void TransformationOutlineFunction::Apply(
// Fill out the body of the outlined function according to the region that is
// being outlined.
PopulateOutlinedFunction(
*original_region_entry_block, *original_region_exit_block, region_blocks,
region_output_ids, output_id_to_fresh_id_map, ir_context,
outlined_function.get(), transformation_context);
PopulateOutlinedFunction(*original_region_entry_block,
*original_region_exit_block, region_blocks,
region_output_ids, output_id_to_fresh_id_map,
ir_context, outlined_function.get());
// Collapse the region that has been outlined into a function down to a single
// block that calls said function.
@ -389,11 +381,28 @@ void TransformationOutlineFunction::Apply(
std::move(cloned_exit_block_terminator), original_region_entry_block);
// Add the outlined function to the module.
const auto* outlined_function_ptr = outlined_function.get();
ir_context->module()->AddFunction(std::move(outlined_function));
// Major surgery has been conducted on the module, so invalidate all analyses.
ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
// If the original function was livesafe, the new function should also be
// livesafe.
if (transformation_context->GetFactManager()->FunctionIsLivesafe(
original_region_entry_block->GetParent()->result_id())) {
transformation_context->GetFactManager()->AddFactFunctionIsLivesafe(
message_.new_function_id());
}
// Record the fact that all blocks in the outlined region are dead if the
// first block is dead.
if (transformation_context->GetFactManager()->BlockIsDead(
original_region_entry_block->id())) {
transformation_context->GetFactManager()->AddFactBlockIsDead(
outlined_function_ptr->entry()->id());
}
}
protobufs::Transformation TransformationOutlineFunction::ToMessage() const {
@ -750,8 +759,7 @@ void TransformationOutlineFunction::PopulateOutlinedFunction(
const std::set<opt::BasicBlock*>& region_blocks,
const std::vector<uint32_t>& region_output_ids,
const std::map<uint32_t, uint32_t>& output_id_to_fresh_id_map,
opt::IRContext* ir_context, opt::Function* outlined_function,
TransformationContext* transformation_context) const {
opt::IRContext* ir_context, opt::Function* outlined_function) const {
// When we create the exit block for the outlined region, we use this pointer
// to track of it so that we can manipulate it later.
opt::BasicBlock* outlined_region_exit_block = nullptr;
@ -765,14 +773,6 @@ void TransformationOutlineFunction::PopulateOutlinedFunction(
opt::Instruction::OperandList()));
outlined_region_entry_block->SetParent(outlined_function);
// If the original region's entry block was dead, the outlined region's entry
// block is also dead.
if (transformation_context->GetFactManager()->BlockIsDead(
original_region_entry_block.id())) {
transformation_context->GetFactManager()->AddFactBlockIsDead(
outlined_region_entry_block->id());
}
if (&original_region_entry_block == &original_region_exit_block) {
outlined_region_exit_block = outlined_region_entry_block.get();
}
@ -879,7 +879,7 @@ void TransformationOutlineFunction::PopulateOutlinedFunction(
}
void TransformationOutlineFunction::ShrinkOriginalRegion(
opt::IRContext* ir_context, std::set<opt::BasicBlock*>& region_blocks,
opt::IRContext* ir_context, const std::set<opt::BasicBlock*>& region_blocks,
const std::vector<uint32_t>& region_input_ids,
const std::vector<uint32_t>& region_output_ids,
const std::map<uint32_t, uint32_t>& output_id_to_type_id,

View File

@ -189,8 +189,7 @@ class TransformationOutlineFunction : public Transformation {
const std::set<opt::BasicBlock*>& region_blocks,
const std::vector<uint32_t>& region_output_ids,
const std::map<uint32_t, uint32_t>& output_id_to_fresh_id_map,
opt::IRContext* ir_context, opt::Function* outlined_function,
TransformationContext* transformation_context) const;
opt::IRContext* ir_context, opt::Function* outlined_function) const;
// Shrinks the outlined region, given by |region_blocks|, down to the single
// block |original_region_entry_block|. This block is itself shrunk to just
@ -209,7 +208,8 @@ class TransformationOutlineFunction : public Transformation {
// function is called, this information cannot be gotten from the def-use
// manager.
void ShrinkOriginalRegion(
opt::IRContext* ir_context, std::set<opt::BasicBlock*>& region_blocks,
opt::IRContext* ir_context,
const std::set<opt::BasicBlock*>& region_blocks,
const std::vector<uint32_t>& region_input_ids,
const std::vector<uint32_t>& region_output_ids,
const std::map<uint32_t, uint32_t>& output_id_to_type_id,

View File

@ -124,6 +124,10 @@ void TransformationSplitBlock::Apply(
phi_inst->SetInOperand(1, {block_to_split->id()});
});
// Invalidate all analyses
ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
// If the block being split was dead, the new block arising from the split is
// also dead.
if (transformation_context->GetFactManager()->BlockIsDead(
@ -131,10 +135,6 @@ void TransformationSplitBlock::Apply(
transformation_context->GetFactManager()->AddFactBlockIsDead(
message_.fresh_id());
}
// Invalidate all analyses
ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
}
protobufs::Transformation TransformationSplitBlock::ToMessage() const {

View File

@ -125,19 +125,20 @@ TEST(DataSynonymTransformationTest, ArrayCompositeSynonyms) {
spvtools::ValidatorOptions validator_options;
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(12, {}, 100, {0}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(13, {}, 100, {1}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(22, {}, 100, {2}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(28, {}, 101, {0}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(23, {}, 101, {1}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(32, {}, 101, {2}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(23, {}, 101, {3}));
// Replace %12 with %100[0] in '%25 = OpAccessChain %24 %20 %12'
@ -411,11 +412,12 @@ TEST(DataSynonymTransformationTest, MatrixCompositeSynonyms) {
spvtools::ValidatorOptions validator_options;
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(23, {}, 100, {0}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(25, {}, 100, {1}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(50, {}, 100, {2}));
// Replace %23 with %100[0] in '%26 = OpFAdd %7 %23 %25'
@ -579,19 +581,20 @@ TEST(DataSynonymTransformationTest, StructCompositeSynonyms) {
spvtools::ValidatorOptions validator_options;
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(16, {}, 100, {0}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(45, {}, 100, {1}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(27, {}, 101, {0}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(36, {}, 101, {1}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(27, {}, 101, {2}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(22, {}, 102, {0}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(15, {}, 102, {1}));
// Replace %45 with %100[1] in '%46 = OpCompositeConstruct %32 %35 %45'
@ -867,45 +870,46 @@ TEST(DataSynonymTransformationTest, VectorCompositeSynonyms) {
spvtools::ValidatorOptions validator_options;
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(20, {0}, 100, {0}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(20, {1}, 100, {1}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(20, {2}, 100, {2}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(54, {}, 100, {3}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(15, {0}, 101, {0}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(15, {1}, 101, {1}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(19, {0}, 101, {2}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(19, {1}, 101, {3}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(27, {}, 102, {0}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(15, {0}, 102, {1}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(15, {1}, 102, {2}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(33, {}, 103, {0}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(47, {0}, 103, {1}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(47, {1}, 103, {2}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(47, {2}, 103, {3}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(42, {}, 104, {0}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(45, {}, 104, {1}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(38, {0}, 105, {0}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(38, {1}, 105, {1}));
transformation_context.GetFactManager()->AddFact(
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(46, {}, 105, {2}));
// Replace %20 with %100[0:2] in '%80 = OpCopyObject %16 %20'

View File

@ -45,7 +45,7 @@ bool AddFactHelper(
descriptor;
protobufs::Fact fact;
*fact.mutable_constant_uniform_fact() = constant_uniform_fact;
return fact_manager->AddFact(fact);
return fact_manager->MaybeAddFact(fact);
}
TEST(FactManagerTest, ConstantsAvailableViaUniforms) {

View File

@ -32,21 +32,21 @@ protobufs::Fact MakeSynonymFact(uint32_t first, uint32_t second) {
// Adds synonym facts to the fact manager.
void SetUpIdSynonyms(FactManager* fact_manager) {
// Synonyms {9, 11, 15, 16, 21, 22}
fact_manager->AddFact(MakeSynonymFact(11, 9));
fact_manager->AddFact(MakeSynonymFact(15, 9));
fact_manager->AddFact(MakeSynonymFact(16, 9));
fact_manager->AddFact(MakeSynonymFact(21, 9));
fact_manager->AddFact(MakeSynonymFact(22, 9));
fact_manager->MaybeAddFact(MakeSynonymFact(11, 9));
fact_manager->MaybeAddFact(MakeSynonymFact(15, 9));
fact_manager->MaybeAddFact(MakeSynonymFact(16, 9));
fact_manager->MaybeAddFact(MakeSynonymFact(21, 9));
fact_manager->MaybeAddFact(MakeSynonymFact(22, 9));
// Synonyms {10, 23}
fact_manager->AddFact(MakeSynonymFact(10, 23));
fact_manager->MaybeAddFact(MakeSynonymFact(10, 23));
// Synonyms {14, 27}
fact_manager->AddFact(MakeSynonymFact(14, 27));
fact_manager->MaybeAddFact(MakeSynonymFact(14, 27));
// Synonyms {24, 26, 30}
fact_manager->AddFact(MakeSynonymFact(26, 24));
fact_manager->AddFact(MakeSynonymFact(30, 24));
fact_manager->MaybeAddFact(MakeSynonymFact(26, 24));
fact_manager->MaybeAddFact(MakeSynonymFact(30, 24));
}
// Returns true if the given lists have the same elements, regardless of their

View File

@ -31,12 +31,12 @@ protobufs::Fact MakeSynonymFact(uint32_t first, uint32_t second) {
// Adds synonym facts to the fact manager.
void SetUpIdSynonyms(FactManager* fact_manager) {
fact_manager->AddFact(MakeSynonymFact(11, 9));
fact_manager->AddFact(MakeSynonymFact(13, 9));
fact_manager->AddFact(MakeSynonymFact(14, 9));
fact_manager->AddFact(MakeSynonymFact(19, 9));
fact_manager->AddFact(MakeSynonymFact(20, 9));
fact_manager->AddFact(MakeSynonymFact(10, 21));
fact_manager->MaybeAddFact(MakeSynonymFact(11, 9));
fact_manager->MaybeAddFact(MakeSynonymFact(13, 9));
fact_manager->MaybeAddFact(MakeSynonymFact(14, 9));
fact_manager->MaybeAddFact(MakeSynonymFact(19, 9));
fact_manager->MaybeAddFact(MakeSynonymFact(20, 9));
fact_manager->MaybeAddFact(MakeSynonymFact(10, 21));
}
TEST(TransformationAddOpPhiSynonymTest, Inapplicable) {
@ -89,7 +89,8 @@ TEST(TransformationAddOpPhiSynonymTest, Inapplicable) {
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
SetUpIdSynonyms(transformation_context.GetFactManager());
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(23, 24));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(23, 24));
// %13 is not a block label.
ASSERT_FALSE(TransformationAddOpPhiSynonym(13, {{}}, 100)
@ -211,8 +212,8 @@ TEST(TransformationAddOpPhiSynonymTest, Apply) {
SetUpIdSynonyms(transformation_context.GetFactManager());
// Add some further synonym facts.
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(28, 9));
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(30, 9));
transformation_context.GetFactManager()->MaybeAddFact(MakeSynonymFact(28, 9));
transformation_context.GetFactManager()->MaybeAddFact(MakeSynonymFact(30, 9));
auto transformation1 = TransformationAddOpPhiSynonym(17, {{{15, 13}}}, 100);
ASSERT_TRUE(
@ -356,8 +357,9 @@ TEST(TransformationAddOpPhiSynonymTest, VariablePointers) {
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
// Declare synonyms
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(3, 15));
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(12, 16));
transformation_context.GetFactManager()->MaybeAddFact(MakeSynonymFact(3, 15));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(12, 16));
// Remove the VariablePointers capability.
context.get()->get_feature_mgr()->RemoveCapability(

View File

@ -31,7 +31,7 @@ bool AddFactHelper(
descriptor;
protobufs::Fact fact;
*fact.mutable_constant_uniform_fact() = constant_uniform_fact;
return transformation_context->GetFactManager()->AddFact(fact);
return transformation_context->GetFactManager()->MaybeAddFact(fact);
}
TEST(TransformationReplaceConstantWithUniformTest, BasicReplacements) {

View File

@ -200,17 +200,17 @@ protobufs::Fact MakeSynonymFact(uint32_t first, uint32_t second) {
// Equips the fact manager with synonym facts for the above shader.
void SetUpIdSynonyms(FactManager* fact_manager) {
fact_manager->AddFact(MakeSynonymFact(15, 200));
fact_manager->AddFact(MakeSynonymFact(15, 201));
fact_manager->AddFact(MakeSynonymFact(15, 202));
fact_manager->AddFact(MakeSynonymFact(55, 203));
fact_manager->AddFact(MakeSynonymFact(54, 204));
fact_manager->AddFact(MakeSynonymFact(74, 205));
fact_manager->AddFact(MakeSynonymFact(78, 206));
fact_manager->AddFact(MakeSynonymFact(84, 207));
fact_manager->AddFact(MakeSynonymFact(33, 208));
fact_manager->AddFact(MakeSynonymFact(12, 209));
fact_manager->AddFact(MakeSynonymFact(19, 210));
fact_manager->MaybeAddFact(MakeSynonymFact(15, 200));
fact_manager->MaybeAddFact(MakeSynonymFact(15, 201));
fact_manager->MaybeAddFact(MakeSynonymFact(15, 202));
fact_manager->MaybeAddFact(MakeSynonymFact(55, 203));
fact_manager->MaybeAddFact(MakeSynonymFact(54, 204));
fact_manager->MaybeAddFact(MakeSynonymFact(74, 205));
fact_manager->MaybeAddFact(MakeSynonymFact(78, 206));
fact_manager->MaybeAddFact(MakeSynonymFact(84, 207));
fact_manager->MaybeAddFact(MakeSynonymFact(33, 208));
fact_manager->MaybeAddFact(MakeSynonymFact(12, 209));
fact_manager->MaybeAddFact(MakeSynonymFact(19, 210));
}
TEST(TransformationReplaceIdWithSynonymTest, IllegalTransformations) {
@ -520,8 +520,10 @@ TEST(TransformationReplaceIdWithSynonymTest, SynonymsOfVariables) {
spvtools::ValidatorOptions validator_options;
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(10, 100));
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(8, 101));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(10, 100));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(8, 101));
// Replace %10 with %100 in:
// %11 = OpLoad %6 %10
@ -650,7 +652,8 @@ TEST(TransformationReplaceIdWithSynonymTest,
spvtools::ValidatorOptions validator_options;
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(14, 100));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(14, 100));
// Replace %14 with %100 in:
// %16 = OpFunctionCall %2 %10 %14
@ -815,19 +818,32 @@ TEST(TransformationReplaceIdWithSynonymTest, SynonymsOfAccessChainIndices) {
MakeUnique<FactManager>(context.get()), validator_options);
// Add synonym facts corresponding to the OpCopyObject operations that have
// been applied to all constants in the module.
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(16, 100));
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(21, 101));
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(17, 102));
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(57, 103));
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(18, 104));
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(40, 105));
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(32, 106));
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(43, 107));
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(55, 108));
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(8, 109));
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(47, 110));
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(28, 111));
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(45, 112));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(16, 100));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(21, 101));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(17, 102));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(57, 103));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(18, 104));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(40, 105));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(32, 106));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(43, 107));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(55, 108));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(8, 109));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(47, 110));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(28, 111));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(45, 112));
// Replacements of the form %16 -> %100
@ -1300,9 +1316,11 @@ TEST(TransformationReplaceIdWithSynonymTest, RuntimeArrayTest) {
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
// Add synonym fact relating %50 and %12.
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(50, 12));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(50, 12));
// Add synonym fact relating %51 and %14.
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(51, 14));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(51, 14));
// Not legal because the index being replaced is a struct index.
ASSERT_FALSE(
@ -1409,7 +1427,8 @@ TEST(TransformationReplaceIdWithSynonymTest,
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
// Add synonym fact relating %100 and %9.
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(100, 9));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(100, 9));
// Not legal the Sample argument of OpImageTexelPointer needs to be a zero
// constant.
@ -1469,7 +1488,8 @@ TEST(TransformationReplaceIdWithSynonymTest, EquivalentIntegerConstants) {
MakeUnique<FactManager>(context.get()), validator_options);
// Add synonym fact relating %10 and %13 (equivalent integer constant with
// different signedness).
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(10, 13));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(10, 13));
// Legal because OpSNegate always considers the integer as signed
auto replacement1 = TransformationReplaceIdWithSynonym(
@ -1611,7 +1631,8 @@ TEST(TransformationReplaceIdWithSynonymTest, EquivalentIntegerVectorConstants) {
MakeUnique<FactManager>(context.get()), validator_options);
// Add synonym fact relating %10 and %13 (equivalent integer vectors with
// different signedness).
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(14, 15));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(14, 15));
// Legal because OpIAdd does not consider the signedness of the operands
auto replacement1 = TransformationReplaceIdWithSynonym(
@ -1630,7 +1651,8 @@ TEST(TransformationReplaceIdWithSynonymTest, EquivalentIntegerVectorConstants) {
// Add synonym fact relating %12 and %13 (equivalent integer constants with
// different signedness).
transformation_context.GetFactManager()->AddFact(MakeSynonymFact(12, 13));
transformation_context.GetFactManager()->MaybeAddFact(
MakeSynonymFact(12, 13));
// Legal because the indices of OpAccessChain are always treated as signed
auto replacement2 = TransformationReplaceIdWithSynonym(