spirv-fuzz: Introduce TransformationContext (#3272)

Some transformations (e.g. TransformationAddFunction) rely on running
the validator to decide whether the transformation is applicable.  A
recent change allowed spirv-fuzz to take validator options, to cater
for the case where a module should be considered valid under
particular conditions.  However, validation during the checking of
transformations had no access to these validator options.

This change introduced TransformationContext, which currently consists
of a fact manager and a set of validator options, but could in the
future have other fields corresponding to other objects that it is
useful to have access to when applying transformations.  Now, instead
of checking and applying transformations in the context of a
FactManager, a TransformationContext is used.  This gives access to
the fact manager as before, and also access to the validator options
when they are needed.
This commit is contained in:
Alastair Donaldson 2020-04-02 15:54:46 +01:00 committed by GitHub
parent 2fdea57d19
commit 8d4261bc44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
204 changed files with 4879 additions and 3344 deletions

View File

@ -99,6 +99,7 @@ if(SPIRV_BUILD_FUZZER)
transformation_add_type_vector.h transformation_add_type_vector.h
transformation_composite_construct.h transformation_composite_construct.h
transformation_composite_extract.h transformation_composite_extract.h
transformation_context.h
transformation_copy_object.h transformation_copy_object.h
transformation_equation_instruction.h transformation_equation_instruction.h
transformation_function_call.h transformation_function_call.h
@ -190,6 +191,7 @@ if(SPIRV_BUILD_FUZZER)
transformation_add_type_vector.cpp transformation_add_type_vector.cpp
transformation_composite_construct.cpp transformation_composite_construct.cpp
transformation_composite_extract.cpp transformation_composite_extract.cpp
transformation_context.cpp
transformation_copy_object.cpp transformation_copy_object.cpp
transformation_equation_instruction.cpp transformation_equation_instruction.cpp
transformation_function_call.cpp transformation_function_call.cpp

View File

@ -17,6 +17,7 @@
#include "source/fuzz/fact_manager.h" #include "source/fuzz/fact_manager.h"
#include "source/fuzz/instruction_descriptor.h" #include "source/fuzz/instruction_descriptor.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation_context.h"
#include "source/fuzz/transformation_replace_constant_with_uniform.h" #include "source/fuzz/transformation_replace_constant_with_uniform.h"
#include "source/fuzz/uniform_buffer_element_descriptor.h" #include "source/fuzz/uniform_buffer_element_descriptor.h"
#include "source/opt/build_module.h" #include "source/opt/build_module.h"
@ -159,7 +160,8 @@ MakeConstantUniformReplacement(opt::IRContext* ir_context,
} // namespace } // namespace
bool ForceRenderRed( bool ForceRenderRed(
const spv_target_env& target_env, const std::vector<uint32_t>& binary_in, const spv_target_env& target_env, spv_validator_options validator_options,
const std::vector<uint32_t>& binary_in,
const spvtools::fuzz::protobufs::FactSequence& initial_facts, const spvtools::fuzz::protobufs::FactSequence& initial_facts,
std::vector<uint32_t>* binary_out) { std::vector<uint32_t>* binary_out) {
auto message_consumer = spvtools::utils::CLIMessageConsumer; auto message_consumer = spvtools::utils::CLIMessageConsumer;
@ -171,7 +173,7 @@ bool ForceRenderRed(
} }
// Initial binary should be valid. // Initial binary should be valid.
if (!tools.Validate(&binary_in[0], binary_in.size())) { if (!tools.Validate(&binary_in[0], binary_in.size(), validator_options)) {
message_consumer(SPV_MSG_ERROR, nullptr, {}, message_consumer(SPV_MSG_ERROR, nullptr, {},
"Initial binary is invalid; stopping."); "Initial binary is invalid; stopping.");
return false; return false;
@ -187,6 +189,8 @@ bool ForceRenderRed(
for (auto& fact : initial_facts.fact()) { for (auto& fact : initial_facts.fact()) {
fact_manager.AddFact(fact, ir_context.get()); fact_manager.AddFact(fact, ir_context.get());
} }
TransformationContext transformation_context(&fact_manager,
validator_options);
auto entry_point_function = auto entry_point_function =
FindFragmentShaderEntryPoint(ir_context.get(), message_consumer); FindFragmentShaderEntryPoint(ir_context.get(), message_consumer);
@ -355,8 +359,9 @@ bool ForceRenderRed(
for (auto& replacement : {first_greater_then_operand_replacement.get(), for (auto& replacement : {first_greater_then_operand_replacement.get(),
second_greater_then_operand_replacement.get()}) { second_greater_then_operand_replacement.get()}) {
if (replacement) { if (replacement) {
assert(replacement->IsApplicable(ir_context.get(), fact_manager)); assert(replacement->IsApplicable(ir_context.get(),
replacement->Apply(ir_context.get(), &fact_manager); transformation_context));
replacement->Apply(ir_context.get(), &transformation_context);
} }
} }
} }

View File

@ -38,7 +38,8 @@ namespace fuzz {
// instead become: 'u > v', where 'u' and 'v' are pieces of uniform data for // instead become: 'u > v', where 'u' and 'v' are pieces of uniform data for
// which it is known that 'u < v' holds. // which it is known that 'u < v' holds.
bool ForceRenderRed( bool ForceRenderRed(
const spv_target_env& target_env, const std::vector<uint32_t>& binary_in, const spv_target_env& target_env, spv_validator_options validator_options,
const std::vector<uint32_t>& binary_in,
const spvtools::fuzz::protobufs::FactSequence& initial_facts, const spvtools::fuzz::protobufs::FactSequence& initial_facts,
std::vector<uint32_t>* binary_out); std::vector<uint32_t>* binary_out);

View File

@ -51,6 +51,7 @@
#include "source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h" #include "source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/pseudo_random_generator.h" #include "source/fuzz/pseudo_random_generator.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/build_module.h" #include "source/opt/build_module.h"
#include "source/spirv_fuzzer_options.h" #include "source/spirv_fuzzer_options.h"
#include "source/util/make_unique.h" #include "source/util/make_unique.h"
@ -66,19 +67,19 @@ const uint32_t kTransformationLimit = 500;
const uint32_t kChanceOfApplyingAnotherPass = 85; const uint32_t kChanceOfApplyingAnotherPass = 85;
// A convenience method to add a fuzzer pass to |passes| with probability 0.5. // A convenience method to add a fuzzer pass to |passes| with probability 0.5.
// All fuzzer passes take |ir_context|, |fact_manager|, |fuzzer_context| and // All fuzzer passes take |ir_context|, |transformation_context|,
// |transformation_sequence_out| as parameters. Extra arguments can be provided // |fuzzer_context| and |transformation_sequence_out| as parameters. Extra
// via |extra_args|. // arguments can be provided via |extra_args|.
template <typename T, typename... Args> template <typename T, typename... Args>
void MaybeAddPass( void MaybeAddPass(
std::vector<std::unique_ptr<FuzzerPass>>* passes, std::vector<std::unique_ptr<FuzzerPass>>* passes,
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformation_sequence_out, protobufs::TransformationSequence* transformation_sequence_out,
Args&&... extra_args) { Args&&... extra_args) {
if (fuzzer_context->ChooseEven()) { if (fuzzer_context->ChooseEven()) {
passes->push_back(MakeUnique<T>(ir_context, fact_manager, fuzzer_context, passes->push_back(MakeUnique<T>(ir_context, transformation_context,
transformation_sequence_out, fuzzer_context, transformation_sequence_out,
std::forward<Args>(extra_args)...)); std::forward<Args>(extra_args)...));
} }
} }
@ -182,11 +183,13 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
FactManager fact_manager; FactManager fact_manager;
fact_manager.AddFacts(impl_->consumer, initial_facts, ir_context.get()); fact_manager.AddFacts(impl_->consumer, initial_facts, ir_context.get());
TransformationContext transformation_context(&fact_manager,
impl_->validator_options);
// Add some essential ingredients to the module if they are not already // Add some essential ingredients to the module if they are not already
// present, such as boolean constants. // present, such as boolean constants.
FuzzerPassAddUsefulConstructs add_useful_constructs( FuzzerPassAddUsefulConstructs add_useful_constructs(
ir_context.get(), &fact_manager, &fuzzer_context, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
if (!impl_->ApplyPassAndCheckValidity(&add_useful_constructs, *ir_context, if (!impl_->ApplyPassAndCheckValidity(&add_useful_constructs, *ir_context,
tools)) { tools)) {
@ -196,69 +199,69 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
// Apply some semantics-preserving passes. // Apply some semantics-preserving passes.
std::vector<std::unique_ptr<FuzzerPass>> passes; std::vector<std::unique_ptr<FuzzerPass>> passes;
while (passes.empty()) { while (passes.empty()) {
MaybeAddPass<FuzzerPassAddAccessChains>(&passes, ir_context.get(), MaybeAddPass<FuzzerPassAddAccessChains>(
&fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassAddCompositeTypes>(&passes, ir_context.get(), MaybeAddPass<FuzzerPassAddCompositeTypes>(
&fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassAddDeadBlocks>(&passes, ir_context.get(), MaybeAddPass<FuzzerPassAddDeadBlocks>(
&fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassAddDeadBreaks>(&passes, ir_context.get(), MaybeAddPass<FuzzerPassAddDeadBreaks>(
&fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassAddDeadContinues>(&passes, ir_context.get(), MaybeAddPass<FuzzerPassAddDeadContinues>(
&fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassAddEquationInstructions>( MaybeAddPass<FuzzerPassAddEquationInstructions>(
&passes, ir_context.get(), &fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassAddFunctionCalls>(&passes, ir_context.get(), MaybeAddPass<FuzzerPassAddFunctionCalls>(
&fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassAddGlobalVariables>(&passes, ir_context.get(), MaybeAddPass<FuzzerPassAddGlobalVariables>(
&fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassAddLoads>(&passes, ir_context.get(), &fact_manager, MaybeAddPass<FuzzerPassAddLoads>(&passes, ir_context.get(),
&fuzzer_context, &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassAddLocalVariables>(&passes, ir_context.get(), MaybeAddPass<FuzzerPassAddLocalVariables>(
&fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassAddStores>(&passes, ir_context.get(), &fact_manager, MaybeAddPass<FuzzerPassAddStores>(&passes, ir_context.get(),
&fuzzer_context, &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassApplyIdSynonyms>(&passes, ir_context.get(), MaybeAddPass<FuzzerPassApplyIdSynonyms>(
&fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassConstructComposites>(&passes, ir_context.get(), MaybeAddPass<FuzzerPassConstructComposites>(
&fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassCopyObjects>(&passes, ir_context.get(), MaybeAddPass<FuzzerPassCopyObjects>(
&fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassDonateModules>( MaybeAddPass<FuzzerPassDonateModules>(
&passes, ir_context.get(), &fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out, donor_suppliers); transformation_sequence_out, donor_suppliers);
MaybeAddPass<FuzzerPassMergeBlocks>(&passes, ir_context.get(), MaybeAddPass<FuzzerPassMergeBlocks>(
&fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassObfuscateConstants>(&passes, ir_context.get(), MaybeAddPass<FuzzerPassObfuscateConstants>(
&fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassOutlineFunctions>(&passes, ir_context.get(), MaybeAddPass<FuzzerPassOutlineFunctions>(
&fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassPermuteBlocks>(&passes, ir_context.get(), MaybeAddPass<FuzzerPassPermuteBlocks>(
&fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassPermuteFunctionParameters>( MaybeAddPass<FuzzerPassPermuteFunctionParameters>(
&passes, ir_context.get(), &fact_manager, &fuzzer_context, &passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassSplitBlocks>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassSplitBlocks>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
} }
bool is_first = true; bool is_first = true;
@ -279,25 +282,25 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
// as they do not unlock other passes. // as they do not unlock other passes.
std::vector<std::unique_ptr<FuzzerPass>> final_passes; std::vector<std::unique_ptr<FuzzerPass>> final_passes;
MaybeAddPass<FuzzerPassAdjustFunctionControls>( MaybeAddPass<FuzzerPassAdjustFunctionControls>(
&final_passes, ir_context.get(), &fact_manager, &fuzzer_context, &final_passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAdjustLoopControls>(
&final_passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassAdjustLoopControls>(&final_passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAdjustMemoryOperandsMasks>( MaybeAddPass<FuzzerPassAdjustMemoryOperandsMasks>(
&final_passes, ir_context.get(), &fact_manager, &fuzzer_context, &final_passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassAdjustSelectionControls>( MaybeAddPass<FuzzerPassAdjustSelectionControls>(
&final_passes, ir_context.get(), &fact_manager, &fuzzer_context, &final_passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassAddNoContractionDecorations>( MaybeAddPass<FuzzerPassAddNoContractionDecorations>(
&final_passes, ir_context.get(), &fact_manager, &fuzzer_context, &final_passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassSwapCommutableOperands>( MaybeAddPass<FuzzerPassSwapCommutableOperands>(
&final_passes, ir_context.get(), &fact_manager, &fuzzer_context, &final_passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
MaybeAddPass<FuzzerPassToggleAccessChainInstruction>( MaybeAddPass<FuzzerPassToggleAccessChainInstruction>(
&final_passes, ir_context.get(), &fact_manager, &fuzzer_context, &final_passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out); transformation_sequence_out);
for (auto& pass : final_passes) { for (auto& pass : final_passes) {
if (!impl_->ApplyPassAndCheckValidity(pass.get(), *ir_context, tools)) { if (!impl_->ApplyPassAndCheckValidity(pass.get(), *ir_context, tools)) {

View File

@ -31,11 +31,12 @@
namespace spvtools { namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPass::FuzzerPass(opt::IRContext* ir_context, FactManager* fact_manager, FuzzerPass::FuzzerPass(opt::IRContext* ir_context,
TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: ir_context_(ir_context), : ir_context_(ir_context),
fact_manager_(fact_manager), transformation_context_(transformation_context),
fuzzer_context_(fuzzer_context), fuzzer_context_(fuzzer_context),
transformations_(transformations) {} transformations_(transformations) {}

View File

@ -18,9 +18,9 @@
#include <functional> #include <functional>
#include <vector> #include <vector>
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/fuzzer_context.h" #include "source/fuzz/fuzzer_context.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
namespace spvtools { namespace spvtools {
@ -29,22 +29,25 @@ namespace fuzz {
// Interface for applying a pass of transformations to a module. // Interface for applying a pass of transformations to a module.
class FuzzerPass { class FuzzerPass {
public: public:
FuzzerPass(opt::IRContext* ir_context, FactManager* fact_manager, FuzzerPass(opt::IRContext* ir_context,
TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);
virtual ~FuzzerPass(); virtual ~FuzzerPass();
// Applies the pass to the module |ir_context_|, assuming and updating // Applies the pass to the module |ir_context_|, assuming and updating
// facts from |fact_manager_|, and using |fuzzer_context_| to guide the // information from |transformation_context_|, and using |fuzzer_context_| to
// process. Appends to |transformations_| all transformations that were // guide the process. Appends to |transformations_| all transformations that
// applied during the pass. // were applied during the pass.
virtual void Apply() = 0; virtual void Apply() = 0;
protected: protected:
opt::IRContext* GetIRContext() const { return ir_context_; } opt::IRContext* GetIRContext() const { return ir_context_; }
FactManager* GetFactManager() const { return fact_manager_; } TransformationContext* GetTransformationContext() const {
return transformation_context_;
}
FuzzerContext* GetFuzzerContext() const { return fuzzer_context_; } FuzzerContext* GetFuzzerContext() const { return fuzzer_context_; }
@ -93,9 +96,10 @@ class FuzzerPass {
// by construction, and adding it to the sequence of applied transformations. // by construction, and adding it to the sequence of applied transformations.
template <typename TransformationType> template <typename TransformationType>
void ApplyTransformation(const TransformationType& transformation) { void ApplyTransformation(const TransformationType& transformation) {
assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) && assert(transformation.IsApplicable(GetIRContext(),
*GetTransformationContext()) &&
"Transformation should be applicable by construction."); "Transformation should be applicable by construction.");
transformation.Apply(GetIRContext(), GetFactManager()); transformation.Apply(GetIRContext(), GetTransformationContext());
*GetTransformations()->add_transformation() = transformation.ToMessage(); *GetTransformations()->add_transformation() = transformation.ToMessage();
} }
@ -230,7 +234,7 @@ class FuzzerPass {
const std::vector<uint32_t>& constant_ids); const std::vector<uint32_t>& constant_ids);
opt::IRContext* ir_context_; opt::IRContext* ir_context_;
FactManager* fact_manager_; TransformationContext* transformation_context_;
FuzzerContext* fuzzer_context_; FuzzerContext* fuzzer_context_;
protobufs::TransformationSequence* transformations_; protobufs::TransformationSequence* transformations_;
}; };

View File

@ -21,10 +21,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassAddAccessChains::FuzzerPassAddAccessChains( FuzzerPassAddAccessChains::FuzzerPassAddAccessChains(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAddAccessChains::~FuzzerPassAddAccessChains() = default; FuzzerPassAddAccessChains::~FuzzerPassAddAccessChains() = default;

View File

@ -26,7 +26,7 @@ namespace fuzz {
class FuzzerPassAddAccessChains : public FuzzerPass { class FuzzerPassAddAccessChains : public FuzzerPass {
public: public:
FuzzerPassAddAccessChains(opt::IRContext* ir_context, FuzzerPassAddAccessChains(opt::IRContext* ir_context,
FactManager* fact_manager, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -22,10 +22,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassAddCompositeTypes::FuzzerPassAddCompositeTypes( FuzzerPassAddCompositeTypes::FuzzerPassAddCompositeTypes(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAddCompositeTypes::~FuzzerPassAddCompositeTypes() = default; FuzzerPassAddCompositeTypes::~FuzzerPassAddCompositeTypes() = default;

View File

@ -25,7 +25,7 @@ namespace fuzz {
class FuzzerPassAddCompositeTypes : public FuzzerPass { class FuzzerPassAddCompositeTypes : public FuzzerPass {
public: public:
FuzzerPassAddCompositeTypes( FuzzerPassAddCompositeTypes(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -21,10 +21,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassAddDeadBlocks::FuzzerPassAddDeadBlocks( FuzzerPassAddDeadBlocks::FuzzerPassAddDeadBlocks(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAddDeadBlocks::~FuzzerPassAddDeadBlocks() = default; FuzzerPassAddDeadBlocks::~FuzzerPassAddDeadBlocks() = default;
@ -53,8 +54,9 @@ void FuzzerPassAddDeadBlocks::Apply() {
} }
// Apply all those transformations that are in fact applicable. // Apply all those transformations that are in fact applicable.
for (auto& transformation : candidate_transformations) { for (auto& transformation : candidate_transformations) {
if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) { if (transformation.IsApplicable(GetIRContext(),
transformation.Apply(GetIRContext(), GetFactManager()); *GetTransformationContext())) {
transformation.Apply(GetIRContext(), GetTransformationContext());
*GetTransformations()->add_transformation() = transformation.ToMessage(); *GetTransformations()->add_transformation() = transformation.ToMessage();
} }
} }

View File

@ -24,7 +24,8 @@ namespace fuzz {
// passes can then manipulate such blocks. // passes can then manipulate such blocks.
class FuzzerPassAddDeadBlocks : public FuzzerPass { class FuzzerPassAddDeadBlocks : public FuzzerPass {
public: public:
FuzzerPassAddDeadBlocks(opt::IRContext* ir_context, FactManager* fact_manager, FuzzerPassAddDeadBlocks(opt::IRContext* ir_context,
TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -21,10 +21,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassAddDeadBreaks::FuzzerPassAddDeadBreaks( FuzzerPassAddDeadBreaks::FuzzerPassAddDeadBreaks(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAddDeadBreaks::~FuzzerPassAddDeadBreaks() = default; FuzzerPassAddDeadBreaks::~FuzzerPassAddDeadBreaks() = default;
@ -79,8 +80,8 @@ void FuzzerPassAddDeadBreaks::Apply() {
auto candidate_transformation = TransformationAddDeadBreak( auto candidate_transformation = TransformationAddDeadBreak(
block.id(), merge_block->id(), GetFuzzerContext()->ChooseEven(), block.id(), merge_block->id(), GetFuzzerContext()->ChooseEven(),
std::move(phi_ids)); std::move(phi_ids));
if (candidate_transformation.IsApplicable(GetIRContext(), if (candidate_transformation.IsApplicable(
*GetFactManager())) { GetIRContext(), *GetTransformationContext())) {
// Only consider a transformation as a candidate if it is applicable. // Only consider a transformation as a candidate if it is applicable.
candidate_transformations.push_back( candidate_transformations.push_back(
std::move(candidate_transformation)); std::move(candidate_transformation));
@ -109,10 +110,11 @@ void FuzzerPassAddDeadBreaks::Apply() {
candidate_transformations.erase(candidate_transformations.begin() + index); candidate_transformations.erase(candidate_transformations.begin() + index);
// Probabilistically decide whether to try to apply it vs. ignore it, in the // Probabilistically decide whether to try to apply it vs. ignore it, in the
// case that it is applicable. // case that it is applicable.
if (transformation.IsApplicable(GetIRContext(), *GetFactManager()) && if (transformation.IsApplicable(GetIRContext(),
*GetTransformationContext()) &&
GetFuzzerContext()->ChoosePercentage( GetFuzzerContext()->ChoosePercentage(
GetFuzzerContext()->GetChanceOfAddingDeadBreak())) { GetFuzzerContext()->GetChanceOfAddingDeadBreak())) {
transformation.Apply(GetIRContext(), GetFactManager()); transformation.Apply(GetIRContext(), GetTransformationContext());
*GetTransformations()->add_transformation() = transformation.ToMessage(); *GetTransformations()->add_transformation() = transformation.ToMessage();
} }
} }

View File

@ -23,7 +23,8 @@ namespace fuzz {
// A fuzzer pass for adding dead break edges to the module. // A fuzzer pass for adding dead break edges to the module.
class FuzzerPassAddDeadBreaks : public FuzzerPass { class FuzzerPassAddDeadBreaks : public FuzzerPass {
public: public:
FuzzerPassAddDeadBreaks(opt::IRContext* ir_context, FactManager* fact_manager, FuzzerPassAddDeadBreaks(opt::IRContext* ir_context,
TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -21,10 +21,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassAddDeadContinues::FuzzerPassAddDeadContinues( FuzzerPassAddDeadContinues::FuzzerPassAddDeadContinues(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAddDeadContinues::~FuzzerPassAddDeadContinues() = default; FuzzerPassAddDeadContinues::~FuzzerPassAddDeadContinues() = default;
@ -75,10 +76,11 @@ void FuzzerPassAddDeadContinues::Apply() {
// Probabilistically decide whether to apply the transformation in the // Probabilistically decide whether to apply the transformation in the
// case that it is applicable. // case that it is applicable.
if (candidate_transformation.IsApplicable(GetIRContext(), if (candidate_transformation.IsApplicable(GetIRContext(),
*GetFactManager()) && *GetTransformationContext()) &&
GetFuzzerContext()->ChoosePercentage( GetFuzzerContext()->ChoosePercentage(
GetFuzzerContext()->GetChanceOfAddingDeadContinue())) { GetFuzzerContext()->GetChanceOfAddingDeadContinue())) {
candidate_transformation.Apply(GetIRContext(), GetFactManager()); candidate_transformation.Apply(GetIRContext(),
GetTransformationContext());
*GetTransformations()->add_transformation() = *GetTransformations()->add_transformation() =
candidate_transformation.ToMessage(); candidate_transformation.ToMessage();
} }

View File

@ -24,7 +24,7 @@ namespace fuzz {
class FuzzerPassAddDeadContinues : public FuzzerPass { class FuzzerPassAddDeadContinues : public FuzzerPass {
public: public:
FuzzerPassAddDeadContinues( FuzzerPassAddDeadContinues(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -23,10 +23,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassAddEquationInstructions::FuzzerPassAddEquationInstructions( FuzzerPassAddEquationInstructions::FuzzerPassAddEquationInstructions(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAddEquationInstructions::~FuzzerPassAddEquationInstructions() = FuzzerPassAddEquationInstructions::~FuzzerPassAddEquationInstructions() =
default; default;

View File

@ -27,7 +27,7 @@ namespace fuzz {
class FuzzerPassAddEquationInstructions : public FuzzerPass { class FuzzerPassAddEquationInstructions : public FuzzerPass {
public: public:
FuzzerPassAddEquationInstructions( FuzzerPassAddEquationInstructions(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -24,10 +24,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassAddFunctionCalls::FuzzerPassAddFunctionCalls( FuzzerPassAddFunctionCalls::FuzzerPassAddFunctionCalls(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAddFunctionCalls::~FuzzerPassAddFunctionCalls() = default; FuzzerPassAddFunctionCalls::~FuzzerPassAddFunctionCalls() = default;
@ -74,8 +75,9 @@ void FuzzerPassAddFunctionCalls::Apply() {
while (!candidate_functions.empty()) { while (!candidate_functions.empty()) {
opt::Function* candidate_function = opt::Function* candidate_function =
GetFuzzerContext()->RemoveAtRandomIndex(&candidate_functions); GetFuzzerContext()->RemoveAtRandomIndex(&candidate_functions);
if (!GetFactManager()->BlockIsDead(block->id()) && if (!GetTransformationContext()->GetFactManager()->BlockIsDead(
!GetFactManager()->FunctionIsLivesafe( block->id()) &&
!GetTransformationContext()->GetFactManager()->FunctionIsLivesafe(
candidate_function->result_id())) { candidate_function->result_id())) {
// Unless in a dead block, only livesafe functions can be invoked // Unless in a dead block, only livesafe functions can be invoked
continue; continue;
@ -132,9 +134,11 @@ FuzzerPassAddFunctionCalls::GetAvailableInstructionsSuitableForActualParameters(
default: default:
return false; return false;
} }
if (!GetFactManager()->BlockIsDead(block->id()) && if (!GetTransformationContext()->GetFactManager()->BlockIsDead(
!GetFactManager()->PointeeValueIsIrrelevant( block->id()) &&
inst->result_id())) { !GetTransformationContext()
->GetFactManager()
->PointeeValueIsIrrelevant(inst->result_id())) {
// We can only pass a pointer as an actual parameter // We can only pass a pointer as an actual parameter
// if the pointee value for the pointer is irrelevant, // if the pointee value for the pointer is irrelevant,
// or if the block from which we would make the // or if the block from which we would make the

View File

@ -25,7 +25,7 @@ namespace fuzz {
class FuzzerPassAddFunctionCalls : public FuzzerPass { class FuzzerPassAddFunctionCalls : public FuzzerPass {
public: public:
FuzzerPassAddFunctionCalls( FuzzerPassAddFunctionCalls(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -21,10 +21,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassAddGlobalVariables::FuzzerPassAddGlobalVariables( FuzzerPassAddGlobalVariables::FuzzerPassAddGlobalVariables(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAddGlobalVariables::~FuzzerPassAddGlobalVariables() = default; FuzzerPassAddGlobalVariables::~FuzzerPassAddGlobalVariables() = default;

View File

@ -25,7 +25,7 @@ namespace fuzz {
class FuzzerPassAddGlobalVariables : public FuzzerPass { class FuzzerPassAddGlobalVariables : public FuzzerPass {
public: public:
FuzzerPassAddGlobalVariables( FuzzerPassAddGlobalVariables(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -21,10 +21,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassAddLoads::FuzzerPassAddLoads( FuzzerPassAddLoads::FuzzerPassAddLoads(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAddLoads::~FuzzerPassAddLoads() = default; FuzzerPassAddLoads::~FuzzerPassAddLoads() = default;

View File

@ -23,7 +23,8 @@ namespace fuzz {
// Fuzzer pass that adds stores, at random, from pointers in the module. // Fuzzer pass that adds stores, at random, from pointers in the module.
class FuzzerPassAddLoads : public FuzzerPass { class FuzzerPassAddLoads : public FuzzerPass {
public: public:
FuzzerPassAddLoads(opt::IRContext* ir_context, FactManager* fact_manager, FuzzerPassAddLoads(opt::IRContext* ir_context,
TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -22,10 +22,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassAddLocalVariables::FuzzerPassAddLocalVariables( FuzzerPassAddLocalVariables::FuzzerPassAddLocalVariables(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAddLocalVariables::~FuzzerPassAddLocalVariables() = default; FuzzerPassAddLocalVariables::~FuzzerPassAddLocalVariables() = default;

View File

@ -25,7 +25,7 @@ namespace fuzz {
class FuzzerPassAddLocalVariables : public FuzzerPass { class FuzzerPassAddLocalVariables : public FuzzerPass {
public: public:
FuzzerPassAddLocalVariables( FuzzerPassAddLocalVariables(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -20,10 +20,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassAddNoContractionDecorations::FuzzerPassAddNoContractionDecorations( FuzzerPassAddNoContractionDecorations::FuzzerPassAddNoContractionDecorations(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAddNoContractionDecorations:: FuzzerPassAddNoContractionDecorations::
~FuzzerPassAddNoContractionDecorations() = default; ~FuzzerPassAddNoContractionDecorations() = default;

View File

@ -24,7 +24,7 @@ namespace fuzz {
class FuzzerPassAddNoContractionDecorations : public FuzzerPass { class FuzzerPassAddNoContractionDecorations : public FuzzerPass {
public: public:
FuzzerPassAddNoContractionDecorations( FuzzerPassAddNoContractionDecorations(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -21,10 +21,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassAddStores::FuzzerPassAddStores( FuzzerPassAddStores::FuzzerPassAddStores(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAddStores::~FuzzerPassAddStores() = default; FuzzerPassAddStores::~FuzzerPassAddStores() = default;
@ -82,9 +83,13 @@ void FuzzerPassAddStores::Apply() {
default: default:
break; break;
} }
return GetFactManager()->BlockIsDead(block->id()) || return GetTransformationContext()
GetFactManager()->PointeeValueIsIrrelevant( ->GetFactManager()
instruction->result_id()); ->BlockIsDead(block->id()) ||
GetTransformationContext()
->GetFactManager()
->PointeeValueIsIrrelevant(
instruction->result_id());
}); });
// At this point, |relevant_pointers| contains all the pointers we might // At this point, |relevant_pointers| contains all the pointers we might

View File

@ -25,7 +25,8 @@ namespace fuzz {
// are known not to affect the module's overall behaviour. // are known not to affect the module's overall behaviour.
class FuzzerPassAddStores : public FuzzerPass { class FuzzerPassAddStores : public FuzzerPass {
public: public:
FuzzerPassAddStores(opt::IRContext* ir_context, FactManager* fact_manager, FuzzerPassAddStores(opt::IRContext* ir_context,
TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -25,10 +25,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassAddUsefulConstructs::FuzzerPassAddUsefulConstructs( FuzzerPassAddUsefulConstructs::FuzzerPassAddUsefulConstructs(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAddUsefulConstructs::~FuzzerPassAddUsefulConstructs() = default; FuzzerPassAddUsefulConstructs::~FuzzerPassAddUsefulConstructs() = default;
@ -49,9 +50,10 @@ void FuzzerPassAddUsefulConstructs::MaybeAddIntConstant(
TransformationAddConstantScalar add_constant_int = TransformationAddConstantScalar add_constant_int =
TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(), TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(),
int_type_id, data); int_type_id, data);
assert(add_constant_int.IsApplicable(GetIRContext(), *GetFactManager()) && assert(add_constant_int.IsApplicable(GetIRContext(),
*GetTransformationContext()) &&
"Should be applicable by construction."); "Should be applicable by construction.");
add_constant_int.Apply(GetIRContext(), GetFactManager()); add_constant_int.Apply(GetIRContext(), GetTransformationContext());
*GetTransformations()->add_transformation() = add_constant_int.ToMessage(); *GetTransformations()->add_transformation() = add_constant_int.ToMessage();
} }
} }
@ -75,9 +77,10 @@ void FuzzerPassAddUsefulConstructs::MaybeAddFloatConstant(
TransformationAddConstantScalar add_constant_float = TransformationAddConstantScalar add_constant_float =
TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(), TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(),
float_type_id, data); float_type_id, data);
assert(add_constant_float.IsApplicable(GetIRContext(), *GetFactManager()) && assert(add_constant_float.IsApplicable(GetIRContext(),
*GetTransformationContext()) &&
"Should be applicable by construction."); "Should be applicable by construction.");
add_constant_float.Apply(GetIRContext(), GetFactManager()); add_constant_float.Apply(GetIRContext(), GetTransformationContext());
*GetTransformations()->add_transformation() = *GetTransformations()->add_transformation() =
add_constant_float.ToMessage(); add_constant_float.ToMessage();
} }
@ -90,9 +93,10 @@ void FuzzerPassAddUsefulConstructs::Apply() {
if (!GetIRContext()->get_type_mgr()->GetId(&temp_bool_type)) { if (!GetIRContext()->get_type_mgr()->GetId(&temp_bool_type)) {
auto add_type_boolean = auto add_type_boolean =
TransformationAddTypeBoolean(GetFuzzerContext()->GetFreshId()); TransformationAddTypeBoolean(GetFuzzerContext()->GetFreshId());
assert(add_type_boolean.IsApplicable(GetIRContext(), *GetFactManager()) && assert(add_type_boolean.IsApplicable(GetIRContext(),
*GetTransformationContext()) &&
"Should be applicable by construction."); "Should be applicable by construction.");
add_type_boolean.Apply(GetIRContext(), GetFactManager()); add_type_boolean.Apply(GetIRContext(), GetTransformationContext());
*GetTransformations()->add_transformation() = *GetTransformations()->add_transformation() =
add_type_boolean.ToMessage(); add_type_boolean.ToMessage();
} }
@ -105,9 +109,10 @@ void FuzzerPassAddUsefulConstructs::Apply() {
if (!GetIRContext()->get_type_mgr()->GetId(&temp_int_type)) { if (!GetIRContext()->get_type_mgr()->GetId(&temp_int_type)) {
TransformationAddTypeInt add_type_int = TransformationAddTypeInt( TransformationAddTypeInt add_type_int = TransformationAddTypeInt(
GetFuzzerContext()->GetFreshId(), 32, is_signed); GetFuzzerContext()->GetFreshId(), 32, is_signed);
assert(add_type_int.IsApplicable(GetIRContext(), *GetFactManager()) && assert(add_type_int.IsApplicable(GetIRContext(),
*GetTransformationContext()) &&
"Should be applicable by construction."); "Should be applicable by construction.");
add_type_int.Apply(GetIRContext(), GetFactManager()); add_type_int.Apply(GetIRContext(), GetTransformationContext());
*GetTransformations()->add_transformation() = add_type_int.ToMessage(); *GetTransformations()->add_transformation() = add_type_int.ToMessage();
} }
} }
@ -119,9 +124,10 @@ void FuzzerPassAddUsefulConstructs::Apply() {
if (!GetIRContext()->get_type_mgr()->GetId(&temp_float_type)) { if (!GetIRContext()->get_type_mgr()->GetId(&temp_float_type)) {
TransformationAddTypeFloat add_type_float = TransformationAddTypeFloat add_type_float =
TransformationAddTypeFloat(GetFuzzerContext()->GetFreshId(), 32); TransformationAddTypeFloat(GetFuzzerContext()->GetFreshId(), 32);
assert(add_type_float.IsApplicable(GetIRContext(), *GetFactManager()) && assert(add_type_float.IsApplicable(GetIRContext(),
*GetTransformationContext()) &&
"Should be applicable by construction."); "Should be applicable by construction.");
add_type_float.Apply(GetIRContext(), GetFactManager()); add_type_float.Apply(GetIRContext(), GetTransformationContext());
*GetTransformations()->add_transformation() = add_type_float.ToMessage(); *GetTransformations()->add_transformation() = add_type_float.ToMessage();
} }
} }
@ -139,9 +145,9 @@ void FuzzerPassAddUsefulConstructs::Apply() {
TransformationAddConstantBoolean add_constant_boolean( TransformationAddConstantBoolean add_constant_boolean(
GetFuzzerContext()->GetFreshId(), boolean_value); GetFuzzerContext()->GetFreshId(), boolean_value);
assert(add_constant_boolean.IsApplicable(GetIRContext(), assert(add_constant_boolean.IsApplicable(GetIRContext(),
*GetFactManager()) && *GetTransformationContext()) &&
"Should be applicable by construction."); "Should be applicable by construction.");
add_constant_boolean.Apply(GetIRContext(), GetFactManager()); add_constant_boolean.Apply(GetIRContext(), GetTransformationContext());
*GetTransformations()->add_transformation() = *GetTransformations()->add_transformation() =
add_constant_boolean.ToMessage(); add_constant_boolean.ToMessage();
} }
@ -168,8 +174,9 @@ void FuzzerPassAddUsefulConstructs::Apply() {
// of the element // of the element
// - a signed integer constant for each index required to access the element // - a signed integer constant for each index required to access the element
// - a constant for the constant value itself // - a constant for the constant value itself
for (auto& fact_and_type_id : for (auto& fact_and_type_id : GetTransformationContext()
GetFactManager()->GetConstantUniformFactsAndTypes()) { ->GetFactManager()
->GetConstantUniformFactsAndTypes()) {
uint32_t element_type_id = fact_and_type_id.second; uint32_t element_type_id = fact_and_type_id.second;
assert(element_type_id); assert(element_type_id);
auto element_type = auto element_type =
@ -183,9 +190,10 @@ void FuzzerPassAddUsefulConstructs::Apply() {
auto add_pointer = auto add_pointer =
TransformationAddTypePointer(GetFuzzerContext()->GetFreshId(), TransformationAddTypePointer(GetFuzzerContext()->GetFreshId(),
SpvStorageClassUniform, element_type_id); SpvStorageClassUniform, element_type_id);
assert(add_pointer.IsApplicable(GetIRContext(), *GetFactManager()) && assert(add_pointer.IsApplicable(GetIRContext(),
*GetTransformationContext()) &&
"Should be applicable by construction."); "Should be applicable by construction.");
add_pointer.Apply(GetIRContext(), GetFactManager()); add_pointer.Apply(GetIRContext(), GetTransformationContext());
*GetTransformations()->add_transformation() = add_pointer.ToMessage(); *GetTransformations()->add_transformation() = add_pointer.ToMessage();
} }
std::vector<uint32_t> words; std::vector<uint32_t> words;

View File

@ -25,7 +25,7 @@ namespace fuzz {
class FuzzerPassAddUsefulConstructs : public FuzzerPass { class FuzzerPassAddUsefulConstructs : public FuzzerPass {
public: public:
FuzzerPassAddUsefulConstructs( FuzzerPassAddUsefulConstructs(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -20,10 +20,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassAdjustFunctionControls::FuzzerPassAdjustFunctionControls( FuzzerPassAdjustFunctionControls::FuzzerPassAdjustFunctionControls(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAdjustFunctionControls::~FuzzerPassAdjustFunctionControls() = default; FuzzerPassAdjustFunctionControls::~FuzzerPassAdjustFunctionControls() = default;

View File

@ -24,7 +24,7 @@ namespace fuzz {
class FuzzerPassAdjustFunctionControls : public FuzzerPass { class FuzzerPassAdjustFunctionControls : public FuzzerPass {
public: public:
FuzzerPassAdjustFunctionControls( FuzzerPassAdjustFunctionControls(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -20,10 +20,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassAdjustLoopControls::FuzzerPassAdjustLoopControls( FuzzerPassAdjustLoopControls::FuzzerPassAdjustLoopControls(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAdjustLoopControls::~FuzzerPassAdjustLoopControls() = default; FuzzerPassAdjustLoopControls::~FuzzerPassAdjustLoopControls() = default;

View File

@ -24,7 +24,7 @@ namespace fuzz {
class FuzzerPassAdjustLoopControls : public FuzzerPass { class FuzzerPassAdjustLoopControls : public FuzzerPass {
public: public:
FuzzerPassAdjustLoopControls( FuzzerPassAdjustLoopControls(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -21,10 +21,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassAdjustMemoryOperandsMasks::FuzzerPassAdjustMemoryOperandsMasks( FuzzerPassAdjustMemoryOperandsMasks::FuzzerPassAdjustMemoryOperandsMasks(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAdjustMemoryOperandsMasks::~FuzzerPassAdjustMemoryOperandsMasks() = FuzzerPassAdjustMemoryOperandsMasks::~FuzzerPassAdjustMemoryOperandsMasks() =
default; default;

View File

@ -25,7 +25,7 @@ namespace fuzz {
class FuzzerPassAdjustMemoryOperandsMasks : public FuzzerPass { class FuzzerPassAdjustMemoryOperandsMasks : public FuzzerPass {
public: public:
FuzzerPassAdjustMemoryOperandsMasks( FuzzerPassAdjustMemoryOperandsMasks(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -20,10 +20,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassAdjustSelectionControls::FuzzerPassAdjustSelectionControls( FuzzerPassAdjustSelectionControls::FuzzerPassAdjustSelectionControls(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAdjustSelectionControls::~FuzzerPassAdjustSelectionControls() = FuzzerPassAdjustSelectionControls::~FuzzerPassAdjustSelectionControls() =
default; default;

View File

@ -24,7 +24,7 @@ namespace fuzz {
class FuzzerPassAdjustSelectionControls : public FuzzerPass { class FuzzerPassAdjustSelectionControls : public FuzzerPass {
public: public:
FuzzerPassAdjustSelectionControls( FuzzerPassAdjustSelectionControls(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -25,16 +25,19 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassApplyIdSynonyms::FuzzerPassApplyIdSynonyms( FuzzerPassApplyIdSynonyms::FuzzerPassApplyIdSynonyms(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassApplyIdSynonyms::~FuzzerPassApplyIdSynonyms() = default; FuzzerPassApplyIdSynonyms::~FuzzerPassApplyIdSynonyms() = default;
void FuzzerPassApplyIdSynonyms::Apply() { void FuzzerPassApplyIdSynonyms::Apply() {
for (auto id_with_known_synonyms : for (auto id_with_known_synonyms :
GetFactManager()->GetIdsForWhichSynonymsAreKnown(GetIRContext())) { GetTransformationContext()
->GetFactManager()
->GetIdsForWhichSynonymsAreKnown(GetIRContext())) {
// Gather up all uses of |id_with_known_synonym|, and then subsequently // Gather up all uses of |id_with_known_synonym|, and then subsequently
// iterate over these uses. We use this separation because, when // iterate over these uses. We use this separation because, when
// considering a given use, we might apply a transformation that will // considering a given use, we might apply a transformation that will
@ -70,7 +73,8 @@ void FuzzerPassApplyIdSynonyms::Apply() {
} }
std::vector<const protobufs::DataDescriptor*> synonyms_to_try; std::vector<const protobufs::DataDescriptor*> synonyms_to_try;
for (auto& data_descriptor : GetFactManager()->GetSynonymsForId( for (auto& data_descriptor :
GetTransformationContext()->GetFactManager()->GetSynonymsForId(
id_with_known_synonyms, GetIRContext())) { id_with_known_synonyms, GetIRContext())) {
protobufs::DataDescriptor descriptor_for_this_id = protobufs::DataDescriptor descriptor_for_this_id =
MakeDataDescriptor(id_with_known_synonyms, {}); MakeDataDescriptor(id_with_known_synonyms, {});

View File

@ -27,7 +27,7 @@ namespace fuzz {
class FuzzerPassApplyIdSynonyms : public FuzzerPass { class FuzzerPassApplyIdSynonyms : public FuzzerPass {
public: public:
FuzzerPassApplyIdSynonyms(opt::IRContext* ir_context, FuzzerPassApplyIdSynonyms(opt::IRContext* ir_context,
FactManager* fact_manager, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -25,10 +25,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassConstructComposites::FuzzerPassConstructComposites( FuzzerPassConstructComposites::FuzzerPassConstructComposites(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassConstructComposites::~FuzzerPassConstructComposites() = default; FuzzerPassConstructComposites::~FuzzerPassConstructComposites() = default;
@ -143,9 +144,10 @@ void FuzzerPassConstructComposites::Apply() {
TransformationCompositeConstruct transformation( TransformationCompositeConstruct transformation(
chosen_composite_type, *constructor_arguments, chosen_composite_type, *constructor_arguments,
instruction_descriptor, GetFuzzerContext()->GetFreshId()); instruction_descriptor, GetFuzzerContext()->GetFreshId());
assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) && assert(transformation.IsApplicable(GetIRContext(),
*GetTransformationContext()) &&
"This transformation should be applicable by construction."); "This transformation should be applicable by construction.");
transformation.Apply(GetIRContext(), GetFactManager()); transformation.Apply(GetIRContext(), GetTransformationContext());
*GetTransformations()->add_transformation() = *GetTransformations()->add_transformation() =
transformation.ToMessage(); transformation.ToMessage();
}); });

View File

@ -27,7 +27,7 @@ namespace fuzz {
class FuzzerPassConstructComposites : public FuzzerPass { class FuzzerPassConstructComposites : public FuzzerPass {
public: public:
FuzzerPassConstructComposites( FuzzerPassConstructComposites(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -21,10 +21,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassCopyObjects::FuzzerPassCopyObjects( FuzzerPassCopyObjects::FuzzerPassCopyObjects(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassCopyObjects::~FuzzerPassCopyObjects() = default; FuzzerPassCopyObjects::~FuzzerPassCopyObjects() = default;

View File

@ -23,7 +23,8 @@ namespace fuzz {
// A fuzzer pass for adding adding copies of objects to the module. // A fuzzer pass for adding adding copies of objects to the module.
class FuzzerPassCopyObjects : public FuzzerPass { class FuzzerPassCopyObjects : public FuzzerPass {
public: public:
FuzzerPassCopyObjects(opt::IRContext* ir_context, FactManager* fact_manager, FuzzerPassCopyObjects(opt::IRContext* ir_context,
TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -40,11 +40,12 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassDonateModules::FuzzerPassDonateModules( FuzzerPassDonateModules::FuzzerPassDonateModules(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations, protobufs::TransformationSequence* transformations,
const std::vector<fuzzerutil::ModuleSupplier>& donor_suppliers) const std::vector<fuzzerutil::ModuleSupplier>& donor_suppliers)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations), : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations),
donor_suppliers_(donor_suppliers) {} donor_suppliers_(donor_suppliers) {}
FuzzerPassDonateModules::~FuzzerPassDonateModules() = default; FuzzerPassDonateModules::~FuzzerPassDonateModules() = default;
@ -62,7 +63,9 @@ void FuzzerPassDonateModules::Apply() {
std::unique_ptr<opt::IRContext> donor_ir_context = donor_suppliers_.at( std::unique_ptr<opt::IRContext> donor_ir_context = donor_suppliers_.at(
GetFuzzerContext()->RandomIndex(donor_suppliers_))(); GetFuzzerContext()->RandomIndex(donor_suppliers_))();
assert(donor_ir_context != nullptr && "Supplying of donor failed"); assert(donor_ir_context != nullptr && "Supplying of donor failed");
assert(fuzzerutil::IsValid(donor_ir_context.get()) && assert(fuzzerutil::IsValid(
donor_ir_context.get(),
GetTransformationContext()->GetValidatorOptions()) &&
"The donor module must be valid"); "The donor module must be valid");
// Donate the supplied module. // Donate the supplied module.
// //

View File

@ -28,7 +28,7 @@ namespace fuzz {
class FuzzerPassDonateModules : public FuzzerPass { class FuzzerPassDonateModules : public FuzzerPass {
public: public:
FuzzerPassDonateModules( FuzzerPassDonateModules(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations, protobufs::TransformationSequence* transformations,
const std::vector<fuzzerutil::ModuleSupplier>& donor_suppliers); const std::vector<fuzzerutil::ModuleSupplier>& donor_suppliers);

View File

@ -22,10 +22,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassMergeBlocks::FuzzerPassMergeBlocks( FuzzerPassMergeBlocks::FuzzerPassMergeBlocks(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassMergeBlocks::~FuzzerPassMergeBlocks() = default; FuzzerPassMergeBlocks::~FuzzerPassMergeBlocks() = default;
@ -44,7 +45,8 @@ void FuzzerPassMergeBlocks::Apply() {
// For other blocks, we add a transformation to merge the block into its // For other blocks, we add a transformation to merge the block into its
// predecessor if that transformation would be applicable. // predecessor if that transformation would be applicable.
TransformationMergeBlocks transformation(block.id()); TransformationMergeBlocks transformation(block.id());
if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) { if (transformation.IsApplicable(GetIRContext(),
*GetTransformationContext())) {
potential_transformations.push_back(transformation); potential_transformations.push_back(transformation);
} }
} }
@ -54,8 +56,9 @@ void FuzzerPassMergeBlocks::Apply() {
uint32_t index = GetFuzzerContext()->RandomIndex(potential_transformations); uint32_t index = GetFuzzerContext()->RandomIndex(potential_transformations);
auto transformation = potential_transformations.at(index); auto transformation = potential_transformations.at(index);
potential_transformations.erase(potential_transformations.begin() + index); potential_transformations.erase(potential_transformations.begin() + index);
if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) { if (transformation.IsApplicable(GetIRContext(),
transformation.Apply(GetIRContext(), GetFactManager()); *GetTransformationContext())) {
transformation.Apply(GetIRContext(), GetTransformationContext());
*GetTransformations()->add_transformation() = transformation.ToMessage(); *GetTransformations()->add_transformation() = transformation.ToMessage();
} }
} }

View File

@ -23,7 +23,8 @@ namespace fuzz {
// A fuzzer pass for merging blocks in the module. // A fuzzer pass for merging blocks in the module.
class FuzzerPassMergeBlocks : public FuzzerPass { class FuzzerPassMergeBlocks : public FuzzerPass {
public: public:
FuzzerPassMergeBlocks(opt::IRContext* ir_context, FactManager* fact_manager, FuzzerPassMergeBlocks(opt::IRContext* ir_context,
TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -25,10 +25,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassObfuscateConstants::FuzzerPassObfuscateConstants( FuzzerPassObfuscateConstants::FuzzerPassObfuscateConstants(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassObfuscateConstants::~FuzzerPassObfuscateConstants() = default; FuzzerPassObfuscateConstants::~FuzzerPassObfuscateConstants() = default;
@ -83,12 +84,13 @@ void FuzzerPassObfuscateConstants::ObfuscateBoolConstantViaConstantPair(
bool_constant_use, lhs_id, rhs_id, comparison_opcode, bool_constant_use, lhs_id, rhs_id, comparison_opcode,
GetFuzzerContext()->GetFreshId()); GetFuzzerContext()->GetFreshId());
// The transformation should be applicable by construction. // The transformation should be applicable by construction.
assert(transformation.IsApplicable(GetIRContext(), *GetFactManager())); assert(
transformation.IsApplicable(GetIRContext(), *GetTransformationContext()));
// Applying this transformation yields a pointer to the new instruction that // Applying this transformation yields a pointer to the new instruction that
// computes the result of the binary expression. // computes the result of the binary expression.
auto binary_operator_instruction = auto binary_operator_instruction = transformation.ApplyWithResult(
transformation.ApplyWithResult(GetIRContext(), GetFactManager()); GetIRContext(), GetTransformationContext());
// Add this transformation to the sequence of transformations that have been // Add this transformation to the sequence of transformations that have been
// applied. // applied.
@ -245,7 +247,9 @@ void FuzzerPassObfuscateConstants::ObfuscateBoolConstant(
// with uniforms of the same value. // with uniforms of the same value.
auto available_types_with_uniforms = auto available_types_with_uniforms =
GetFactManager()->GetTypesForWhichUniformValuesAreKnown(); GetTransformationContext()
->GetFactManager()
->GetTypesForWhichUniformValuesAreKnown();
if (available_types_with_uniforms.empty()) { if (available_types_with_uniforms.empty()) {
// Do not try to obfuscate if we do not have access to any uniform // Do not try to obfuscate if we do not have access to any uniform
// elements with known values. // elements with known values.
@ -254,9 +258,10 @@ void FuzzerPassObfuscateConstants::ObfuscateBoolConstant(
auto chosen_type_id = auto chosen_type_id =
available_types_with_uniforms[GetFuzzerContext()->RandomIndex( available_types_with_uniforms[GetFuzzerContext()->RandomIndex(
available_types_with_uniforms)]; available_types_with_uniforms)];
auto available_constants = auto available_constants = GetTransformationContext()
GetFactManager()->GetConstantsAvailableFromUniformsForType( ->GetFactManager()
GetIRContext(), chosen_type_id); ->GetConstantsAvailableFromUniformsForType(
GetIRContext(), chosen_type_id);
if (available_constants.size() == 1) { if (available_constants.size() == 1) {
// TODO(afd): for now we only obfuscate a boolean if there are at least // TODO(afd): for now we only obfuscate a boolean if there are at least
// two constants available from uniforms, so that we can do a // two constants available from uniforms, so that we can do a
@ -308,8 +313,11 @@ void FuzzerPassObfuscateConstants::ObfuscateScalarConstant(
// Check whether we know that any uniforms are guaranteed to be equal to the // Check whether we know that any uniforms are guaranteed to be equal to the
// scalar constant associated with |constant_use|. // scalar constant associated with |constant_use|.
auto uniform_descriptors = GetFactManager()->GetUniformDescriptorsForConstant( auto uniform_descriptors =
GetIRContext(), constant_use.id_of_interest()); GetTransformationContext()
->GetFactManager()
->GetUniformDescriptorsForConstant(GetIRContext(),
constant_use.id_of_interest());
if (uniform_descriptors.empty()) { if (uniform_descriptors.empty()) {
// No relevant uniforms, so do not obfuscate. // No relevant uniforms, so do not obfuscate.
return; return;
@ -324,8 +332,9 @@ void FuzzerPassObfuscateConstants::ObfuscateScalarConstant(
constant_use, uniform_descriptor, GetFuzzerContext()->GetFreshId(), constant_use, uniform_descriptor, GetFuzzerContext()->GetFreshId(),
GetFuzzerContext()->GetFreshId()); GetFuzzerContext()->GetFreshId());
// Transformation should be applicable by construction. // Transformation should be applicable by construction.
assert(transformation.IsApplicable(GetIRContext(), *GetFactManager())); assert(
transformation.Apply(GetIRContext(), GetFactManager()); transformation.IsApplicable(GetIRContext(), *GetTransformationContext()));
transformation.Apply(GetIRContext(), GetTransformationContext());
*GetTransformations()->add_transformation() = transformation.ToMessage(); *GetTransformations()->add_transformation() = transformation.ToMessage();
} }

View File

@ -28,7 +28,7 @@ namespace fuzz {
class FuzzerPassObfuscateConstants : public FuzzerPass { class FuzzerPassObfuscateConstants : public FuzzerPass {
public: public:
FuzzerPassObfuscateConstants( FuzzerPassObfuscateConstants(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -23,10 +23,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassOutlineFunctions::FuzzerPassOutlineFunctions( FuzzerPassOutlineFunctions::FuzzerPassOutlineFunctions(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassOutlineFunctions::~FuzzerPassOutlineFunctions() = default; FuzzerPassOutlineFunctions::~FuzzerPassOutlineFunctions() = default;
@ -88,8 +89,9 @@ void FuzzerPassOutlineFunctions::Apply() {
/*new_callee_result_id*/ GetFuzzerContext()->GetFreshId(), /*new_callee_result_id*/ GetFuzzerContext()->GetFreshId(),
/*input_id_to_fresh_id*/ std::move(input_id_to_fresh_id), /*input_id_to_fresh_id*/ std::move(input_id_to_fresh_id),
/*output_id_to_fresh_id*/ std::move(output_id_to_fresh_id)); /*output_id_to_fresh_id*/ std::move(output_id_to_fresh_id));
if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) { if (transformation.IsApplicable(GetIRContext(),
transformation.Apply(GetIRContext(), GetFactManager()); *GetTransformationContext())) {
transformation.Apply(GetIRContext(), GetTransformationContext());
*GetTransformations()->add_transformation() = transformation.ToMessage(); *GetTransformations()->add_transformation() = transformation.ToMessage();
} }
} }

View File

@ -25,7 +25,7 @@ namespace fuzz {
class FuzzerPassOutlineFunctions : public FuzzerPass { class FuzzerPassOutlineFunctions : public FuzzerPass {
public: public:
FuzzerPassOutlineFunctions( FuzzerPassOutlineFunctions(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -20,10 +20,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassPermuteBlocks::FuzzerPassPermuteBlocks( FuzzerPassPermuteBlocks::FuzzerPassPermuteBlocks(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassPermuteBlocks::~FuzzerPassPermuteBlocks() = default; FuzzerPassPermuteBlocks::~FuzzerPassPermuteBlocks() = default;
@ -66,8 +67,9 @@ void FuzzerPassPermuteBlocks::Apply() {
// down indefinitely. // down indefinitely.
while (true) { while (true) {
TransformationMoveBlockDown transformation(*id); TransformationMoveBlockDown transformation(*id);
if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) { if (transformation.IsApplicable(GetIRContext(),
transformation.Apply(GetIRContext(), GetFactManager()); *GetTransformationContext())) {
transformation.Apply(GetIRContext(), GetTransformationContext());
*GetTransformations()->add_transformation() = *GetTransformations()->add_transformation() =
transformation.ToMessage(); transformation.ToMessage();
} else { } else {

View File

@ -24,7 +24,8 @@ namespace fuzz {
// manner. // manner.
class FuzzerPassPermuteBlocks : public FuzzerPass { class FuzzerPassPermuteBlocks : public FuzzerPass {
public: public:
FuzzerPassPermuteBlocks(opt::IRContext* ir_context, FactManager* fact_manager, FuzzerPassPermuteBlocks(opt::IRContext* ir_context,
TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -25,10 +25,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassPermuteFunctionParameters::FuzzerPassPermuteFunctionParameters( FuzzerPassPermuteFunctionParameters::FuzzerPassPermuteFunctionParameters(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassPermuteFunctionParameters::~FuzzerPassPermuteFunctionParameters() = FuzzerPassPermuteFunctionParameters::~FuzzerPassPermuteFunctionParameters() =
default; default;

View File

@ -30,7 +30,7 @@ namespace fuzz {
class FuzzerPassPermuteFunctionParameters : public FuzzerPass { class FuzzerPassPermuteFunctionParameters : public FuzzerPass {
public: public:
FuzzerPassPermuteFunctionParameters( FuzzerPassPermuteFunctionParameters(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -23,10 +23,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassSplitBlocks::FuzzerPassSplitBlocks( FuzzerPassSplitBlocks::FuzzerPassSplitBlocks(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassSplitBlocks::~FuzzerPassSplitBlocks() = default; FuzzerPassSplitBlocks::~FuzzerPassSplitBlocks() = default;
@ -95,8 +96,9 @@ void FuzzerPassSplitBlocks::Apply() {
// If the position we have chosen turns out to be a valid place to split // If the position we have chosen turns out to be a valid place to split
// the block, we apply the split. Otherwise the block just doesn't get // the block, we apply the split. Otherwise the block just doesn't get
// split. // split.
if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) { if (transformation.IsApplicable(GetIRContext(),
transformation.Apply(GetIRContext(), GetFactManager()); *GetTransformationContext())) {
transformation.Apply(GetIRContext(), GetTransformationContext());
*GetTransformations()->add_transformation() = transformation.ToMessage(); *GetTransformations()->add_transformation() = transformation.ToMessage();
} }
} }

View File

@ -24,7 +24,8 @@ namespace fuzz {
// can be very useful for giving other passes a chance to apply. // can be very useful for giving other passes a chance to apply.
class FuzzerPassSplitBlocks : public FuzzerPass { class FuzzerPassSplitBlocks : public FuzzerPass {
public: public:
FuzzerPassSplitBlocks(opt::IRContext* ir_context, FactManager* fact_manager, FuzzerPassSplitBlocks(opt::IRContext* ir_context,
TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -22,10 +22,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassSwapCommutableOperands::FuzzerPassSwapCommutableOperands( FuzzerPassSwapCommutableOperands::FuzzerPassSwapCommutableOperands(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassSwapCommutableOperands::~FuzzerPassSwapCommutableOperands() = default; FuzzerPassSwapCommutableOperands::~FuzzerPassSwapCommutableOperands() = default;

View File

@ -26,7 +26,7 @@ namespace fuzz {
class FuzzerPassSwapCommutableOperands : public FuzzerPass { class FuzzerPassSwapCommutableOperands : public FuzzerPass {
public: public:
FuzzerPassSwapCommutableOperands( FuzzerPassSwapCommutableOperands(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -22,10 +22,11 @@ namespace spvtools {
namespace fuzz { namespace fuzz {
FuzzerPassToggleAccessChainInstruction::FuzzerPassToggleAccessChainInstruction( FuzzerPassToggleAccessChainInstruction::FuzzerPassToggleAccessChainInstruction(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations) protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} : FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassToggleAccessChainInstruction:: FuzzerPassToggleAccessChainInstruction::
~FuzzerPassToggleAccessChainInstruction() = default; ~FuzzerPassToggleAccessChainInstruction() = default;

View File

@ -25,7 +25,7 @@ namespace fuzz {
class FuzzerPassToggleAccessChainInstruction : public FuzzerPass { class FuzzerPassToggleAccessChainInstruction : public FuzzerPass {
public: public:
FuzzerPassToggleAccessChainInstruction( FuzzerPassToggleAccessChainInstruction(
opt::IRContext* ir_context, FactManager* fact_manager, opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context, FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations); protobufs::TransformationSequence* transformations);

View File

@ -329,11 +329,11 @@ uint32_t GetArraySize(const opt::Instruction& array_type_instruction,
return array_length_constant->GetU32(); return array_length_constant->GetU32();
} }
bool IsValid(opt::IRContext* context) { bool IsValid(opt::IRContext* context, spv_validator_options validator_options) {
std::vector<uint32_t> binary; std::vector<uint32_t> binary;
context->module()->ToBinary(&binary, false); context->module()->ToBinary(&binary, false);
SpirvTools tools(context->grammar().target_env()); SpirvTools tools(context->grammar().target_env());
return tools.Validate(binary); return tools.Validate(binary.data(), binary.size(), validator_options);
} }
std::unique_ptr<opt::IRContext> CloneIRContext(opt::IRContext* context) { std::unique_ptr<opt::IRContext> CloneIRContext(opt::IRContext* context) {

View File

@ -132,8 +132,9 @@ uint32_t GetNumberOfStructMembers(
uint32_t GetArraySize(const opt::Instruction& array_type_instruction, uint32_t GetArraySize(const opt::Instruction& array_type_instruction,
opt::IRContext* context); opt::IRContext* context);
// Returns true if and only if |context| is valid, according to the validator. // Returns true if and only if |context| is valid, according to the validator
bool IsValid(opt::IRContext* context); // instantiated with |validator_options|.
bool IsValid(opt::IRContext* context, spv_validator_options validator_options);
// Returns a clone of |context|, by writing |context| to a binary and then // Returns a clone of |context|, by writing |context| to a binary and then
// parsing it again. // parsing it again.

View File

@ -26,6 +26,7 @@
#include "source/fuzz/transformation_add_type_float.h" #include "source/fuzz/transformation_add_type_float.h"
#include "source/fuzz/transformation_add_type_int.h" #include "source/fuzz/transformation_add_type_int.h"
#include "source/fuzz/transformation_add_type_pointer.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_move_block_down.h"
#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.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_replace_constant_with_uniform.h"
@ -99,16 +100,19 @@ Replayer::ReplayerResultStatus Replayer::Run(
FactManager fact_manager; FactManager fact_manager;
fact_manager.AddFacts(impl_->consumer, initial_facts, ir_context.get()); fact_manager.AddFacts(impl_->consumer, initial_facts, ir_context.get());
TransformationContext transformation_context(&fact_manager,
impl_->validator_options);
// Consider the transformation proto messages in turn. // Consider the transformation proto messages in turn.
for (auto& message : transformation_sequence_in.transformation()) { for (auto& message : transformation_sequence_in.transformation()) {
auto transformation = Transformation::FromMessage(message); auto transformation = Transformation::FromMessage(message);
// Check whether the transformation can be applied. // Check whether the transformation can be applied.
if (transformation->IsApplicable(ir_context.get(), fact_manager)) { if (transformation->IsApplicable(ir_context.get(),
transformation_context)) {
// The transformation is applicable, so apply it, and copy it to the // The transformation is applicable, so apply it, and copy it to the
// sequence of transformations that were applied. // sequence of transformations that were applied.
transformation->Apply(ir_context.get(), &fact_manager); transformation->Apply(ir_context.get(), &transformation_context);
*transformation_sequence_out->add_transformation() = message; *transformation_sequence_out->add_transformation() = message;
if (impl_->validate_during_replay) { if (impl_->validate_during_replay) {

View File

@ -195,9 +195,9 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
} }
bool Transformation::CheckIdIsFreshAndNotUsedByThisTransformation( bool Transformation::CheckIdIsFreshAndNotUsedByThisTransformation(
uint32_t id, opt::IRContext* context, uint32_t id, opt::IRContext* ir_context,
std::set<uint32_t>* ids_used_by_this_transformation) { std::set<uint32_t>* ids_used_by_this_transformation) {
if (!fuzzerutil::IsFreshId(context, id)) { if (!fuzzerutil::IsFreshId(ir_context, id)) {
return false; return false;
} }
if (ids_used_by_this_transformation->count(id) != 0) { if (ids_used_by_this_transformation->count(id) != 0) {

View File

@ -17,8 +17,8 @@
#include <memory> #include <memory>
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
namespace spvtools { namespace spvtools {
@ -60,19 +60,22 @@ class Transformation {
public: public:
// A precondition that determines whether the transformation can be cleanly // A precondition that determines whether the transformation can be cleanly
// applied in a semantics-preserving manner to the SPIR-V module given by // applied in a semantics-preserving manner to the SPIR-V module given by
// |context|, in the presence of facts captured by |fact_manager|. // |ir_context|, in the presence of facts and other contextual information
// captured by |transformation_context|.
//
// Preconditions for individual transformations must be documented in the // Preconditions for individual transformations must be documented in the
// associated header file using precise English. The fact manager is used to // associated header file using precise English. The transformation context
// provide access to facts about the module that are known to be true, on // provides access to facts about the module that are known to be true, on
// which the precondition may depend. // which the precondition may depend.
virtual bool IsApplicable(opt::IRContext* context, virtual bool IsApplicable(
const FactManager& fact_manager) const = 0; opt::IRContext* ir_context,
const TransformationContext& transformation_context) const = 0;
// Requires that IsApplicable(context, fact_manager) holds. Applies the // Requires that IsApplicable(ir_context, *transformation_context) holds.
// transformation, mutating |context| and possibly updating |fact_manager| // Applies the transformation, mutating |ir_context| and possibly updating
// with new facts established by the transformation. // |transformation_context| with new facts established by the transformation.
virtual void Apply(opt::IRContext* context, virtual void Apply(opt::IRContext* ir_context,
FactManager* fact_manager) const = 0; TransformationContext* transformation_context) const = 0;
// Turns the transformation into a protobuf message for serialization. // Turns the transformation into a protobuf message for serialization.
virtual protobufs::Transformation ToMessage() const = 0; virtual protobufs::Transformation ToMessage() const = 0;
@ -90,7 +93,7 @@ class Transformation {
// checking id freshness for a transformation that uses many ids, all of which // checking id freshness for a transformation that uses many ids, all of which
// must be distinct. // must be distinct.
static bool CheckIdIsFreshAndNotUsedByThisTransformation( static bool CheckIdIsFreshAndNotUsedByThisTransformation(
uint32_t id, opt::IRContext* context, uint32_t id, opt::IRContext* ir_context,
std::set<uint32_t>* ids_used_by_this_transformation); std::set<uint32_t>* ids_used_by_this_transformation);
}; };

View File

@ -40,19 +40,18 @@ TransformationAccessChain::TransformationAccessChain(
} }
bool TransformationAccessChain::IsApplicable( bool TransformationAccessChain::IsApplicable(
opt::IRContext* context, opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
const spvtools::fuzz::FactManager& /*unused*/) const {
// The result id must be fresh // The result id must be fresh
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
return false; return false;
} }
// The pointer id must exist and have a type. // The pointer id must exist and have a type.
auto pointer = context->get_def_use_mgr()->GetDef(message_.pointer_id()); auto pointer = ir_context->get_def_use_mgr()->GetDef(message_.pointer_id());
if (!pointer || !pointer->type_id()) { if (!pointer || !pointer->type_id()) {
return false; return false;
} }
// The type must indeed be a pointer // The type must indeed be a pointer
auto pointer_type = context->get_def_use_mgr()->GetDef(pointer->type_id()); auto pointer_type = ir_context->get_def_use_mgr()->GetDef(pointer->type_id());
if (pointer_type->opcode() != SpvOpTypePointer) { if (pointer_type->opcode() != SpvOpTypePointer) {
return false; return false;
} }
@ -60,7 +59,7 @@ bool TransformationAccessChain::IsApplicable(
// The described instruction to insert before must exist and be a suitable // The described instruction to insert before must exist and be a suitable
// point where an OpAccessChain instruction could be inserted. // point where an OpAccessChain instruction could be inserted.
auto instruction_to_insert_before = auto instruction_to_insert_before =
FindInstruction(message_.instruction_to_insert_before(), context); FindInstruction(message_.instruction_to_insert_before(), ir_context);
if (!instruction_to_insert_before) { if (!instruction_to_insert_before) {
return false; return false;
} }
@ -86,7 +85,7 @@ bool TransformationAccessChain::IsApplicable(
// The pointer on which the access chain is to be based needs to be available // The pointer on which the access chain is to be based needs to be available
// (according to dominance rules) at the insertion point. // (according to dominance rules) at the insertion point.
if (!fuzzerutil::IdIsAvailableBeforeInstruction( if (!fuzzerutil::IdIsAvailableBeforeInstruction(
context, instruction_to_insert_before, message_.pointer_id())) { ir_context, instruction_to_insert_before, message_.pointer_id())) {
return false; return false;
} }
@ -104,7 +103,7 @@ bool TransformationAccessChain::IsApplicable(
// integer. Otherwise, the integer with which the id is associated is the // integer. Otherwise, the integer with which the id is associated is the
// second component. // second component.
std::pair<bool, uint32_t> maybe_index_value = std::pair<bool, uint32_t> maybe_index_value =
GetIndexValue(context, index_id); GetIndexValue(ir_context, index_id);
if (!maybe_index_value.first) { if (!maybe_index_value.first) {
// There was no integer: this index is no good. // There was no integer: this index is no good.
return false; return false;
@ -113,7 +112,7 @@ bool TransformationAccessChain::IsApplicable(
// type is not a composite or the index is out of bounds, and the id of // type is not a composite or the index is out of bounds, and the id of
// the next type otherwise. // the next type otherwise.
subobject_type_id = fuzzerutil::WalkOneCompositeTypeIndex( subobject_type_id = fuzzerutil::WalkOneCompositeTypeIndex(
context, subobject_type_id, maybe_index_value.second); ir_context, subobject_type_id, maybe_index_value.second);
if (!subobject_type_id) { if (!subobject_type_id) {
// Either the type was not a composite (so that too many indices were // Either the type was not a composite (so that too many indices were
// provided), or the index was out of bounds. // provided), or the index was out of bounds.
@ -128,13 +127,14 @@ bool TransformationAccessChain::IsApplicable(
// We do not use the type manager to look up this type, due to problems // We do not use the type manager to look up this type, due to problems
// associated with pointers to isomorphic structs being regarded as the same. // associated with pointers to isomorphic structs being regarded as the same.
return fuzzerutil::MaybeGetPointerType( return fuzzerutil::MaybeGetPointerType(
context, subobject_type_id, ir_context, subobject_type_id,
static_cast<SpvStorageClass>( static_cast<SpvStorageClass>(
pointer_type->GetSingleWordInOperand(0))) != 0; pointer_type->GetSingleWordInOperand(0))) != 0;
} }
void TransformationAccessChain::Apply( void TransformationAccessChain::Apply(
opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const { opt::IRContext* ir_context,
TransformationContext* transformation_context) const {
// The operands to the access chain are the pointer followed by the indices. // The operands to the access chain are the pointer followed by the indices.
// The result type of the access chain is determined by where the indices // The result type of the access chain is determined by where the indices
// lead. We thus push the pointer to a sequence of operands, and then follow // lead. We thus push the pointer to a sequence of operands, and then follow
@ -148,8 +148,8 @@ void TransformationAccessChain::Apply(
operands.push_back({SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}); operands.push_back({SPV_OPERAND_TYPE_ID, {message_.pointer_id()}});
// Start walking the indices, starting with the pointer's base type. // Start walking the indices, starting with the pointer's base type.
auto pointer_type = context->get_def_use_mgr()->GetDef( auto pointer_type = ir_context->get_def_use_mgr()->GetDef(
context->get_def_use_mgr()->GetDef(message_.pointer_id())->type_id()); ir_context->get_def_use_mgr()->GetDef(message_.pointer_id())->type_id());
uint32_t subobject_type_id = pointer_type->GetSingleWordInOperand(1); uint32_t subobject_type_id = pointer_type->GetSingleWordInOperand(1);
// Go through the index ids in turn. // Go through the index ids in turn.
@ -157,33 +157,35 @@ void TransformationAccessChain::Apply(
// Add the index id to the operands. // Add the index id to the operands.
operands.push_back({SPV_OPERAND_TYPE_ID, {index_id}}); operands.push_back({SPV_OPERAND_TYPE_ID, {index_id}});
// Get the integer value associated with the index id. // Get the integer value associated with the index id.
uint32_t index_value = GetIndexValue(context, index_id).second; uint32_t index_value = GetIndexValue(ir_context, index_id).second;
// Walk to the next type in the composite object using this index. // Walk to the next type in the composite object using this index.
subobject_type_id = fuzzerutil::WalkOneCompositeTypeIndex( subobject_type_id = fuzzerutil::WalkOneCompositeTypeIndex(
context, subobject_type_id, index_value); ir_context, subobject_type_id, index_value);
} }
// The access chain's result type is a pointer to the composite component that // The access chain's result type is a pointer to the composite component that
// was reached after following all indices. The storage class is that of the // was reached after following all indices. The storage class is that of the
// original pointer. // original pointer.
uint32_t result_type = fuzzerutil::MaybeGetPointerType( uint32_t result_type = fuzzerutil::MaybeGetPointerType(
context, subobject_type_id, ir_context, subobject_type_id,
static_cast<SpvStorageClass>(pointer_type->GetSingleWordInOperand(0))); static_cast<SpvStorageClass>(pointer_type->GetSingleWordInOperand(0)));
// Add the access chain instruction to the module, and update the module's id // Add the access chain instruction to the module, and update the module's id
// bound. // bound.
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
FindInstruction(message_.instruction_to_insert_before(), context) FindInstruction(message_.instruction_to_insert_before(), ir_context)
->InsertBefore( ->InsertBefore(MakeUnique<opt::Instruction>(
MakeUnique<opt::Instruction>(context, SpvOpAccessChain, result_type, ir_context, SpvOpAccessChain, result_type, message_.fresh_id(),
message_.fresh_id(), operands)); operands));
// Conservatively invalidate all analyses. // Conservatively invalidate all analyses.
context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
// If the base pointer's pointee value was irrelevant, the same is true of the // If the base pointer's pointee value was irrelevant, the same is true of the
// pointee value of the result of this access chain. // pointee value of the result of this access chain.
if (fact_manager->PointeeValueIsIrrelevant(message_.pointer_id())) { if (transformation_context->GetFactManager()->PointeeValueIsIrrelevant(
fact_manager->AddFactValueOfPointeeIsIrrelevant(message_.fresh_id()); message_.pointer_id())) {
transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
message_.fresh_id());
} }
} }
@ -194,8 +196,8 @@ protobufs::Transformation TransformationAccessChain::ToMessage() const {
} }
std::pair<bool, uint32_t> TransformationAccessChain::GetIndexValue( std::pair<bool, uint32_t> TransformationAccessChain::GetIndexValue(
opt::IRContext* context, uint32_t index_id) const { opt::IRContext* ir_context, uint32_t index_id) const {
auto index_instruction = context->get_def_use_mgr()->GetDef(index_id); auto index_instruction = ir_context->get_def_use_mgr()->GetDef(index_id);
if (!index_instruction || !spvOpcodeIsConstant(index_instruction->opcode())) { if (!index_instruction || !spvOpcodeIsConstant(index_instruction->opcode())) {
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3179) We could // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3179) We could
// allow non-constant indices when looking up non-structs, using clamping // allow non-constant indices when looking up non-structs, using clamping
@ -203,7 +205,7 @@ std::pair<bool, uint32_t> TransformationAccessChain::GetIndexValue(
return {false, 0}; return {false, 0};
} }
auto index_type = auto index_type =
context->get_def_use_mgr()->GetDef(index_instruction->type_id()); ir_context->get_def_use_mgr()->GetDef(index_instruction->type_id());
if (index_type->opcode() != SpvOpTypeInt || if (index_type->opcode() != SpvOpTypeInt ||
index_type->GetSingleWordInOperand(0) != 32) { index_type->GetSingleWordInOperand(0) != 32) {
return {false, 0}; return {false, 0};

View File

@ -17,9 +17,9 @@
#include <utility> #include <utility>
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h" #include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
namespace spvtools { namespace spvtools {
@ -47,8 +47,9 @@ class TransformationAccessChain : public Transformation {
// - If type t is the final type reached by walking these indices, the module // - If type t is the final type reached by walking these indices, the module
// must include an instruction "OpTypePointer SC %t" where SC is the storage // must include an instruction "OpTypePointer SC %t" where SC is the storage
// class associated with |message_.pointer_id| // class associated with |message_.pointer_id|
bool IsApplicable(opt::IRContext* context, bool IsApplicable(
const FactManager& fact_manager) const override; opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Adds an instruction of the form: // Adds an instruction of the form:
// |message_.fresh_id| = OpAccessChain %ptr |message_.index_id| // |message_.fresh_id| = OpAccessChain %ptr |message_.index_id|
@ -57,10 +58,12 @@ class TransformationAccessChain : public Transformation {
// the indices in |message_.index_id|, and with the same storage class as // the indices in |message_.index_id|, and with the same storage class as
// |message_.pointer_id|. // |message_.pointer_id|.
// //
// If |fact_manager| reports that |message_.pointer_id| has an irrelevant // If the fact manager in |transformation_context| reports that
// pointee value, then the fact that |message_.fresh_id| (the result of the // |message_.pointer_id| has an irrelevant pointee value, then the fact that
// access chain) also has an irrelevant pointee value is also recorded. // |message_.fresh_id| (the result of the access chain) also has an irrelevant
void Apply(opt::IRContext* context, FactManager* fact_manager) const override; // pointee value is also recorded.
void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
protobufs::Transformation ToMessage() const override; protobufs::Transformation ToMessage() const override;
@ -68,7 +71,7 @@ class TransformationAccessChain : public Transformation {
// Returns {false, 0} if |index_id| does not correspond to a 32-bit integer // Returns {false, 0} if |index_id| does not correspond to a 32-bit integer
// constant. Otherwise, returns {true, value}, where value is the value of // constant. Otherwise, returns {true, value}, where value is the value of
// the 32-bit integer constant to which |index_id| corresponds. // the 32-bit integer constant to which |index_id| corresponds.
std::pair<bool, uint32_t> GetIndexValue(opt::IRContext* context, std::pair<bool, uint32_t> GetIndexValue(opt::IRContext* ir_context,
uint32_t index_id) const; uint32_t index_id) const;
protobufs::TransformationAccessChain message_; protobufs::TransformationAccessChain message_;

View File

@ -31,27 +31,28 @@ TransformationAddConstantBoolean::TransformationAddConstantBoolean(
} }
bool TransformationAddConstantBoolean::IsApplicable( bool TransformationAddConstantBoolean::IsApplicable(
opt::IRContext* context, const FactManager& /*unused*/) const { opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
opt::analysis::Bool bool_type; opt::analysis::Bool bool_type;
if (!context->get_type_mgr()->GetId(&bool_type)) { if (!ir_context->get_type_mgr()->GetId(&bool_type)) {
// No OpTypeBool is present. // No OpTypeBool is present.
return false; return false;
} }
return fuzzerutil::IsFreshId(context, message_.fresh_id()); return fuzzerutil::IsFreshId(ir_context, message_.fresh_id());
} }
void TransformationAddConstantBoolean::Apply(opt::IRContext* context, void TransformationAddConstantBoolean::Apply(
FactManager* /*unused*/) const { opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
opt::analysis::Bool bool_type; opt::analysis::Bool bool_type;
// Add the boolean constant to the module, ensuring the module's id bound is // Add the boolean constant to the module, ensuring the module's id bound is
// high enough. // high enough.
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
context->module()->AddGlobalValue( ir_context->module()->AddGlobalValue(
message_.is_true() ? SpvOpConstantTrue : SpvOpConstantFalse, message_.is_true() ? SpvOpConstantTrue : SpvOpConstantFalse,
message_.fresh_id(), context->get_type_mgr()->GetId(&bool_type)); message_.fresh_id(), ir_context->get_type_mgr()->GetId(&bool_type));
// We have added an instruction to the module, so need to be careful about the // We have added an instruction to the module, so need to be careful about the
// validity of existing analyses. // validity of existing analyses.
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
} }
protobufs::Transformation TransformationAddConstantBoolean::ToMessage() const { protobufs::Transformation TransformationAddConstantBoolean::ToMessage() const {

View File

@ -15,9 +15,9 @@
#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_BOOLEAN_CONSTANT_H_ #ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_BOOLEAN_CONSTANT_H_
#define SOURCE_FUZZ_TRANSFORMATION_ADD_BOOLEAN_CONSTANT_H_ #define SOURCE_FUZZ_TRANSFORMATION_ADD_BOOLEAN_CONSTANT_H_
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h" #include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
namespace spvtools { namespace spvtools {
@ -32,12 +32,14 @@ class TransformationAddConstantBoolean : public Transformation {
// - |message_.fresh_id| must not be used by the module. // - |message_.fresh_id| must not be used by the module.
// - The module must already contain OpTypeBool. // - The module must already contain OpTypeBool.
bool IsApplicable(opt::IRContext* context, bool IsApplicable(
const FactManager& fact_manager) const override; opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// - Adds OpConstantTrue (OpConstantFalse) to the module with id // - Adds OpConstantTrue (OpConstantFalse) to the module with id
// |message_.fresh_id| if |message_.is_true| holds (does not hold). // |message_.fresh_id| if |message_.is_true| holds (does not hold).
void Apply(opt::IRContext* context, FactManager* fact_manager) const override; void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
protobufs::Transformation ToMessage() const override; protobufs::Transformation ToMessage() const override;

View File

@ -37,15 +37,14 @@ TransformationAddConstantComposite::TransformationAddConstantComposite(
} }
bool TransformationAddConstantComposite::IsApplicable( bool TransformationAddConstantComposite::IsApplicable(
opt::IRContext* context, opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
const spvtools::fuzz::FactManager& /*unused*/) const {
// Check that the given id is fresh. // Check that the given id is fresh.
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
return false; return false;
} }
// Check that the composite type id is an instruction id. // Check that the composite type id is an instruction id.
auto composite_type_instruction = auto composite_type_instruction =
context->get_def_use_mgr()->GetDef(message_.type_id()); ir_context->get_def_use_mgr()->GetDef(message_.type_id());
if (!composite_type_instruction) { if (!composite_type_instruction) {
return false; return false;
} }
@ -56,7 +55,7 @@ bool TransformationAddConstantComposite::IsApplicable(
case SpvOpTypeArray: case SpvOpTypeArray:
for (uint32_t index = 0; for (uint32_t index = 0;
index < index <
fuzzerutil::GetArraySize(*composite_type_instruction, context); fuzzerutil::GetArraySize(*composite_type_instruction, ir_context);
index++) { index++) {
constituent_type_ids.push_back( constituent_type_ids.push_back(
composite_type_instruction->GetSingleWordInOperand(0)); composite_type_instruction->GetSingleWordInOperand(0));
@ -93,7 +92,7 @@ bool TransformationAddConstantComposite::IsApplicable(
// corresponding constituent type. // corresponding constituent type.
for (uint32_t index = 0; index < constituent_type_ids.size(); index++) { for (uint32_t index = 0; index < constituent_type_ids.size(); index++) {
auto constituent_instruction = auto constituent_instruction =
context->get_def_use_mgr()->GetDef(message_.constituent_id(index)); ir_context->get_def_use_mgr()->GetDef(message_.constituent_id(index));
if (!constituent_instruction) { if (!constituent_instruction) {
return false; return false;
} }
@ -105,18 +104,19 @@ bool TransformationAddConstantComposite::IsApplicable(
} }
void TransformationAddConstantComposite::Apply( void TransformationAddConstantComposite::Apply(
opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
opt::Instruction::OperandList in_operands; opt::Instruction::OperandList in_operands;
for (auto constituent_id : message_.constituent_id()) { for (auto constituent_id : message_.constituent_id()) {
in_operands.push_back({SPV_OPERAND_TYPE_ID, {constituent_id}}); in_operands.push_back({SPV_OPERAND_TYPE_ID, {constituent_id}});
} }
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>( ir_context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
context, SpvOpConstantComposite, message_.type_id(), message_.fresh_id(), ir_context, SpvOpConstantComposite, message_.type_id(),
in_operands)); message_.fresh_id(), in_operands));
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
// We have added an instruction to the module, so need to be careful about the // We have added an instruction to the module, so need to be careful about the
// validity of existing analyses. // validity of existing analyses.
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
} }
protobufs::Transformation TransformationAddConstantComposite::ToMessage() protobufs::Transformation TransformationAddConstantComposite::ToMessage()

View File

@ -17,9 +17,9 @@
#include <vector> #include <vector>
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h" #include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
namespace spvtools { namespace spvtools {
@ -38,13 +38,15 @@ class TransformationAddConstantComposite : public Transformation {
// - |message_.type_id| must be the id of a composite type // - |message_.type_id| must be the id of a composite type
// - |message_.constituent_id| must refer to ids that match the constituent // - |message_.constituent_id| must refer to ids that match the constituent
// types of this composite type // types of this composite type
bool IsApplicable(opt::IRContext* context, bool IsApplicable(
const FactManager& fact_manager) const override; opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Adds an OpConstantComposite instruction defining a constant of type // Adds an OpConstantComposite instruction defining a constant of type
// |message_.type_id|, using |message_.constituent_id| as constituents, with // |message_.type_id|, using |message_.constituent_id| as constituents, with
// result id |message_.fresh_id|. // result id |message_.fresh_id|.
void Apply(opt::IRContext* context, FactManager* fact_manager) const override; void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
protobufs::Transformation ToMessage() const override; protobufs::Transformation ToMessage() const override;

View File

@ -33,14 +33,13 @@ TransformationAddConstantScalar::TransformationAddConstantScalar(
} }
bool TransformationAddConstantScalar::IsApplicable( bool TransformationAddConstantScalar::IsApplicable(
opt::IRContext* context, opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
const spvtools::fuzz::FactManager& /*unused*/) const {
// The id needs to be fresh. // The id needs to be fresh.
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
return false; return false;
} }
// The type id for the scalar must exist and be a type. // The type id for the scalar must exist and be a type.
auto type = context->get_type_mgr()->GetType(message_.type_id()); auto type = ir_context->get_type_mgr()->GetType(message_.type_id());
if (!type) { if (!type) {
return false; return false;
} }
@ -61,20 +60,21 @@ bool TransformationAddConstantScalar::IsApplicable(
} }
void TransformationAddConstantScalar::Apply( void TransformationAddConstantScalar::Apply(
opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
opt::Instruction::OperandList operand_list; opt::Instruction::OperandList operand_list;
for (auto word : message_.word()) { for (auto word : message_.word()) {
operand_list.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {word}}); operand_list.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {word}});
} }
context->module()->AddGlobalValue( ir_context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
MakeUnique<opt::Instruction>(context, SpvOpConstant, message_.type_id(), ir_context, SpvOpConstant, message_.type_id(), message_.fresh_id(),
message_.fresh_id(), operand_list)); operand_list));
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
// We have added an instruction to the module, so need to be careful about the // We have added an instruction to the module, so need to be careful about the
// validity of existing analyses. // validity of existing analyses.
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
} }
protobufs::Transformation TransformationAddConstantScalar::ToMessage() const { protobufs::Transformation TransformationAddConstantScalar::ToMessage() const {

View File

@ -17,9 +17,9 @@
#include <vector> #include <vector>
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h" #include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
namespace spvtools { namespace spvtools {
@ -37,11 +37,13 @@ class TransformationAddConstantScalar : public Transformation {
// - |message_.type_id| must be the id of a floating-point or integer type // - |message_.type_id| must be the id of a floating-point or integer type
// - The size of |message_.word| must be compatible with the width of this // - The size of |message_.word| must be compatible with the width of this
// type // type
bool IsApplicable(opt::IRContext* context, bool IsApplicable(
const FactManager& fact_manager) const override; opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Adds a new OpConstant instruction with the given type and words. // Adds a new OpConstant instruction with the given type and words.
void Apply(opt::IRContext* context, FactManager* fact_manager) const override; void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
protobufs::Transformation ToMessage() const override; protobufs::Transformation ToMessage() const override;

View File

@ -32,16 +32,15 @@ TransformationAddDeadBlock::TransformationAddDeadBlock(uint32_t fresh_id,
} }
bool TransformationAddDeadBlock::IsApplicable( bool TransformationAddDeadBlock::IsApplicable(
opt::IRContext* context, opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
const spvtools::fuzz::FactManager& /*unused*/) const {
// The new block's id must be fresh. // The new block's id must be fresh.
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
return false; return false;
} }
// First, we check that a constant with the same value as // First, we check that a constant with the same value as
// |message_.condition_value| is present. // |message_.condition_value| is present.
if (!fuzzerutil::MaybeGetBoolConstantId(context, if (!fuzzerutil::MaybeGetBoolConstantId(ir_context,
message_.condition_value())) { message_.condition_value())) {
// The required constant is not present, so the transformation cannot be // The required constant is not present, so the transformation cannot be
// applied. // applied.
@ -50,7 +49,7 @@ bool TransformationAddDeadBlock::IsApplicable(
// The existing block must indeed exist. // The existing block must indeed exist.
auto existing_block = auto existing_block =
fuzzerutil::MaybeFindBlock(context, message_.existing_block()); fuzzerutil::MaybeFindBlock(ir_context, message_.existing_block());
if (!existing_block) { if (!existing_block) {
return false; return false;
} }
@ -68,13 +67,13 @@ bool TransformationAddDeadBlock::IsApplicable(
// Its successor must not be a merge block nor continue target. // Its successor must not be a merge block nor continue target.
auto successor_block_id = auto successor_block_id =
existing_block->terminator()->GetSingleWordInOperand(0); existing_block->terminator()->GetSingleWordInOperand(0);
if (fuzzerutil::IsMergeOrContinue(context, successor_block_id)) { if (fuzzerutil::IsMergeOrContinue(ir_context, successor_block_id)) {
return false; return false;
} }
// The successor must not be a loop header (i.e., |message_.existing_block| // The successor must not be a loop header (i.e., |message_.existing_block|
// must not be a back-edge block. // must not be a back-edge block.
if (context->cfg()->block(successor_block_id)->IsLoopHeader()) { if (ir_context->cfg()->block(successor_block_id)->IsLoopHeader()) {
return false; return false;
} }
@ -82,34 +81,36 @@ bool TransformationAddDeadBlock::IsApplicable(
} }
void TransformationAddDeadBlock::Apply( void TransformationAddDeadBlock::Apply(
opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const { opt::IRContext* ir_context,
TransformationContext* transformation_context) const {
// Update the module id bound so that it is at least the id of the new block. // Update the module id bound so that it is at least the id of the new block.
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
// Get the existing block and its successor. // Get the existing block and its successor.
auto existing_block = context->cfg()->block(message_.existing_block()); auto existing_block = ir_context->cfg()->block(message_.existing_block());
auto successor_block_id = auto successor_block_id =
existing_block->terminator()->GetSingleWordInOperand(0); existing_block->terminator()->GetSingleWordInOperand(0);
// Get the id of the boolean value that will be used as the branch condition. // Get the id of the boolean value that will be used as the branch condition.
auto bool_id = auto bool_id = fuzzerutil::MaybeGetBoolConstantId(ir_context,
fuzzerutil::MaybeGetBoolConstantId(context, message_.condition_value()); message_.condition_value());
// Make a new block that unconditionally branches to the original successor // Make a new block that unconditionally branches to the original successor
// block. // block.
auto enclosing_function = existing_block->GetParent(); auto enclosing_function = existing_block->GetParent();
std::unique_ptr<opt::BasicBlock> new_block = MakeUnique<opt::BasicBlock>( std::unique_ptr<opt::BasicBlock> new_block =
MakeUnique<opt::Instruction>(context, SpvOpLabel, 0, message_.fresh_id(), MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
opt::Instruction::OperandList())); ir_context, SpvOpLabel, 0, message_.fresh_id(),
opt::Instruction::OperandList()));
new_block->AddInstruction(MakeUnique<opt::Instruction>( new_block->AddInstruction(MakeUnique<opt::Instruction>(
context, SpvOpBranch, 0, 0, ir_context, SpvOpBranch, 0, 0,
opt::Instruction::OperandList( opt::Instruction::OperandList(
{{SPV_OPERAND_TYPE_ID, {successor_block_id}}}))); {{SPV_OPERAND_TYPE_ID, {successor_block_id}}})));
// Turn the original block into a selection merge, with its original successor // Turn the original block into a selection merge, with its original successor
// as the merge block. // as the merge block.
existing_block->terminator()->InsertBefore(MakeUnique<opt::Instruction>( existing_block->terminator()->InsertBefore(MakeUnique<opt::Instruction>(
context, SpvOpSelectionMerge, 0, 0, ir_context, SpvOpSelectionMerge, 0, 0,
opt::Instruction::OperandList( opt::Instruction::OperandList(
{{SPV_OPERAND_TYPE_ID, {successor_block_id}}, {{SPV_OPERAND_TYPE_ID, {successor_block_id}},
{SPV_OPERAND_TYPE_SELECTION_CONTROL, {SPV_OPERAND_TYPE_SELECTION_CONTROL,
@ -135,7 +136,8 @@ void TransformationAddDeadBlock::Apply(
existing_block); existing_block);
// Record the fact that the new block is dead. // Record the fact that the new block is dead.
fact_manager->AddFactBlockIsDead(message_.fresh_id()); transformation_context->GetFactManager()->AddFactBlockIsDead(
message_.fresh_id());
// Fix up OpPhi instructions in the successor block, so that the values they // 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 // yield when control has transferred from the new block are the same as if
@ -143,7 +145,7 @@ void TransformationAddDeadBlock::Apply(
// to be valid since |message_.existing_block| dominates the new block by // to be valid since |message_.existing_block| dominates the new block by
// construction. Other transformations can change these phi operands to more // construction. Other transformations can change these phi operands to more
// interesting values. // interesting values.
context->cfg() ir_context->cfg()
->block(successor_block_id) ->block(successor_block_id)
->ForEachPhiInst([this](opt::Instruction* phi_inst) { ->ForEachPhiInst([this](opt::Instruction* phi_inst) {
// Copy the operand that provides the phi value for the first of any // Copy the operand that provides the phi value for the first of any
@ -156,7 +158,7 @@ void TransformationAddDeadBlock::Apply(
// Do not rely on any existing analysis results since the control flow graph // Do not rely on any existing analysis results since the control flow graph
// of the module has changed. // of the module has changed.
context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
} }
protobufs::Transformation TransformationAddDeadBlock::ToMessage() const { protobufs::Transformation TransformationAddDeadBlock::ToMessage() const {

View File

@ -15,9 +15,9 @@
#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BLOCK_H_ #ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BLOCK_H_
#define SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BLOCK_H_ #define SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BLOCK_H_
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h" #include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
namespace spvtools { namespace spvtools {
@ -41,15 +41,17 @@ class TransformationAddDeadBlock : public Transformation {
// - |message_.existing_block| must not be a back-edge block, since in this // - |message_.existing_block| must not be a back-edge block, since in this
// case the newly-added block would lead to another back-edge to the // case the newly-added block would lead to another back-edge to the
// associated loop header // associated loop header
bool IsApplicable(opt::IRContext* context, bool IsApplicable(
const FactManager& fact_manager) const override; opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Changes the OpBranch from |message_.existing_block| to its successor 's' // Changes the OpBranch from |message_.existing_block| to its successor 's'
// to an OpBranchConditional to either 's' or a new block, // to an OpBranchConditional to either 's' or a new block,
// |message_.fresh_id|, which itself unconditionally branches to 's'. The // |message_.fresh_id|, which itself unconditionally branches to 's'. The
// conditional branch uses |message.condition_value| as its condition, and is // conditional branch uses |message.condition_value| as its condition, and is
// arranged so that control will pass to 's' at runtime. // arranged so that control will pass to 's' at runtime.
void Apply(opt::IRContext* context, FactManager* fact_manager) const override; void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
protobufs::Transformation ToMessage() const override; protobufs::Transformation ToMessage() const override;

View File

@ -14,8 +14,8 @@
#include "source/fuzz/transformation_add_dead_break.h" #include "source/fuzz/transformation_add_dead_break.h"
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/fuzzer_util.h" #include "source/fuzz/fuzzer_util.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/basic_block.h" #include "source/opt/basic_block.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
#include "source/opt/struct_cfg_analysis.h" #include "source/opt/struct_cfg_analysis.h"
@ -39,7 +39,7 @@ TransformationAddDeadBreak::TransformationAddDeadBreak(
} }
bool TransformationAddDeadBreak::AddingBreakRespectsStructuredControlFlow( bool TransformationAddDeadBreak::AddingBreakRespectsStructuredControlFlow(
opt::IRContext* context, opt::BasicBlock* bb_from) const { opt::IRContext* ir_context, opt::BasicBlock* bb_from) const {
// Look at the structured control flow associated with |from_block| and // Look at the structured control flow associated with |from_block| and
// check whether it is contained in an appropriate construct with merge id // check whether it is contained in an appropriate construct with merge id
// |to_block| such that a break from |from_block| to |to_block| is legal. // |to_block| such that a break from |from_block| to |to_block| is legal.
@ -70,7 +70,7 @@ bool TransformationAddDeadBreak::AddingBreakRespectsStructuredControlFlow(
// structured control flow construct. // structured control flow construct.
auto containing_construct = auto containing_construct =
context->GetStructuredCFGAnalysis()->ContainingConstruct( ir_context->GetStructuredCFGAnalysis()->ContainingConstruct(
message_.from_block()); message_.from_block());
if (!containing_construct) { if (!containing_construct) {
// |from_block| is not in a construct from which we can break. // |from_block| is not in a construct from which we can break.
@ -79,7 +79,7 @@ bool TransformationAddDeadBreak::AddingBreakRespectsStructuredControlFlow(
// Consider case (2) // Consider case (2)
if (message_.to_block() == if (message_.to_block() ==
context->cfg()->block(containing_construct)->MergeBlockId()) { ir_context->cfg()->block(containing_construct)->MergeBlockId()) {
// This looks like an instance of case (2). // This looks like an instance of case (2).
// However, the structured CFG analysis regards the continue construct of a // However, the structured CFG analysis regards the continue construct of a
// loop as part of the loop, but it is not legal to jump from a loop's // loop as part of the loop, but it is not legal to jump from a loop's
@ -90,28 +90,29 @@ bool TransformationAddDeadBreak::AddingBreakRespectsStructuredControlFlow(
// currently allow a dead break from a back edge block, but we could and // currently allow a dead break from a back edge block, but we could and
// ultimately should. // ultimately should.
return !fuzzerutil::BlockIsInLoopContinueConstruct( return !fuzzerutil::BlockIsInLoopContinueConstruct(
context, message_.from_block(), containing_construct); ir_context, message_.from_block(), containing_construct);
} }
// Case (3) holds if and only if |to_block| is the merge block for this // Case (3) holds if and only if |to_block| is the merge block for this
// innermost loop that contains |from_block| // innermost loop that contains |from_block|
auto containing_loop_header = auto containing_loop_header =
context->GetStructuredCFGAnalysis()->ContainingLoop( ir_context->GetStructuredCFGAnalysis()->ContainingLoop(
message_.from_block()); message_.from_block());
if (containing_loop_header && if (containing_loop_header &&
message_.to_block() == message_.to_block() ==
context->cfg()->block(containing_loop_header)->MergeBlockId()) { ir_context->cfg()->block(containing_loop_header)->MergeBlockId()) {
return !fuzzerutil::BlockIsInLoopContinueConstruct( return !fuzzerutil::BlockIsInLoopContinueConstruct(
context, message_.from_block(), containing_loop_header); ir_context, message_.from_block(), containing_loop_header);
} }
return false; return false;
} }
bool TransformationAddDeadBreak::IsApplicable( bool TransformationAddDeadBreak::IsApplicable(
opt::IRContext* context, const FactManager& /*unused*/) const { opt::IRContext* ir_context,
const TransformationContext& transformation_context) const {
// First, we check that a constant with the same value as // First, we check that a constant with the same value as
// |message_.break_condition_value| is present. // |message_.break_condition_value| is present.
if (!fuzzerutil::MaybeGetBoolConstantId(context, if (!fuzzerutil::MaybeGetBoolConstantId(ir_context,
message_.break_condition_value())) { message_.break_condition_value())) {
// The required constant is not present, so the transformation cannot be // The required constant is not present, so the transformation cannot be
// applied. // applied.
@ -121,17 +122,17 @@ bool TransformationAddDeadBreak::IsApplicable(
// Check that |message_.from_block| and |message_.to_block| really are block // Check that |message_.from_block| and |message_.to_block| really are block
// ids // ids
opt::BasicBlock* bb_from = opt::BasicBlock* bb_from =
fuzzerutil::MaybeFindBlock(context, message_.from_block()); fuzzerutil::MaybeFindBlock(ir_context, message_.from_block());
if (bb_from == nullptr) { if (bb_from == nullptr) {
return false; return false;
} }
opt::BasicBlock* bb_to = opt::BasicBlock* bb_to =
fuzzerutil::MaybeFindBlock(context, message_.to_block()); fuzzerutil::MaybeFindBlock(ir_context, message_.to_block());
if (bb_to == nullptr) { if (bb_to == nullptr) {
return false; return false;
} }
if (!fuzzerutil::BlockIsReachableInItsFunction(context, bb_to)) { if (!fuzzerutil::BlockIsReachableInItsFunction(ir_context, bb_to)) {
// If the target of the break is unreachable, we conservatively do not // If the target of the break is unreachable, we conservatively do not
// allow adding a dead break, to avoid the compilations that arise due to // allow adding a dead break, to avoid the compilations that arise due to
// the lack of sensible dominance information for unreachable blocks. // the lack of sensible dominance information for unreachable blocks.
@ -157,14 +158,14 @@ bool TransformationAddDeadBreak::IsApplicable(
"The id of the block we found should match the target id for the break."); "The id of the block we found should match the target id for the break.");
// Check whether the data passed to extend OpPhi instructions is appropriate. // Check whether the data passed to extend OpPhi instructions is appropriate.
if (!fuzzerutil::PhiIdsOkForNewEdge(context, bb_from, bb_to, if (!fuzzerutil::PhiIdsOkForNewEdge(ir_context, bb_from, bb_to,
message_.phi_id())) { message_.phi_id())) {
return false; return false;
} }
// Check that adding the break would respect the rules of structured // Check that adding the break would respect the rules of structured
// control flow. // control flow.
if (!AddingBreakRespectsStructuredControlFlow(context, bb_from)) { if (!AddingBreakRespectsStructuredControlFlow(ir_context, bb_from)) {
return false; return false;
} }
@ -177,16 +178,18 @@ bool TransformationAddDeadBreak::IsApplicable(
// being places on the validator. This should be revisited if we are sure // being places on the validator. This should be revisited if we are sure
// the validator is complete with respect to checking structured control flow // the validator is complete with respect to checking structured control flow
// rules. // rules.
auto cloned_context = fuzzerutil::CloneIRContext(context); auto cloned_context = fuzzerutil::CloneIRContext(ir_context);
ApplyImpl(cloned_context.get()); ApplyImpl(cloned_context.get());
return fuzzerutil::IsValid(cloned_context.get()); return fuzzerutil::IsValid(cloned_context.get(),
transformation_context.GetValidatorOptions());
} }
void TransformationAddDeadBreak::Apply(opt::IRContext* context, void TransformationAddDeadBreak::Apply(
FactManager* /*unused*/) const { opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
ApplyImpl(context); ApplyImpl(ir_context);
// Invalidate all analyses // Invalidate all analyses
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
} }
protobufs::Transformation TransformationAddDeadBreak::ToMessage() const { protobufs::Transformation TransformationAddDeadBreak::ToMessage() const {
@ -196,10 +199,10 @@ protobufs::Transformation TransformationAddDeadBreak::ToMessage() const {
} }
void TransformationAddDeadBreak::ApplyImpl( void TransformationAddDeadBreak::ApplyImpl(
spvtools::opt::IRContext* context) const { spvtools::opt::IRContext* ir_context) const {
fuzzerutil::AddUnreachableEdgeAndUpdateOpPhis( fuzzerutil::AddUnreachableEdgeAndUpdateOpPhis(
context, context->cfg()->block(message_.from_block()), ir_context, ir_context->cfg()->block(message_.from_block()),
context->cfg()->block(message_.to_block()), ir_context->cfg()->block(message_.to_block()),
message_.break_condition_value(), message_.phi_id()); message_.break_condition_value(), message_.phi_id());
} }

View File

@ -17,9 +17,9 @@
#include <vector> #include <vector>
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h" #include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
namespace spvtools { namespace spvtools {
@ -50,21 +50,23 @@ class TransformationAddDeadBreak : public Transformation {
// maintain validity of the module. // maintain validity of the module.
// In particular, the new branch must not lead to violations of the rule // In particular, the new branch must not lead to violations of the rule
// that a use must be dominated by its definition. // that a use must be dominated by its definition.
bool IsApplicable(opt::IRContext* context, bool IsApplicable(
const FactManager& fact_manager) const override; opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Replaces the terminator of a with a conditional branch to b or c. // Replaces the terminator of a with a conditional branch to b or c.
// The boolean constant associated with |message_.break_condition_value| is // The boolean constant associated with |message_.break_condition_value| is
// used as the condition, and the order of b and c is arranged such that // used as the condition, and the order of b and c is arranged such that
// control is guaranteed to jump to c. // control is guaranteed to jump to c.
void Apply(opt::IRContext* context, FactManager* fact_manager) const override; void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
protobufs::Transformation ToMessage() const override; protobufs::Transformation ToMessage() const override;
private: private:
// Returns true if and only if adding an edge from |bb_from| to // Returns true if and only if adding an edge from |bb_from| to
// |message_.to_block| respects structured control flow. // |message_.to_block| respects structured control flow.
bool AddingBreakRespectsStructuredControlFlow(opt::IRContext* context, bool AddingBreakRespectsStructuredControlFlow(opt::IRContext* ir_context,
opt::BasicBlock* bb_from) const; opt::BasicBlock* bb_from) const;
// Used by 'Apply' to actually apply the transformation to the module of // Used by 'Apply' to actually apply the transformation to the module of
@ -73,7 +75,7 @@ class TransformationAddDeadBreak : public Transformation {
// module. This is only invoked by 'IsApplicable' after certain basic // module. This is only invoked by 'IsApplicable' after certain basic
// applicability checks have been made, ensuring that the invocation of this // applicability checks have been made, ensuring that the invocation of this
// method is legal. // method is legal.
void ApplyImpl(opt::IRContext* context) const; void ApplyImpl(opt::IRContext* ir_context) const;
protobufs::TransformationAddDeadBreak message_; protobufs::TransformationAddDeadBreak message_;
}; };

View File

@ -34,11 +34,12 @@ TransformationAddDeadContinue::TransformationAddDeadContinue(
} }
bool TransformationAddDeadContinue::IsApplicable( bool TransformationAddDeadContinue::IsApplicable(
opt::IRContext* context, const FactManager& /*unused*/) const { opt::IRContext* ir_context,
const TransformationContext& transformation_context) const {
// First, we check that a constant with the same value as // First, we check that a constant with the same value as
// |message_.continue_condition_value| is present. // |message_.continue_condition_value| is present.
if (!fuzzerutil::MaybeGetBoolConstantId( if (!fuzzerutil::MaybeGetBoolConstantId(
context, message_.continue_condition_value())) { ir_context, message_.continue_condition_value())) {
// The required constant is not present, so the transformation cannot be // The required constant is not present, so the transformation cannot be
// applied. // applied.
return false; return false;
@ -46,7 +47,7 @@ bool TransformationAddDeadContinue::IsApplicable(
// Check that |message_.from_block| really is a block id. // Check that |message_.from_block| really is a block id.
opt::BasicBlock* bb_from = opt::BasicBlock* bb_from =
fuzzerutil::MaybeFindBlock(context, message_.from_block()); fuzzerutil::MaybeFindBlock(ir_context, message_.from_block());
if (bb_from == nullptr) { if (bb_from == nullptr) {
return false; return false;
} }
@ -68,31 +69,33 @@ bool TransformationAddDeadContinue::IsApplicable(
// Because the structured CFG analysis does not regard a loop header as part // Because the structured CFG analysis does not regard a loop header as part
// of the loop it heads, we check first whether bb_from is a loop header // of the loop it heads, we check first whether bb_from is a loop header
// before using the structured CFG analysis. // before using the structured CFG analysis.
auto loop_header = bb_from->IsLoopHeader() auto loop_header =
? message_.from_block() bb_from->IsLoopHeader()
: context->GetStructuredCFGAnalysis()->ContainingLoop( ? message_.from_block()
message_.from_block()); : ir_context->GetStructuredCFGAnalysis()->ContainingLoop(
message_.from_block());
if (!loop_header) { if (!loop_header) {
return false; return false;
} }
auto continue_block = context->cfg()->block(loop_header)->ContinueBlockId(); auto continue_block =
ir_context->cfg()->block(loop_header)->ContinueBlockId();
if (!fuzzerutil::BlockIsReachableInItsFunction( if (!fuzzerutil::BlockIsReachableInItsFunction(
context, context->cfg()->block(continue_block))) { ir_context, ir_context->cfg()->block(continue_block))) {
// If the loop's continue block is unreachable, we conservatively do not // If the loop's continue block is unreachable, we conservatively do not
// allow adding a dead continue, to avoid the compilations that arise due to // allow adding a dead continue, to avoid the compilations that arise due to
// the lack of sensible dominance information for unreachable blocks. // the lack of sensible dominance information for unreachable blocks.
return false; return false;
} }
if (fuzzerutil::BlockIsInLoopContinueConstruct(context, message_.from_block(), if (fuzzerutil::BlockIsInLoopContinueConstruct(
loop_header)) { ir_context, message_.from_block(), loop_header)) {
// We cannot jump to the continue target from the continue construct. // We cannot jump to the continue target from the continue construct.
return false; return false;
} }
if (context->GetStructuredCFGAnalysis()->IsMergeBlock(continue_block)) { if (ir_context->GetStructuredCFGAnalysis()->IsMergeBlock(continue_block)) {
// A branch straight to the continue target that is also a merge block might // A branch straight to the continue target that is also a merge block might
// break the property that a construct header must dominate its merge block // break the property that a construct header must dominate its merge block
// (if the merge block is reachable). // (if the merge block is reachable).
@ -100,8 +103,8 @@ bool TransformationAddDeadContinue::IsApplicable(
} }
// Check whether the data passed to extend OpPhi instructions is appropriate. // Check whether the data passed to extend OpPhi instructions is appropriate.
if (!fuzzerutil::PhiIdsOkForNewEdge(context, bb_from, if (!fuzzerutil::PhiIdsOkForNewEdge(ir_context, bb_from,
context->cfg()->block(continue_block), ir_context->cfg()->block(continue_block),
message_.phi_id())) { message_.phi_id())) {
return false; return false;
} }
@ -115,16 +118,18 @@ bool TransformationAddDeadContinue::IsApplicable(
// being placed on the validator. This should be revisited if we are sure // being placed on the validator. This should be revisited if we are sure
// the validator is complete with respect to checking structured control flow // the validator is complete with respect to checking structured control flow
// rules. // rules.
auto cloned_context = fuzzerutil::CloneIRContext(context); auto cloned_context = fuzzerutil::CloneIRContext(ir_context);
ApplyImpl(cloned_context.get()); ApplyImpl(cloned_context.get());
return fuzzerutil::IsValid(cloned_context.get()); return fuzzerutil::IsValid(cloned_context.get(),
transformation_context.GetValidatorOptions());
} }
void TransformationAddDeadContinue::Apply(opt::IRContext* context, void TransformationAddDeadContinue::Apply(
FactManager* /*unused*/) const { opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
ApplyImpl(context); ApplyImpl(ir_context);
// Invalidate all analyses // Invalidate all analyses
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
} }
protobufs::Transformation TransformationAddDeadContinue::ToMessage() const { protobufs::Transformation TransformationAddDeadContinue::ToMessage() const {
@ -134,16 +139,16 @@ protobufs::Transformation TransformationAddDeadContinue::ToMessage() const {
} }
void TransformationAddDeadContinue::ApplyImpl( void TransformationAddDeadContinue::ApplyImpl(
spvtools::opt::IRContext* context) const { spvtools::opt::IRContext* ir_context) const {
auto bb_from = context->cfg()->block(message_.from_block()); auto bb_from = ir_context->cfg()->block(message_.from_block());
auto continue_block = auto continue_block =
bb_from->IsLoopHeader() bb_from->IsLoopHeader()
? bb_from->ContinueBlockId() ? bb_from->ContinueBlockId()
: context->GetStructuredCFGAnalysis()->LoopContinueBlock( : ir_context->GetStructuredCFGAnalysis()->LoopContinueBlock(
message_.from_block()); message_.from_block());
assert(continue_block && "message_.from_block must be in a loop."); assert(continue_block && "message_.from_block must be in a loop.");
fuzzerutil::AddUnreachableEdgeAndUpdateOpPhis( fuzzerutil::AddUnreachableEdgeAndUpdateOpPhis(
context, bb_from, context->cfg()->block(continue_block), ir_context, bb_from, ir_context->cfg()->block(continue_block),
message_.continue_condition_value(), message_.phi_id()); message_.continue_condition_value(), message_.phi_id());
} }

View File

@ -17,9 +17,9 @@
#include <vector> #include <vector>
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h" #include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
namespace spvtools { namespace spvtools {
@ -52,14 +52,16 @@ class TransformationAddDeadContinue : public Transformation {
// In particular, adding an edge from somewhere in the loop to the continue // In particular, adding an edge from somewhere in the loop to the continue
// target must not prevent uses of ids in the continue target from being // target must not prevent uses of ids in the continue target from being
// dominated by the definitions of those ids. // dominated by the definitions of those ids.
bool IsApplicable(opt::IRContext* context, bool IsApplicable(
const FactManager& fact_manager) const override; opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Replaces the terminator of a with a conditional branch to b or c. // Replaces the terminator of a with a conditional branch to b or c.
// The boolean constant associated with |message_.continue_condition_value| is // The boolean constant associated with |message_.continue_condition_value| is
// used as the condition, and the order of b and c is arranged such that // used as the condition, and the order of b and c is arranged such that
// control is guaranteed to jump to c. // control is guaranteed to jump to c.
void Apply(opt::IRContext* context, FactManager* fact_manager) const override; void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
protobufs::Transformation ToMessage() const override; protobufs::Transformation ToMessage() const override;
@ -70,7 +72,7 @@ class TransformationAddDeadContinue : public Transformation {
// module. This is only invoked by 'IsApplicable' after certain basic // module. This is only invoked by 'IsApplicable' after certain basic
// applicability checks have been made, ensuring that the invocation of this // applicability checks have been made, ensuring that the invocation of this
// method is legal. // method is legal.
void ApplyImpl(opt::IRContext* context) const; void ApplyImpl(opt::IRContext* ir_context) const;
protobufs::TransformationAddDeadContinue message_; protobufs::TransformationAddDeadContinue message_;
}; };

View File

@ -56,8 +56,8 @@ TransformationAddFunction::TransformationAddFunction(
} }
bool TransformationAddFunction::IsApplicable( bool TransformationAddFunction::IsApplicable(
opt::IRContext* context, opt::IRContext* ir_context,
const spvtools::fuzz::FactManager& fact_manager) const { const TransformationContext& transformation_context) const {
// This transformation may use a lot of ids, all of which need to be fresh // This transformation may use a lot of ids, all of which need to be fresh
// and distinct. This set tracks them. // and distinct. This set tracks them.
std::set<uint32_t> ids_used_by_this_transformation; std::set<uint32_t> ids_used_by_this_transformation;
@ -66,7 +66,7 @@ bool TransformationAddFunction::IsApplicable(
for (auto& instruction : message_.instruction()) { for (auto& instruction : message_.instruction()) {
if (instruction.result_id()) { if (instruction.result_id()) {
if (!CheckIdIsFreshAndNotUsedByThisTransformation( if (!CheckIdIsFreshAndNotUsedByThisTransformation(
instruction.result_id(), context, instruction.result_id(), ir_context,
&ids_used_by_this_transformation)) { &ids_used_by_this_transformation)) {
return false; return false;
} }
@ -77,28 +77,28 @@ bool TransformationAddFunction::IsApplicable(
// Ensure that all ids provided for making the function livesafe are fresh // Ensure that all ids provided for making the function livesafe are fresh
// and distinct. // and distinct.
if (!CheckIdIsFreshAndNotUsedByThisTransformation( if (!CheckIdIsFreshAndNotUsedByThisTransformation(
message_.loop_limiter_variable_id(), context, message_.loop_limiter_variable_id(), ir_context,
&ids_used_by_this_transformation)) { &ids_used_by_this_transformation)) {
return false; return false;
} }
for (auto& loop_limiter_info : message_.loop_limiter_info()) { for (auto& loop_limiter_info : message_.loop_limiter_info()) {
if (!CheckIdIsFreshAndNotUsedByThisTransformation( if (!CheckIdIsFreshAndNotUsedByThisTransformation(
loop_limiter_info.load_id(), context, loop_limiter_info.load_id(), ir_context,
&ids_used_by_this_transformation)) { &ids_used_by_this_transformation)) {
return false; return false;
} }
if (!CheckIdIsFreshAndNotUsedByThisTransformation( if (!CheckIdIsFreshAndNotUsedByThisTransformation(
loop_limiter_info.increment_id(), context, loop_limiter_info.increment_id(), ir_context,
&ids_used_by_this_transformation)) { &ids_used_by_this_transformation)) {
return false; return false;
} }
if (!CheckIdIsFreshAndNotUsedByThisTransformation( if (!CheckIdIsFreshAndNotUsedByThisTransformation(
loop_limiter_info.compare_id(), context, loop_limiter_info.compare_id(), ir_context,
&ids_used_by_this_transformation)) { &ids_used_by_this_transformation)) {
return false; return false;
} }
if (!CheckIdIsFreshAndNotUsedByThisTransformation( if (!CheckIdIsFreshAndNotUsedByThisTransformation(
loop_limiter_info.logical_op_id(), context, loop_limiter_info.logical_op_id(), ir_context,
&ids_used_by_this_transformation)) { &ids_used_by_this_transformation)) {
return false; return false;
} }
@ -107,11 +107,11 @@ bool TransformationAddFunction::IsApplicable(
message_.access_chain_clamping_info()) { message_.access_chain_clamping_info()) {
for (auto& pair : access_chain_clamping_info.compare_and_select_ids()) { for (auto& pair : access_chain_clamping_info.compare_and_select_ids()) {
if (!CheckIdIsFreshAndNotUsedByThisTransformation( if (!CheckIdIsFreshAndNotUsedByThisTransformation(
pair.first(), context, &ids_used_by_this_transformation)) { pair.first(), ir_context, &ids_used_by_this_transformation)) {
return false; return false;
} }
if (!CheckIdIsFreshAndNotUsedByThisTransformation( if (!CheckIdIsFreshAndNotUsedByThisTransformation(
pair.second(), context, &ids_used_by_this_transformation)) { pair.second(), ir_context, &ids_used_by_this_transformation)) {
return false; return false;
} }
} }
@ -123,8 +123,8 @@ bool TransformationAddFunction::IsApplicable(
// is taken here. // is taken here.
// We first clone the current module, so that we can try adding the new // We first clone the current module, so that we can try adding the new
// function without risking wrecking |context|. // function without risking wrecking |ir_context|.
auto cloned_module = fuzzerutil::CloneIRContext(context); auto cloned_module = fuzzerutil::CloneIRContext(ir_context);
// We try to add a function to the cloned module, which may fail if // We try to add a function to the cloned module, which may fail if
// |message_.instruction| is not sufficiently well-formed. // |message_.instruction| is not sufficiently well-formed.
@ -134,12 +134,14 @@ bool TransformationAddFunction::IsApplicable(
// Check whether the cloned module is still valid after adding the function. // Check whether the cloned module is still valid after adding the function.
// If it is not, the transformation is not applicable. // If it is not, the transformation is not applicable.
if (!fuzzerutil::IsValid(cloned_module.get())) { if (!fuzzerutil::IsValid(cloned_module.get(),
transformation_context.GetValidatorOptions())) {
return false; return false;
} }
if (message_.is_livesafe()) { if (message_.is_livesafe()) {
if (!TryToMakeFunctionLivesafe(cloned_module.get(), fact_manager)) { if (!TryToMakeFunctionLivesafe(cloned_module.get(),
transformation_context)) {
return false; return false;
} }
// After making the function livesafe, we check validity of the module // After making the function livesafe, we check validity of the module
@ -148,7 +150,8 @@ bool TransformationAddFunction::IsApplicable(
// has the potential to make the module invalid when it was otherwise valid. // has the potential to make the module invalid when it was otherwise valid.
// It is simpler to rely on the validator to guard against this than to // It is simpler to rely on the validator to guard against this than to
// consider all scenarios when making a function livesafe. // consider all scenarios when making a function livesafe.
if (!fuzzerutil::IsValid(cloned_module.get())) { if (!fuzzerutil::IsValid(cloned_module.get(),
transformation_context.GetValidatorOptions())) {
return false; return false;
} }
} }
@ -156,10 +159,11 @@ bool TransformationAddFunction::IsApplicable(
} }
void TransformationAddFunction::Apply( void TransformationAddFunction::Apply(
opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const { opt::IRContext* ir_context,
TransformationContext* transformation_context) const {
// Add the function to the module. As the transformation is applicable, this // Add the function to the module. As the transformation is applicable, this
// should succeed. // should succeed.
bool success = TryToAddFunction(context); bool success = TryToAddFunction(ir_context);
assert(success && "The function should be successfully added."); assert(success && "The function should be successfully added.");
(void)(success); // Keep release builds happy (otherwise they may complain (void)(success); // Keep release builds happy (otherwise they may complain
// that |success| is not used). // that |success| is not used).
@ -172,16 +176,16 @@ void TransformationAddFunction::Apply(
for (auto& instruction : message_.instruction()) { for (auto& instruction : message_.instruction()) {
switch (instruction.opcode()) { switch (instruction.opcode()) {
case SpvOpFunctionParameter: case SpvOpFunctionParameter:
if (context->get_def_use_mgr() if (ir_context->get_def_use_mgr()
->GetDef(instruction.result_type_id()) ->GetDef(instruction.result_type_id())
->opcode() == SpvOpTypePointer) { ->opcode() == SpvOpTypePointer) {
fact_manager->AddFactValueOfPointeeIsIrrelevant( transformation_context->GetFactManager()
instruction.result_id()); ->AddFactValueOfPointeeIsIrrelevant(instruction.result_id());
} }
break; break;
case SpvOpVariable: case SpvOpVariable:
fact_manager->AddFactValueOfPointeeIsIrrelevant( transformation_context->GetFactManager()
instruction.result_id()); ->AddFactValueOfPointeeIsIrrelevant(instruction.result_id());
break; break;
default: default:
break; break;
@ -190,7 +194,7 @@ void TransformationAddFunction::Apply(
if (message_.is_livesafe()) { if (message_.is_livesafe()) {
// Make the function livesafe, which also should succeed. // Make the function livesafe, which also should succeed.
success = TryToMakeFunctionLivesafe(context, *fact_manager); success = TryToMakeFunctionLivesafe(ir_context, *transformation_context);
assert(success && "It should be possible to make the function livesafe."); assert(success && "It should be possible to make the function livesafe.");
(void)(success); // Keep release builds happy. (void)(success); // Keep release builds happy.
@ -198,17 +202,18 @@ void TransformationAddFunction::Apply(
assert(message_.instruction(0).opcode() == SpvOpFunction && assert(message_.instruction(0).opcode() == SpvOpFunction &&
"The first instruction of an 'add function' transformation must be " "The first instruction of an 'add function' transformation must be "
"OpFunction."); "OpFunction.");
fact_manager->AddFactFunctionIsLivesafe( transformation_context->GetFactManager()->AddFactFunctionIsLivesafe(
message_.instruction(0).result_id()); message_.instruction(0).result_id());
} else { } else {
// Inform the fact manager that all blocks in the function are dead. // Inform the fact manager that all blocks in the function are dead.
for (auto& inst : message_.instruction()) { for (auto& inst : message_.instruction()) {
if (inst.opcode() == SpvOpLabel) { if (inst.opcode() == SpvOpLabel) {
fact_manager->AddFactBlockIsDead(inst.result_id()); transformation_context->GetFactManager()->AddFactBlockIsDead(
inst.result_id());
} }
} }
} }
context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
} }
protobufs::Transformation TransformationAddFunction::ToMessage() const { protobufs::Transformation TransformationAddFunction::ToMessage() const {
@ -218,9 +223,9 @@ protobufs::Transformation TransformationAddFunction::ToMessage() const {
} }
bool TransformationAddFunction::TryToAddFunction( bool TransformationAddFunction::TryToAddFunction(
opt::IRContext* context) const { opt::IRContext* ir_context) const {
// This function returns false if |message_.instruction| was not well-formed // This function returns false if |message_.instruction| was not well-formed
// enough to actually create a function and add it to |context|. // enough to actually create a function and add it to |ir_context|.
// A function must have at least some instructions. // A function must have at least some instructions.
if (message_.instruction().empty()) { if (message_.instruction().empty()) {
@ -235,7 +240,7 @@ bool TransformationAddFunction::TryToAddFunction(
// Make a function, headed by the OpFunction instruction. // Make a function, headed by the OpFunction instruction.
std::unique_ptr<opt::Function> new_function = MakeUnique<opt::Function>( std::unique_ptr<opt::Function> new_function = MakeUnique<opt::Function>(
InstructionFromMessage(context, function_begin)); InstructionFromMessage(ir_context, function_begin));
// Keeps track of which instruction protobuf message we are currently // Keeps track of which instruction protobuf message we are currently
// considering. // considering.
@ -249,7 +254,7 @@ bool TransformationAddFunction::TryToAddFunction(
message_.instruction(instruction_index).opcode() == message_.instruction(instruction_index).opcode() ==
SpvOpFunctionParameter) { SpvOpFunctionParameter) {
new_function->AddParameter(InstructionFromMessage( new_function->AddParameter(InstructionFromMessage(
context, message_.instruction(instruction_index))); ir_context, message_.instruction(instruction_index)));
instruction_index++; instruction_index++;
} }
@ -270,7 +275,7 @@ bool TransformationAddFunction::TryToAddFunction(
// as its parent. // as its parent.
std::unique_ptr<opt::BasicBlock> block = std::unique_ptr<opt::BasicBlock> block =
MakeUnique<opt::BasicBlock>(InstructionFromMessage( MakeUnique<opt::BasicBlock>(InstructionFromMessage(
context, message_.instruction(instruction_index))); ir_context, message_.instruction(instruction_index)));
block->SetParent(new_function.get()); block->SetParent(new_function.get());
// Consider successive instructions until we hit another label or the end // Consider successive instructions until we hit another label or the end
@ -281,7 +286,7 @@ bool TransformationAddFunction::TryToAddFunction(
SpvOpFunctionEnd && SpvOpFunctionEnd &&
message_.instruction(instruction_index).opcode() != SpvOpLabel) { message_.instruction(instruction_index).opcode() != SpvOpLabel) {
block->AddInstruction(InstructionFromMessage( block->AddInstruction(InstructionFromMessage(
context, message_.instruction(instruction_index))); ir_context, message_.instruction(instruction_index)));
instruction_index++; instruction_index++;
} }
// Add the block to the new function. // Add the block to the new function.
@ -295,22 +300,23 @@ bool TransformationAddFunction::TryToAddFunction(
} }
// Set the function's final instruction, add the function to the module and // Set the function's final instruction, add the function to the module and
// report success. // report success.
new_function->SetFunctionEnd( new_function->SetFunctionEnd(InstructionFromMessage(
InstructionFromMessage(context, message_.instruction(instruction_index))); ir_context, message_.instruction(instruction_index)));
context->AddFunction(std::move(new_function)); ir_context->AddFunction(std::move(new_function));
context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
return true; return true;
} }
bool TransformationAddFunction::TryToMakeFunctionLivesafe( bool TransformationAddFunction::TryToMakeFunctionLivesafe(
opt::IRContext* context, const FactManager& fact_manager) const { opt::IRContext* ir_context,
const TransformationContext& transformation_context) const {
assert(message_.is_livesafe() && "Precondition: is_livesafe must hold."); assert(message_.is_livesafe() && "Precondition: is_livesafe must hold.");
// Get a pointer to the added function. // Get a pointer to the added function.
opt::Function* added_function = nullptr; opt::Function* added_function = nullptr;
for (auto& function : *context->module()) { for (auto& function : *ir_context->module()) {
if (function.result_id() == message_.instruction(0).result_id()) { if (function.result_id() == message_.instruction(0).result_id()) {
added_function = &function; added_function = &function;
break; break;
@ -318,7 +324,7 @@ bool TransformationAddFunction::TryToMakeFunctionLivesafe(
} }
assert(added_function && "The added function should have been found."); assert(added_function && "The added function should have been found.");
if (!TryToAddLoopLimiters(context, added_function)) { if (!TryToAddLoopLimiters(ir_context, added_function)) {
// Adding loop limiters did not work; bail out. // Adding loop limiters did not work; bail out.
return false; return false;
} }
@ -332,20 +338,20 @@ bool TransformationAddFunction::TryToMakeFunctionLivesafe(
switch (inst.opcode()) { switch (inst.opcode()) {
case SpvOpKill: case SpvOpKill:
case SpvOpUnreachable: case SpvOpUnreachable:
if (!TryToTurnKillOrUnreachableIntoReturn(context, added_function, if (!TryToTurnKillOrUnreachableIntoReturn(ir_context, added_function,
&inst)) { &inst)) {
return false; return false;
} }
break; break;
case SpvOpAccessChain: case SpvOpAccessChain:
case SpvOpInBoundsAccessChain: case SpvOpInBoundsAccessChain:
if (!TryToClampAccessChainIndices(context, &inst)) { if (!TryToClampAccessChainIndices(ir_context, &inst)) {
return false; return false;
} }
break; break;
case SpvOpFunctionCall: case SpvOpFunctionCall:
// A livesafe function my only call other livesafe functions. // A livesafe function my only call other livesafe functions.
if (!fact_manager.FunctionIsLivesafe( if (!transformation_context.GetFactManager()->FunctionIsLivesafe(
inst.GetSingleWordInOperand(0))) { inst.GetSingleWordInOperand(0))) {
return false; return false;
} }
@ -358,7 +364,7 @@ bool TransformationAddFunction::TryToMakeFunctionLivesafe(
} }
bool TransformationAddFunction::TryToAddLoopLimiters( bool TransformationAddFunction::TryToAddLoopLimiters(
opt::IRContext* context, opt::Function* added_function) const { opt::IRContext* ir_context, opt::Function* added_function) const {
// Collect up all the loop headers so that we can subsequently add loop // Collect up all the loop headers so that we can subsequently add loop
// limiting logic. // limiting logic.
std::vector<opt::BasicBlock*> loop_headers; std::vector<opt::BasicBlock*> loop_headers;
@ -377,7 +383,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// manipulating a loop limiter. // manipulating a loop limiter.
auto loop_limit_constant_id_instr = auto loop_limit_constant_id_instr =
context->get_def_use_mgr()->GetDef(message_.loop_limit_constant_id()); ir_context->get_def_use_mgr()->GetDef(message_.loop_limit_constant_id());
if (!loop_limit_constant_id_instr || if (!loop_limit_constant_id_instr ||
loop_limit_constant_id_instr->opcode() != SpvOpConstant) { loop_limit_constant_id_instr->opcode() != SpvOpConstant) {
// The loop limit constant id instruction must exist and have an // The loop limit constant id instruction must exist and have an
@ -385,7 +391,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
return false; return false;
} }
auto loop_limit_type = context->get_def_use_mgr()->GetDef( auto loop_limit_type = ir_context->get_def_use_mgr()->GetDef(
loop_limit_constant_id_instr->type_id()); loop_limit_constant_id_instr->type_id());
if (loop_limit_type->opcode() != SpvOpTypeInt || if (loop_limit_type->opcode() != SpvOpTypeInt ||
loop_limit_type->GetSingleWordInOperand(0) != 32) { loop_limit_type->GetSingleWordInOperand(0) != 32) {
@ -397,36 +403,36 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// Find the id of the "unsigned int" type. // Find the id of the "unsigned int" type.
opt::analysis::Integer unsigned_int_type(32, false); opt::analysis::Integer unsigned_int_type(32, false);
uint32_t unsigned_int_type_id = uint32_t unsigned_int_type_id =
context->get_type_mgr()->GetId(&unsigned_int_type); ir_context->get_type_mgr()->GetId(&unsigned_int_type);
if (!unsigned_int_type_id) { if (!unsigned_int_type_id) {
// Unsigned int is not available; we need this type in order to add loop // Unsigned int is not available; we need this type in order to add loop
// limiters. // limiters.
return false; return false;
} }
auto registered_unsigned_int_type = auto registered_unsigned_int_type =
context->get_type_mgr()->GetRegisteredType(&unsigned_int_type); ir_context->get_type_mgr()->GetRegisteredType(&unsigned_int_type);
// Look for 0 of type unsigned int. // Look for 0 of type unsigned int.
opt::analysis::IntConstant zero(registered_unsigned_int_type->AsInteger(), opt::analysis::IntConstant zero(registered_unsigned_int_type->AsInteger(),
{0}); {0});
auto registered_zero = context->get_constant_mgr()->FindConstant(&zero); auto registered_zero = ir_context->get_constant_mgr()->FindConstant(&zero);
if (!registered_zero) { if (!registered_zero) {
// We need 0 in order to be able to initialize loop limiters. // We need 0 in order to be able to initialize loop limiters.
return false; return false;
} }
uint32_t zero_id = context->get_constant_mgr() uint32_t zero_id = ir_context->get_constant_mgr()
->GetDefiningInstruction(registered_zero) ->GetDefiningInstruction(registered_zero)
->result_id(); ->result_id();
// Look for 1 of type unsigned int. // Look for 1 of type unsigned int.
opt::analysis::IntConstant one(registered_unsigned_int_type->AsInteger(), opt::analysis::IntConstant one(registered_unsigned_int_type->AsInteger(),
{1}); {1});
auto registered_one = context->get_constant_mgr()->FindConstant(&one); auto registered_one = ir_context->get_constant_mgr()->FindConstant(&one);
if (!registered_one) { if (!registered_one) {
// We need 1 in order to be able to increment loop limiters. // We need 1 in order to be able to increment loop limiters.
return false; return false;
} }
uint32_t one_id = context->get_constant_mgr() uint32_t one_id = ir_context->get_constant_mgr()
->GetDefiningInstruction(registered_one) ->GetDefiningInstruction(registered_one)
->result_id(); ->result_id();
@ -434,7 +440,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
opt::analysis::Pointer pointer_to_unsigned_int_type( opt::analysis::Pointer pointer_to_unsigned_int_type(
registered_unsigned_int_type, SpvStorageClassFunction); registered_unsigned_int_type, SpvStorageClassFunction);
uint32_t pointer_to_unsigned_int_type_id = uint32_t pointer_to_unsigned_int_type_id =
context->get_type_mgr()->GetId(&pointer_to_unsigned_int_type); ir_context->get_type_mgr()->GetId(&pointer_to_unsigned_int_type);
if (!pointer_to_unsigned_int_type_id) { if (!pointer_to_unsigned_int_type_id) {
// We need pointer-to-unsigned int in order to declare the loop limiter // We need pointer-to-unsigned int in order to declare the loop limiter
// variable. // variable.
@ -443,7 +449,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// Look for bool type. // Look for bool type.
opt::analysis::Bool bool_type; opt::analysis::Bool bool_type;
uint32_t bool_type_id = context->get_type_mgr()->GetId(&bool_type); uint32_t bool_type_id = ir_context->get_type_mgr()->GetId(&bool_type);
if (!bool_type_id) { if (!bool_type_id) {
// We need bool in order to compare the loop limiter's value with the loop // We need bool in order to compare the loop limiter's value with the loop
// limit constant. // limit constant.
@ -454,22 +460,23 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// block, via an instruction of the form: // block, via an instruction of the form:
// %loop_limiter_var = SpvOpVariable %ptr_to_uint Function %zero // %loop_limiter_var = SpvOpVariable %ptr_to_uint Function %zero
added_function->begin()->begin()->InsertBefore(MakeUnique<opt::Instruction>( added_function->begin()->begin()->InsertBefore(MakeUnique<opt::Instruction>(
context, SpvOpVariable, pointer_to_unsigned_int_type_id, ir_context, SpvOpVariable, pointer_to_unsigned_int_type_id,
message_.loop_limiter_variable_id(), message_.loop_limiter_variable_id(),
opt::Instruction::OperandList( opt::Instruction::OperandList(
{{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}}, {{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}},
{SPV_OPERAND_TYPE_ID, {zero_id}}}))); {SPV_OPERAND_TYPE_ID, {zero_id}}})));
// Update the module's id bound since we have added the loop limiter // Update the module's id bound since we have added the loop limiter
// variable id. // variable id.
fuzzerutil::UpdateModuleIdBound(context, message_.loop_limiter_variable_id()); fuzzerutil::UpdateModuleIdBound(ir_context,
message_.loop_limiter_variable_id());
// Consider each loop in turn. // Consider each loop in turn.
for (auto loop_header : loop_headers) { for (auto loop_header : loop_headers) {
// Look for the loop's back-edge block. This is a predecessor of the loop // Look for the loop's back-edge block. This is a predecessor of the loop
// header that is dominated by the loop header. // header that is dominated by the loop header.
uint32_t back_edge_block_id = 0; uint32_t back_edge_block_id = 0;
for (auto pred : context->cfg()->preds(loop_header->id())) { for (auto pred : ir_context->cfg()->preds(loop_header->id())) {
if (context->GetDominatorAnalysis(added_function) if (ir_context->GetDominatorAnalysis(added_function)
->Dominates(loop_header->id(), pred)) { ->Dominates(loop_header->id(), pred)) {
back_edge_block_id = pred; back_edge_block_id = pred;
break; break;
@ -481,7 +488,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// move on from this loop. // move on from this loop.
continue; continue;
} }
auto back_edge_block = context->cfg()->block(back_edge_block_id); auto back_edge_block = ir_context->cfg()->block(back_edge_block_id);
// Go through the sequence of loop limiter infos and find the one // Go through the sequence of loop limiter infos and find the one
// corresponding to this loop. // corresponding to this loop.
@ -579,14 +586,15 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// Add a load from the loop limiter variable, of the form: // Add a load from the loop limiter variable, of the form:
// %t1 = OpLoad %uint32 %loop_limiter // %t1 = OpLoad %uint32 %loop_limiter
new_instructions.push_back(MakeUnique<opt::Instruction>( new_instructions.push_back(MakeUnique<opt::Instruction>(
context, SpvOpLoad, unsigned_int_type_id, loop_limiter_info.load_id(), ir_context, SpvOpLoad, unsigned_int_type_id,
loop_limiter_info.load_id(),
opt::Instruction::OperandList( opt::Instruction::OperandList(
{{SPV_OPERAND_TYPE_ID, {message_.loop_limiter_variable_id()}}}))); {{SPV_OPERAND_TYPE_ID, {message_.loop_limiter_variable_id()}}})));
// Increment the loaded value: // Increment the loaded value:
// %t2 = OpIAdd %uint32 %t1 %one // %t2 = OpIAdd %uint32 %t1 %one
new_instructions.push_back(MakeUnique<opt::Instruction>( new_instructions.push_back(MakeUnique<opt::Instruction>(
context, SpvOpIAdd, unsigned_int_type_id, ir_context, SpvOpIAdd, unsigned_int_type_id,
loop_limiter_info.increment_id(), loop_limiter_info.increment_id(),
opt::Instruction::OperandList( opt::Instruction::OperandList(
{{SPV_OPERAND_TYPE_ID, {loop_limiter_info.load_id()}}, {{SPV_OPERAND_TYPE_ID, {loop_limiter_info.load_id()}},
@ -595,7 +603,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// Store the incremented value back to the loop limiter variable: // Store the incremented value back to the loop limiter variable:
// OpStore %loop_limiter %t2 // OpStore %loop_limiter %t2
new_instructions.push_back(MakeUnique<opt::Instruction>( new_instructions.push_back(MakeUnique<opt::Instruction>(
context, SpvOpStore, 0, 0, ir_context, SpvOpStore, 0, 0,
opt::Instruction::OperandList( opt::Instruction::OperandList(
{{SPV_OPERAND_TYPE_ID, {message_.loop_limiter_variable_id()}}, {{SPV_OPERAND_TYPE_ID, {message_.loop_limiter_variable_id()}},
{SPV_OPERAND_TYPE_ID, {loop_limiter_info.increment_id()}}}))); {SPV_OPERAND_TYPE_ID, {loop_limiter_info.increment_id()}}})));
@ -605,7 +613,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// or // or
// %t3 = OpULessThan %bool %t1 %loop_limit // %t3 = OpULessThan %bool %t1 %loop_limit
new_instructions.push_back(MakeUnique<opt::Instruction>( new_instructions.push_back(MakeUnique<opt::Instruction>(
context, ir_context,
compare_using_greater_than_equal ? SpvOpUGreaterThanEqual compare_using_greater_than_equal ? SpvOpUGreaterThanEqual
: SpvOpULessThan, : SpvOpULessThan,
bool_type_id, loop_limiter_info.compare_id(), bool_type_id, loop_limiter_info.compare_id(),
@ -615,7 +623,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
if (back_edge_block_terminator->opcode() == SpvOpBranchConditional) { if (back_edge_block_terminator->opcode() == SpvOpBranchConditional) {
new_instructions.push_back(MakeUnique<opt::Instruction>( new_instructions.push_back(MakeUnique<opt::Instruction>(
context, ir_context,
compare_using_greater_than_equal ? SpvOpLogicalOr : SpvOpLogicalAnd, compare_using_greater_than_equal ? SpvOpLogicalOr : SpvOpLogicalAnd,
bool_type_id, loop_limiter_info.logical_op_id(), bool_type_id, loop_limiter_info.logical_op_id(),
opt::Instruction::OperandList( opt::Instruction::OperandList(
@ -644,8 +652,9 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// Check that, if the merge block starts with OpPhi instructions, suitable // Check that, if the merge block starts with OpPhi instructions, suitable
// ids have been provided to give these instructions a value corresponding // ids have been provided to give these instructions a value corresponding
// to the new incoming edge from the back edge block. // to the new incoming edge from the back edge block.
auto merge_block = context->cfg()->block(loop_header->MergeBlockId()); auto merge_block = ir_context->cfg()->block(loop_header->MergeBlockId());
if (!fuzzerutil::PhiIdsOkForNewEdge(context, back_edge_block, merge_block, if (!fuzzerutil::PhiIdsOkForNewEdge(ir_context, back_edge_block,
merge_block,
loop_limiter_info.phi_id())) { loop_limiter_info.phi_id())) {
return false; return false;
} }
@ -681,16 +690,18 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// Update the module's id bound with respect to the various ids that // Update the module's id bound with respect to the various ids that
// have been used for loop limiter manipulation. // have been used for loop limiter manipulation.
fuzzerutil::UpdateModuleIdBound(context, loop_limiter_info.load_id()); fuzzerutil::UpdateModuleIdBound(ir_context, loop_limiter_info.load_id());
fuzzerutil::UpdateModuleIdBound(context, loop_limiter_info.increment_id()); fuzzerutil::UpdateModuleIdBound(ir_context,
fuzzerutil::UpdateModuleIdBound(context, loop_limiter_info.compare_id()); loop_limiter_info.increment_id());
fuzzerutil::UpdateModuleIdBound(context, loop_limiter_info.logical_op_id()); fuzzerutil::UpdateModuleIdBound(ir_context, loop_limiter_info.compare_id());
fuzzerutil::UpdateModuleIdBound(ir_context,
loop_limiter_info.logical_op_id());
} }
return true; return true;
} }
bool TransformationAddFunction::TryToTurnKillOrUnreachableIntoReturn( bool TransformationAddFunction::TryToTurnKillOrUnreachableIntoReturn(
opt::IRContext* context, opt::Function* added_function, opt::IRContext* ir_context, opt::Function* added_function,
opt::Instruction* kill_or_unreachable_inst) const { opt::Instruction* kill_or_unreachable_inst) const {
assert((kill_or_unreachable_inst->opcode() == SpvOpKill || assert((kill_or_unreachable_inst->opcode() == SpvOpKill ||
kill_or_unreachable_inst->opcode() == SpvOpUnreachable) && kill_or_unreachable_inst->opcode() == SpvOpUnreachable) &&
@ -698,7 +709,7 @@ bool TransformationAddFunction::TryToTurnKillOrUnreachableIntoReturn(
// Get the function's return type. // Get the function's return type.
auto function_return_type_inst = auto function_return_type_inst =
context->get_def_use_mgr()->GetDef(added_function->type_id()); ir_context->get_def_use_mgr()->GetDef(added_function->type_id());
if (function_return_type_inst->opcode() == SpvOpTypeVoid) { if (function_return_type_inst->opcode() == SpvOpTypeVoid) {
// The function has void return type, so change this instruction to // The function has void return type, so change this instruction to
@ -712,7 +723,7 @@ bool TransformationAddFunction::TryToTurnKillOrUnreachableIntoReturn(
// We first check that the id, %id, provided with the transformation // We first check that the id, %id, provided with the transformation
// specifically to turn OpKill and OpUnreachable instructions into // specifically to turn OpKill and OpUnreachable instructions into
// OpReturnValue %id has the same type as the function's return type. // OpReturnValue %id has the same type as the function's return type.
if (context->get_def_use_mgr() if (ir_context->get_def_use_mgr()
->GetDef(message_.kill_unreachable_return_value_id()) ->GetDef(message_.kill_unreachable_return_value_id())
->type_id() != function_return_type_inst->result_id()) { ->type_id() != function_return_type_inst->result_id()) {
return false; return false;
@ -725,7 +736,7 @@ bool TransformationAddFunction::TryToTurnKillOrUnreachableIntoReturn(
} }
bool TransformationAddFunction::TryToClampAccessChainIndices( bool TransformationAddFunction::TryToClampAccessChainIndices(
opt::IRContext* context, opt::Instruction* access_chain_inst) const { opt::IRContext* ir_context, opt::Instruction* access_chain_inst) const {
assert((access_chain_inst->opcode() == SpvOpAccessChain || assert((access_chain_inst->opcode() == SpvOpAccessChain ||
access_chain_inst->opcode() == SpvOpInBoundsAccessChain) && access_chain_inst->opcode() == SpvOpInBoundsAccessChain) &&
"Precondition: instruction must be OpAccessChain or " "Precondition: instruction must be OpAccessChain or "
@ -756,14 +767,14 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
// Walk the access chain, clamping each index to be within bounds if it is // Walk the access chain, clamping each index to be within bounds if it is
// not a constant. // not a constant.
auto base_object = context->get_def_use_mgr()->GetDef( auto base_object = ir_context->get_def_use_mgr()->GetDef(
access_chain_inst->GetSingleWordInOperand(0)); access_chain_inst->GetSingleWordInOperand(0));
assert(base_object && "The base object must exist."); assert(base_object && "The base object must exist.");
auto pointer_type = auto pointer_type =
context->get_def_use_mgr()->GetDef(base_object->type_id()); ir_context->get_def_use_mgr()->GetDef(base_object->type_id());
assert(pointer_type && pointer_type->opcode() == SpvOpTypePointer && assert(pointer_type && pointer_type->opcode() == SpvOpTypePointer &&
"The base object must have pointer type."); "The base object must have pointer type.");
auto should_be_composite_type = context->get_def_use_mgr()->GetDef( auto should_be_composite_type = ir_context->get_def_use_mgr()->GetDef(
pointer_type->GetSingleWordInOperand(1)); pointer_type->GetSingleWordInOperand(1));
// Consider each index input operand in turn (operand 0 is the base object). // Consider each index input operand in turn (operand 0 is the base object).
@ -784,18 +795,18 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
// Get the bound for the composite being indexed into; e.g. the number of // Get the bound for the composite being indexed into; e.g. the number of
// columns of matrix or the size of an array. // columns of matrix or the size of an array.
uint32_t bound = uint32_t bound =
GetBoundForCompositeIndex(context, *should_be_composite_type); GetBoundForCompositeIndex(ir_context, *should_be_composite_type);
// Get the instruction associated with the index and figure out its integer // Get the instruction associated with the index and figure out its integer
// type. // type.
const uint32_t index_id = access_chain_inst->GetSingleWordInOperand(index); const uint32_t index_id = access_chain_inst->GetSingleWordInOperand(index);
auto index_inst = context->get_def_use_mgr()->GetDef(index_id); auto index_inst = ir_context->get_def_use_mgr()->GetDef(index_id);
auto index_type_inst = auto index_type_inst =
context->get_def_use_mgr()->GetDef(index_inst->type_id()); ir_context->get_def_use_mgr()->GetDef(index_inst->type_id());
assert(index_type_inst->opcode() == SpvOpTypeInt); assert(index_type_inst->opcode() == SpvOpTypeInt);
assert(index_type_inst->GetSingleWordInOperand(0) == 32); assert(index_type_inst->GetSingleWordInOperand(0) == 32);
opt::analysis::Integer* index_int_type = opt::analysis::Integer* index_int_type =
context->get_type_mgr() ir_context->get_type_mgr()
->GetType(index_type_inst->result_id()) ->GetType(index_type_inst->result_id())
->AsInteger(); ->AsInteger();
@ -805,20 +816,20 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
"Access chain indices into structures are required to be " "Access chain indices into structures are required to be "
"constants."); "constants.");
opt::analysis::IntConstant bound_minus_one(index_int_type, {bound - 1}); opt::analysis::IntConstant bound_minus_one(index_int_type, {bound - 1});
if (!context->get_constant_mgr()->FindConstant(&bound_minus_one)) { if (!ir_context->get_constant_mgr()->FindConstant(&bound_minus_one)) {
// We do not have an integer constant whose value is |bound| -1. // We do not have an integer constant whose value is |bound| -1.
return false; return false;
} }
opt::analysis::Bool bool_type; opt::analysis::Bool bool_type;
uint32_t bool_type_id = context->get_type_mgr()->GetId(&bool_type); uint32_t bool_type_id = ir_context->get_type_mgr()->GetId(&bool_type);
if (!bool_type_id) { if (!bool_type_id) {
// Bool type is not declared; we cannot do a comparison. // Bool type is not declared; we cannot do a comparison.
return false; return false;
} }
uint32_t bound_minus_one_id = uint32_t bound_minus_one_id =
context->get_constant_mgr() ir_context->get_constant_mgr()
->GetDefiningInstruction(&bound_minus_one) ->GetDefiningInstruction(&bound_minus_one)
->result_id(); ->result_id();
@ -832,7 +843,7 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
// Compare the index with the bound via an instruction of the form: // Compare the index with the bound via an instruction of the form:
// %t1 = OpULessThanEqual %bool %index %bound_minus_one // %t1 = OpULessThanEqual %bool %index %bound_minus_one
new_instructions.push_back(MakeUnique<opt::Instruction>( new_instructions.push_back(MakeUnique<opt::Instruction>(
context, SpvOpULessThanEqual, bool_type_id, compare_id, ir_context, SpvOpULessThanEqual, bool_type_id, compare_id,
opt::Instruction::OperandList( opt::Instruction::OperandList(
{{SPV_OPERAND_TYPE_ID, {index_inst->result_id()}}, {{SPV_OPERAND_TYPE_ID, {index_inst->result_id()}},
{SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}}))); {SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}})));
@ -840,7 +851,7 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
// Select the index if in-bounds, otherwise one less than the bound: // Select the index if in-bounds, otherwise one less than the bound:
// %t2 = OpSelect %int_type %t1 %index %bound_minus_one // %t2 = OpSelect %int_type %t1 %index %bound_minus_one
new_instructions.push_back(MakeUnique<opt::Instruction>( new_instructions.push_back(MakeUnique<opt::Instruction>(
context, SpvOpSelect, index_type_inst->result_id(), select_id, ir_context, SpvOpSelect, index_type_inst->result_id(), select_id,
opt::Instruction::OperandList( opt::Instruction::OperandList(
{{SPV_OPERAND_TYPE_ID, {compare_id}}, {{SPV_OPERAND_TYPE_ID, {compare_id}},
{SPV_OPERAND_TYPE_ID, {index_inst->result_id()}}, {SPV_OPERAND_TYPE_ID, {index_inst->result_id()}},
@ -851,8 +862,8 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
// Replace %index with %t2. // Replace %index with %t2.
access_chain_inst->SetInOperand(index, {select_id}); access_chain_inst->SetInOperand(index, {select_id});
fuzzerutil::UpdateModuleIdBound(context, compare_id); fuzzerutil::UpdateModuleIdBound(ir_context, compare_id);
fuzzerutil::UpdateModuleIdBound(context, select_id); fuzzerutil::UpdateModuleIdBound(ir_context, select_id);
} else { } else {
// TODO(afd): At present the SPIR-V spec is not clear on whether // TODO(afd): At present the SPIR-V spec is not clear on whether
// statically out-of-bounds indices mean that a module is invalid (so // statically out-of-bounds indices mean that a module is invalid (so
@ -870,16 +881,16 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
} }
} }
should_be_composite_type = should_be_composite_type =
FollowCompositeIndex(context, *should_be_composite_type, index_id); FollowCompositeIndex(ir_context, *should_be_composite_type, index_id);
} }
return true; return true;
} }
uint32_t TransformationAddFunction::GetBoundForCompositeIndex( uint32_t TransformationAddFunction::GetBoundForCompositeIndex(
opt::IRContext* context, const opt::Instruction& composite_type_inst) { opt::IRContext* ir_context, const opt::Instruction& composite_type_inst) {
switch (composite_type_inst.opcode()) { switch (composite_type_inst.opcode()) {
case SpvOpTypeArray: case SpvOpTypeArray:
return fuzzerutil::GetArraySize(composite_type_inst, context); return fuzzerutil::GetArraySize(composite_type_inst, ir_context);
case SpvOpTypeMatrix: case SpvOpTypeMatrix:
case SpvOpTypeVector: case SpvOpTypeVector:
return composite_type_inst.GetSingleWordInOperand(1); return composite_type_inst.GetSingleWordInOperand(1);
@ -893,7 +904,7 @@ uint32_t TransformationAddFunction::GetBoundForCompositeIndex(
} }
opt::Instruction* TransformationAddFunction::FollowCompositeIndex( opt::Instruction* TransformationAddFunction::FollowCompositeIndex(
opt::IRContext* context, const opt::Instruction& composite_type_inst, opt::IRContext* ir_context, const opt::Instruction& composite_type_inst,
uint32_t index_id) { uint32_t index_id) {
uint32_t sub_object_type_id; uint32_t sub_object_type_id;
switch (composite_type_inst.opcode()) { switch (composite_type_inst.opcode()) {
@ -905,12 +916,12 @@ opt::Instruction* TransformationAddFunction::FollowCompositeIndex(
sub_object_type_id = composite_type_inst.GetSingleWordInOperand(0); sub_object_type_id = composite_type_inst.GetSingleWordInOperand(0);
break; break;
case SpvOpTypeStruct: { case SpvOpTypeStruct: {
auto index_inst = context->get_def_use_mgr()->GetDef(index_id); auto index_inst = ir_context->get_def_use_mgr()->GetDef(index_id);
assert(index_inst->opcode() == SpvOpConstant); assert(index_inst->opcode() == SpvOpConstant);
assert( assert(ir_context->get_def_use_mgr()
context->get_def_use_mgr()->GetDef(index_inst->type_id())->opcode() == ->GetDef(index_inst->type_id())
SpvOpTypeInt); ->opcode() == SpvOpTypeInt);
assert(context->get_def_use_mgr() assert(ir_context->get_def_use_mgr()
->GetDef(index_inst->type_id()) ->GetDef(index_inst->type_id())
->GetSingleWordInOperand(0) == 32); ->GetSingleWordInOperand(0) == 32);
uint32_t index_value = index_inst->GetSingleWordInOperand(0); uint32_t index_value = index_inst->GetSingleWordInOperand(0);
@ -924,7 +935,7 @@ opt::Instruction* TransformationAddFunction::FollowCompositeIndex(
break; break;
} }
assert(sub_object_type_id && "No sub-object found."); assert(sub_object_type_id && "No sub-object found.");
return context->get_def_use_mgr()->GetDef(sub_object_type_id); return ir_context->get_def_use_mgr()->GetDef(sub_object_type_id);
} }
} // namespace fuzz } // namespace fuzz

View File

@ -15,9 +15,9 @@
#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_FUNCTION_H_ #ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_FUNCTION_H_
#define SOURCE_FUZZ_TRANSFORMATION_ADD_FUNCTION_H_ #define SOURCE_FUZZ_TRANSFORMATION_ADD_FUNCTION_H_
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h" #include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
namespace spvtools { namespace spvtools {
@ -47,12 +47,14 @@ class TransformationAddFunction : public Transformation {
// ingredients to make the function livesafe, and the function must only // ingredients to make the function livesafe, and the function must only
// invoke other livesafe functions // invoke other livesafe functions
// - Adding the created function to the module must lead to a valid module. // - Adding the created function to the module must lead to a valid module.
bool IsApplicable(opt::IRContext* context, bool IsApplicable(
const FactManager& fact_manager) const override; opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Adds the function defined by |message_.instruction| to the module, making // Adds the function defined by |message_.instruction| to the module, making
// it livesafe if |message_.is_livesafe| holds. // it livesafe if |message_.is_livesafe| holds.
void Apply(opt::IRContext* context, FactManager* fact_manager) const override; void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
protobufs::Transformation ToMessage() const override; protobufs::Transformation ToMessage() const override;
@ -61,26 +63,26 @@ class TransformationAddFunction : public Transformation {
// an array, the number of components of a vector, or the number of columns of // an array, the number of components of a vector, or the number of columns of
// a matrix. // a matrix.
static uint32_t GetBoundForCompositeIndex( static uint32_t GetBoundForCompositeIndex(
opt::IRContext* context, const opt::Instruction& composite_type_inst); opt::IRContext* ir_context, const opt::Instruction& composite_type_inst);
// Helper method that, given composite type |composite_type_inst|, returns the // Helper method that, given composite type |composite_type_inst|, returns the
// type of the sub-object at index |index_id|, which is required to be in- // type of the sub-object at index |index_id|, which is required to be in-
// bounds. // bounds.
static opt::Instruction* FollowCompositeIndex( static opt::Instruction* FollowCompositeIndex(
opt::IRContext* context, const opt::Instruction& composite_type_inst, opt::IRContext* ir_context, const opt::Instruction& composite_type_inst,
uint32_t index_id); uint32_t index_id);
private: private:
// Attempts to create a function from the series of instructions in // Attempts to create a function from the series of instructions in
// |message_.instruction| and add it to |context|. // |message_.instruction| and add it to |ir_context|.
// //
// Returns false if adding the function is not possible due to the messages // Returns false if adding the function is not possible due to the messages
// not respecting the basic structure of a function, e.g. if there is no // not respecting the basic structure of a function, e.g. if there is no
// OpFunction instruction or no blocks; in this case |context| is left in an // OpFunction instruction or no blocks; in this case |ir_context| is left in
// indeterminate state. // an indeterminate state.
// //
// Otherwise returns true. Whether |context| is valid after addition of the // Otherwise returns true. Whether |ir_context| is valid after addition of
// function depends on the contents of |message_.instruction|. // the function depends on the contents of |message_.instruction|.
// //
// Intended usage: // Intended usage:
// - Perform a dry run of this method on a clone of a module, and use // - Perform a dry run of this method on a clone of a module, and use
@ -89,30 +91,31 @@ class TransformationAddFunction : public Transformation {
// added, or leads to an invalid module. // added, or leads to an invalid module.
// - If the dry run succeeds, run the method on the real module of interest, // - If the dry run succeeds, run the method on the real module of interest,
// to add the function. // to add the function.
bool TryToAddFunction(opt::IRContext* context) const; bool TryToAddFunction(opt::IRContext* ir_context) const;
// Should only be called if |message_.is_livesafe| holds. Attempts to make // Should only be called if |message_.is_livesafe| holds. Attempts to make
// the function livesafe (see FactFunctionIsLivesafe for a definition). // the function livesafe (see FactFunctionIsLivesafe for a definition).
// Returns false if this is not possible, due to |message_| or |context| not // Returns false if this is not possible, due to |message_| or |ir_context|
// containing sufficient ingredients (such as types and fresh ids) to add // not containing sufficient ingredients (such as types and fresh ids) to add
// the instrumentation necessary to make the function livesafe. // the instrumentation necessary to make the function livesafe.
bool TryToMakeFunctionLivesafe(opt::IRContext* context, bool TryToMakeFunctionLivesafe(
const FactManager& fact_manager) const; opt::IRContext* ir_context,
const TransformationContext& transformation_context) const;
// A helper for TryToMakeFunctionLivesafe that tries to add loop-limiting // A helper for TryToMakeFunctionLivesafe that tries to add loop-limiting
// logic. // logic.
bool TryToAddLoopLimiters(opt::IRContext* context, bool TryToAddLoopLimiters(opt::IRContext* ir_context,
opt::Function* added_function) const; opt::Function* added_function) const;
// A helper for TryToMakeFunctionLivesafe that tries to replace OpKill and // A helper for TryToMakeFunctionLivesafe that tries to replace OpKill and
// OpUnreachable instructions into return instructions. // OpUnreachable instructions into return instructions.
bool TryToTurnKillOrUnreachableIntoReturn( bool TryToTurnKillOrUnreachableIntoReturn(
opt::IRContext* context, opt::Function* added_function, opt::IRContext* ir_context, opt::Function* added_function,
opt::Instruction* kill_or_unreachable_inst) const; opt::Instruction* kill_or_unreachable_inst) const;
// A helper for TryToMakeFunctionLivesafe that tries to clamp access chain // A helper for TryToMakeFunctionLivesafe that tries to clamp access chain
// indices so that they are guaranteed to be in-bounds. // indices so that they are guaranteed to be in-bounds.
bool TryToClampAccessChainIndices(opt::IRContext* context, bool TryToClampAccessChainIndices(opt::IRContext* ir_context,
opt::Instruction* access_chain_inst) const; opt::Instruction* access_chain_inst) const;
protobufs::TransformationAddFunction message_; protobufs::TransformationAddFunction message_;

View File

@ -30,26 +30,26 @@ TransformationAddGlobalUndef::TransformationAddGlobalUndef(uint32_t fresh_id,
} }
bool TransformationAddGlobalUndef::IsApplicable( bool TransformationAddGlobalUndef::IsApplicable(
opt::IRContext* context, opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
const spvtools::fuzz::FactManager& /*unused*/) const {
// A fresh id is required. // A fresh id is required.
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
return false; return false;
} }
auto type = context->get_type_mgr()->GetType(message_.type_id()); auto type = ir_context->get_type_mgr()->GetType(message_.type_id());
// The type must exist, and must not be a function type. // The type must exist, and must not be a function type.
return type && !type->AsFunction(); return type && !type->AsFunction();
} }
void TransformationAddGlobalUndef::Apply( void TransformationAddGlobalUndef::Apply(
opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>( ir_context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
context, SpvOpUndef, message_.type_id(), message_.fresh_id(), ir_context, SpvOpUndef, message_.type_id(), message_.fresh_id(),
opt::Instruction::OperandList())); opt::Instruction::OperandList()));
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
// We have added an instruction to the module, so need to be careful about the // We have added an instruction to the module, so need to be careful about the
// validity of existing analyses. // validity of existing analyses.
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
} }
protobufs::Transformation TransformationAddGlobalUndef::ToMessage() const { protobufs::Transformation TransformationAddGlobalUndef::ToMessage() const {

View File

@ -15,9 +15,9 @@
#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_UNDEF_H_ #ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_UNDEF_H_
#define SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_UNDEF_H_ #define SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_UNDEF_H_
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h" #include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
namespace spvtools { namespace spvtools {
@ -32,12 +32,14 @@ class TransformationAddGlobalUndef : public Transformation {
// - |message_.fresh_id| must be fresh // - |message_.fresh_id| must be fresh
// - |message_.type_id| must be the id of a non-function type // - |message_.type_id| must be the id of a non-function type
bool IsApplicable(opt::IRContext* context, bool IsApplicable(
const FactManager& fact_manager) const override; opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Adds an OpUndef instruction to the module, with |message_.type_id| as its // Adds an OpUndef instruction to the module, with |message_.type_id| as its
// type. The instruction has result id |message_.fresh_id|. // type. The instruction has result id |message_.fresh_id|.
void Apply(opt::IRContext* context, FactManager* fact_manager) const override; void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
protobufs::Transformation ToMessage() const override; protobufs::Transformation ToMessage() const override;

View File

@ -33,14 +33,13 @@ TransformationAddGlobalVariable::TransformationAddGlobalVariable(
} }
bool TransformationAddGlobalVariable::IsApplicable( bool TransformationAddGlobalVariable::IsApplicable(
opt::IRContext* context, opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
const spvtools::fuzz::FactManager& /*unused*/) const {
// The result id must be fresh. // The result id must be fresh.
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
return false; return false;
} }
// The type id must correspond to a type. // The type id must correspond to a type.
auto type = context->get_type_mgr()->GetType(message_.type_id()); auto type = ir_context->get_type_mgr()->GetType(message_.type_id());
if (!type) { if (!type) {
return false; return false;
} }
@ -55,7 +54,7 @@ bool TransformationAddGlobalVariable::IsApplicable(
} }
// The initializer id must be the id of a constant. Check this with the // The initializer id must be the id of a constant. Check this with the
// constant manager. // constant manager.
auto constant_id = context->get_constant_mgr()->GetConstantsFromIds( auto constant_id = ir_context->get_constant_mgr()->GetConstantsFromIds(
{message_.initializer_id()}); {message_.initializer_id()});
if (constant_id.empty()) { if (constant_id.empty()) {
return false; return false;
@ -71,7 +70,8 @@ bool TransformationAddGlobalVariable::IsApplicable(
} }
void TransformationAddGlobalVariable::Apply( void TransformationAddGlobalVariable::Apply(
opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const { opt::IRContext* ir_context,
TransformationContext* transformation_context) const {
opt::Instruction::OperandList input_operands; opt::Instruction::OperandList input_operands;
input_operands.push_back( input_operands.push_back(
{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassPrivate}}); {SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassPrivate}});
@ -79,12 +79,12 @@ void TransformationAddGlobalVariable::Apply(
input_operands.push_back( input_operands.push_back(
{SPV_OPERAND_TYPE_ID, {message_.initializer_id()}}); {SPV_OPERAND_TYPE_ID, {message_.initializer_id()}});
} }
context->module()->AddGlobalValue( ir_context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
MakeUnique<opt::Instruction>(context, SpvOpVariable, message_.type_id(), ir_context, SpvOpVariable, message_.type_id(), message_.fresh_id(),
message_.fresh_id(), input_operands)); input_operands));
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
if (PrivateGlobalsMustBeDeclaredInEntryPointInterfaces(context)) { if (PrivateGlobalsMustBeDeclaredInEntryPointInterfaces(ir_context)) {
// Conservatively add this global to the interface of every entry point in // Conservatively add this global to the interface of every entry point in
// the module. This means that the global is available for other // the module. This means that the global is available for other
// transformations to use. // transformations to use.
@ -94,18 +94,20 @@ void TransformationAddGlobalVariable::Apply(
// //
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3111) revisit // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3111) revisit
// this if a more thorough approach to entry point interfaces is taken. // this if a more thorough approach to entry point interfaces is taken.
for (auto& entry_point : context->module()->entry_points()) { for (auto& entry_point : ir_context->module()->entry_points()) {
entry_point.AddOperand({SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}); entry_point.AddOperand({SPV_OPERAND_TYPE_ID, {message_.fresh_id()}});
} }
} }
if (message_.value_is_irrelevant()) { if (message_.value_is_irrelevant()) {
fact_manager->AddFactValueOfPointeeIsIrrelevant(message_.fresh_id()); transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
message_.fresh_id());
} }
// We have added an instruction to the module, so need to be careful about the // We have added an instruction to the module, so need to be careful about the
// validity of existing analyses. // validity of existing analyses.
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
} }
protobufs::Transformation TransformationAddGlobalVariable::ToMessage() const { protobufs::Transformation TransformationAddGlobalVariable::ToMessage() const {
@ -116,11 +118,11 @@ protobufs::Transformation TransformationAddGlobalVariable::ToMessage() const {
bool TransformationAddGlobalVariable:: bool TransformationAddGlobalVariable::
PrivateGlobalsMustBeDeclaredInEntryPointInterfaces( PrivateGlobalsMustBeDeclaredInEntryPointInterfaces(
opt::IRContext* context) { opt::IRContext* ir_context) {
// TODO(afd): We capture the universal environments for which this requirement // TODO(afd): We capture the universal environments for which this requirement
// holds. The check should be refined on demand for other target // holds. The check should be refined on demand for other target
// environments. // environments.
switch (context->grammar().target_env()) { switch (ir_context->grammar().target_env()) {
case SPV_ENV_UNIVERSAL_1_0: case SPV_ENV_UNIVERSAL_1_0:
case SPV_ENV_UNIVERSAL_1_1: case SPV_ENV_UNIVERSAL_1_1:
case SPV_ENV_UNIVERSAL_1_2: case SPV_ENV_UNIVERSAL_1_2:

View File

@ -15,9 +15,9 @@
#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_VARIABLE_H_ #ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_VARIABLE_H_
#define SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_VARIABLE_H_ #define SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_VARIABLE_H_
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h" #include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
namespace spvtools { namespace spvtools {
@ -37,23 +37,25 @@ class TransformationAddGlobalVariable : public Transformation {
// class // class
// - |message_.initializer_id| must either be 0 or the id of a constant whose // - |message_.initializer_id| must either be 0 or the id of a constant whose
// type is the pointee type of |message_.type_id| // type is the pointee type of |message_.type_id|
bool IsApplicable(opt::IRContext* context, bool IsApplicable(
const FactManager& fact_manager) const override; opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Adds a global variable with Private storage class to the module, with type // Adds a global variable with Private storage class to the module, with type
// |message_.type_id| and either no initializer or |message_.initializer_id| // |message_.type_id| and either no initializer or |message_.initializer_id|
// as an initializer, depending on whether |message_.initializer_id| is 0. // as an initializer, depending on whether |message_.initializer_id| is 0.
// The global variable has result id |message_.fresh_id|. // The global variable has result id |message_.fresh_id|.
// //
// If |message_.value_is_irrelevant| holds, adds a corresponding fact to // If |message_.value_is_irrelevant| holds, adds a corresponding fact to the
// |fact_manager|. // fact manager in |transformation_context|.
void Apply(opt::IRContext* context, FactManager* fact_manager) const override; void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
protobufs::Transformation ToMessage() const override; protobufs::Transformation ToMessage() const override;
private: private:
static bool PrivateGlobalsMustBeDeclaredInEntryPointInterfaces( static bool PrivateGlobalsMustBeDeclaredInEntryPointInterfaces(
opt::IRContext* context); opt::IRContext* ir_context);
protobufs::TransformationAddGlobalVariable message_; protobufs::TransformationAddGlobalVariable message_;
}; };

View File

@ -34,23 +34,22 @@ TransformationAddLocalVariable::TransformationAddLocalVariable(
} }
bool TransformationAddLocalVariable::IsApplicable( bool TransformationAddLocalVariable::IsApplicable(
opt::IRContext* context, opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
const spvtools::fuzz::FactManager& /*unused*/) const {
// The provided id must be fresh. // The provided id must be fresh.
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
return false; return false;
} }
// The pointer type id must indeed correspond to a pointer, and it must have // The pointer type id must indeed correspond to a pointer, and it must have
// function storage class. // function storage class.
auto type_instruction = auto type_instruction =
context->get_def_use_mgr()->GetDef(message_.type_id()); ir_context->get_def_use_mgr()->GetDef(message_.type_id());
if (!type_instruction || type_instruction->opcode() != SpvOpTypePointer || if (!type_instruction || type_instruction->opcode() != SpvOpTypePointer ||
type_instruction->GetSingleWordInOperand(0) != SpvStorageClassFunction) { type_instruction->GetSingleWordInOperand(0) != SpvStorageClassFunction) {
return false; return false;
} }
// The initializer must... // The initializer must...
auto initializer_instruction = auto initializer_instruction =
context->get_def_use_mgr()->GetDef(message_.initializer_id()); ir_context->get_def_use_mgr()->GetDef(message_.initializer_id());
// ... exist, ... // ... exist, ...
if (!initializer_instruction) { if (!initializer_instruction) {
return false; return false;
@ -65,17 +64,18 @@ bool TransformationAddLocalVariable::IsApplicable(
return false; return false;
} }
// The function to which the local variable is to be added must exist. // The function to which the local variable is to be added must exist.
return fuzzerutil::FindFunction(context, message_.function_id()); return fuzzerutil::FindFunction(ir_context, message_.function_id());
} }
void TransformationAddLocalVariable::Apply( void TransformationAddLocalVariable::Apply(
opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const { opt::IRContext* ir_context,
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); TransformationContext* transformation_context) const {
fuzzerutil::FindFunction(context, message_.function_id()) fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
fuzzerutil::FindFunction(ir_context, message_.function_id())
->begin() ->begin()
->begin() ->begin()
->InsertBefore(MakeUnique<opt::Instruction>( ->InsertBefore(MakeUnique<opt::Instruction>(
context, SpvOpVariable, message_.type_id(), message_.fresh_id(), ir_context, SpvOpVariable, message_.type_id(), message_.fresh_id(),
opt::Instruction::OperandList( opt::Instruction::OperandList(
{{SPV_OPERAND_TYPE_STORAGE_CLASS, {{SPV_OPERAND_TYPE_STORAGE_CLASS,
{ {
@ -83,9 +83,10 @@ void TransformationAddLocalVariable::Apply(
SpvStorageClassFunction}}, SpvStorageClassFunction}},
{SPV_OPERAND_TYPE_ID, {message_.initializer_id()}}}))); {SPV_OPERAND_TYPE_ID, {message_.initializer_id()}}})));
if (message_.value_is_irrelevant()) { if (message_.value_is_irrelevant()) {
fact_manager->AddFactValueOfPointeeIsIrrelevant(message_.fresh_id()); transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
message_.fresh_id());
} }
context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
} }
protobufs::Transformation TransformationAddLocalVariable::ToMessage() const { protobufs::Transformation TransformationAddLocalVariable::ToMessage() const {

View File

@ -15,9 +15,9 @@
#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_LOCAL_VARIABLE_H_ #ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_LOCAL_VARIABLE_H_
#define SOURCE_FUZZ_TRANSFORMATION_ADD_LOCAL_VARIABLE_H_ #define SOURCE_FUZZ_TRANSFORMATION_ADD_LOCAL_VARIABLE_H_
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h" #include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
namespace spvtools { namespace spvtools {
@ -38,15 +38,17 @@ class TransformationAddLocalVariable : public Transformation {
// - |message_.initializer_id| must be the id of a constant with the same // - |message_.initializer_id| must be the id of a constant with the same
// type as the pointer's pointee type // type as the pointer's pointee type
// - |message_.function_id| must be the id of a function // - |message_.function_id| must be the id of a function
bool IsApplicable(opt::IRContext* context, bool IsApplicable(
const FactManager& fact_manager) const override; opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Adds an instruction to the start of |message_.function_id|, of the form: // Adds an instruction to the start of |message_.function_id|, of the form:
// |message_.fresh_id| = OpVariable |message_.type_id| Function // |message_.fresh_id| = OpVariable |message_.type_id| Function
// |message_.initializer_id| // |message_.initializer_id|
// If |message_.value_is_irrelevant| holds, adds a corresponding fact to // If |message_.value_is_irrelevant| holds, adds a corresponding fact to the
// |fact_manager|. // fact manager in |transformation_context|.
void Apply(opt::IRContext* context, FactManager* fact_manager) const override; void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
protobufs::Transformation ToMessage() const override; protobufs::Transformation ToMessage() const override;

View File

@ -31,10 +31,9 @@ TransformationAddNoContractionDecoration::
} }
bool TransformationAddNoContractionDecoration::IsApplicable( bool TransformationAddNoContractionDecoration::IsApplicable(
opt::IRContext* context, opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
const spvtools::fuzz::FactManager& /*unused*/) const {
// |message_.result_id| must be the id of an instruction. // |message_.result_id| must be the id of an instruction.
auto instr = context->get_def_use_mgr()->GetDef(message_.result_id()); auto instr = ir_context->get_def_use_mgr()->GetDef(message_.result_id());
if (!instr) { if (!instr) {
return false; return false;
} }
@ -43,10 +42,10 @@ bool TransformationAddNoContractionDecoration::IsApplicable(
} }
void TransformationAddNoContractionDecoration::Apply( void TransformationAddNoContractionDecoration::Apply(
opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
// Add a NoContraction decoration targeting |message_.result_id|. // Add a NoContraction decoration targeting |message_.result_id|.
context->get_decoration_mgr()->AddDecoration(message_.result_id(), ir_context->get_decoration_mgr()->AddDecoration(message_.result_id(),
SpvDecorationNoContraction); SpvDecorationNoContraction);
} }
protobufs::Transformation TransformationAddNoContractionDecoration::ToMessage() protobufs::Transformation TransformationAddNoContractionDecoration::ToMessage()

View File

@ -15,9 +15,9 @@
#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_NO_CONTRACTION_DECORATION_H_ #ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_NO_CONTRACTION_DECORATION_H_
#define SOURCE_FUZZ_TRANSFORMATION_ADD_NO_CONTRACTION_DECORATION_H_ #define SOURCE_FUZZ_TRANSFORMATION_ADD_NO_CONTRACTION_DECORATION_H_
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h" #include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
namespace spvtools { namespace spvtools {
@ -34,13 +34,15 @@ class TransformationAddNoContractionDecoration : public Transformation {
// as defined by the SPIR-V specification. // as defined by the SPIR-V specification.
// - It does not matter whether this instruction is already annotated with the // - It does not matter whether this instruction is already annotated with the
// NoContraction decoration. // NoContraction decoration.
bool IsApplicable(opt::IRContext* context, bool IsApplicable(
const FactManager& fact_manager) const override; opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Adds a decoration of the form: // Adds a decoration of the form:
// 'OpDecoration |message_.result_id| NoContraction' // 'OpDecoration |message_.result_id| NoContraction'
// to the module. // to the module.
void Apply(opt::IRContext* context, FactManager* fact_manager) const override; void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
protobufs::Transformation ToMessage() const override; protobufs::Transformation ToMessage() const override;

View File

@ -32,21 +32,20 @@ TransformationAddTypeArray::TransformationAddTypeArray(uint32_t fresh_id,
} }
bool TransformationAddTypeArray::IsApplicable( bool TransformationAddTypeArray::IsApplicable(
opt::IRContext* context, opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
const spvtools::fuzz::FactManager& /*unused*/) const {
// A fresh id is required. // A fresh id is required.
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
return false; return false;
} }
auto element_type = auto element_type =
context->get_type_mgr()->GetType(message_.element_type_id()); ir_context->get_type_mgr()->GetType(message_.element_type_id());
if (!element_type || element_type->AsFunction()) { if (!element_type || element_type->AsFunction()) {
// The element type id either does not refer to a type, or refers to a // The element type id either does not refer to a type, or refers to a
// function type; both are illegal. // function type; both are illegal.
return false; return false;
} }
auto constant = auto constant =
context->get_constant_mgr()->GetConstantsFromIds({message_.size_id()}); ir_context->get_constant_mgr()->GetConstantsFromIds({message_.size_id()});
if (constant.empty()) { if (constant.empty()) {
// The size id does not refer to a constant. // The size id does not refer to a constant.
return false; return false;
@ -66,16 +65,17 @@ bool TransformationAddTypeArray::IsApplicable(
} }
void TransformationAddTypeArray::Apply( void TransformationAddTypeArray::Apply(
opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
opt::Instruction::OperandList in_operands; opt::Instruction::OperandList in_operands;
in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.element_type_id()}}); in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.element_type_id()}});
in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.size_id()}}); in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.size_id()}});
context->module()->AddType(MakeUnique<opt::Instruction>( ir_context->module()->AddType(MakeUnique<opt::Instruction>(
context, SpvOpTypeArray, 0, message_.fresh_id(), in_operands)); ir_context, SpvOpTypeArray, 0, message_.fresh_id(), in_operands));
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
// We have added an instruction to the module, so need to be careful about the // We have added an instruction to the module, so need to be careful about the
// validity of existing analyses. // validity of existing analyses.
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
} }
protobufs::Transformation TransformationAddTypeArray::ToMessage() const { protobufs::Transformation TransformationAddTypeArray::ToMessage() const {

View File

@ -15,9 +15,9 @@
#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_ARRAY_H_ #ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_ARRAY_H_
#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_ARRAY_H_ #define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_ARRAY_H_
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h" #include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
namespace spvtools { namespace spvtools {
@ -35,13 +35,15 @@ class TransformationAddTypeArray : public Transformation {
// - |message_.element_type_id| must be the id of a non-function type // - |message_.element_type_id| must be the id of a non-function type
// - |message_.size_id| must be the id of a 32-bit integer constant that is // - |message_.size_id| must be the id of a 32-bit integer constant that is
// positive when interpreted as signed. // positive when interpreted as signed.
bool IsApplicable(opt::IRContext* context, bool IsApplicable(
const FactManager& fact_manager) const override; opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Adds an OpTypeArray instruction to the module, with element type given by // Adds an OpTypeArray instruction to the module, with element type given by
// |message_.element_type_id| and size given by |message_.size_id|. The // |message_.element_type_id| and size given by |message_.size_id|. The
// result id of the instruction is |message_.fresh_id|. // result id of the instruction is |message_.fresh_id|.
void Apply(opt::IRContext* context, FactManager* fact_manager) const override; void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
protobufs::Transformation ToMessage() const override; protobufs::Transformation ToMessage() const override;

View File

@ -28,27 +28,27 @@ TransformationAddTypeBoolean::TransformationAddTypeBoolean(uint32_t fresh_id) {
} }
bool TransformationAddTypeBoolean::IsApplicable( bool TransformationAddTypeBoolean::IsApplicable(
opt::IRContext* context, opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
const spvtools::fuzz::FactManager& /*unused*/) const {
// The id must be fresh. // The id must be fresh.
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
return false; return false;
} }
// Applicable if there is no bool type already declared in the module. // Applicable if there is no bool type already declared in the module.
opt::analysis::Bool bool_type; opt::analysis::Bool bool_type;
return context->get_type_mgr()->GetId(&bool_type) == 0; return ir_context->get_type_mgr()->GetId(&bool_type) == 0;
} }
void TransformationAddTypeBoolean::Apply( void TransformationAddTypeBoolean::Apply(
opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
opt::Instruction::OperandList empty_operands; opt::Instruction::OperandList empty_operands;
context->module()->AddType(MakeUnique<opt::Instruction>( ir_context->module()->AddType(MakeUnique<opt::Instruction>(
context, SpvOpTypeBool, 0, message_.fresh_id(), empty_operands)); ir_context, SpvOpTypeBool, 0, message_.fresh_id(), empty_operands));
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
// We have added an instruction to the module, so need to be careful about the // We have added an instruction to the module, so need to be careful about the
// validity of existing analyses. // validity of existing analyses.
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
} }
protobufs::Transformation TransformationAddTypeBoolean::ToMessage() const { protobufs::Transformation TransformationAddTypeBoolean::ToMessage() const {

View File

@ -15,7 +15,6 @@
#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_BOOLEAN_H_ #ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_BOOLEAN_H_
#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_BOOLEAN_H_ #define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_BOOLEAN_H_
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h" #include "source/fuzz/transformation.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
@ -32,11 +31,13 @@ class TransformationAddTypeBoolean : public Transformation {
// - |message_.fresh_id| must not be used by the module. // - |message_.fresh_id| must not be used by the module.
// - The module must not yet declare OpTypeBoolean // - The module must not yet declare OpTypeBoolean
bool IsApplicable(opt::IRContext* context, bool IsApplicable(
const FactManager& fact_manager) const override; opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Adds OpTypeBoolean with |message_.fresh_id| as result id. // Adds OpTypeBoolean with |message_.fresh_id| as result id.
void Apply(opt::IRContext* context, FactManager* fact_manager) const override; void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
protobufs::Transformation ToMessage() const override; protobufs::Transformation ToMessage() const override;

View File

@ -30,29 +30,29 @@ TransformationAddTypeFloat::TransformationAddTypeFloat(
: message_(message) {} : message_(message) {}
bool TransformationAddTypeFloat::IsApplicable( bool TransformationAddTypeFloat::IsApplicable(
opt::IRContext* context, opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
const spvtools::fuzz::FactManager& /*unused*/) const {
// The id must be fresh. // The id must be fresh.
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
return false; return false;
} }
// Applicable if there is no float type with this width already declared in // Applicable if there is no float type with this width already declared in
// the module. // the module.
opt::analysis::Float float_type(message_.width()); opt::analysis::Float float_type(message_.width());
return context->get_type_mgr()->GetId(&float_type) == 0; return ir_context->get_type_mgr()->GetId(&float_type) == 0;
} }
void TransformationAddTypeFloat::Apply( void TransformationAddTypeFloat::Apply(
opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
opt::Instruction::OperandList width = { opt::Instruction::OperandList width = {
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.width()}}}; {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.width()}}};
context->module()->AddType(MakeUnique<opt::Instruction>( ir_context->module()->AddType(MakeUnique<opt::Instruction>(
context, SpvOpTypeFloat, 0, message_.fresh_id(), width)); ir_context, SpvOpTypeFloat, 0, message_.fresh_id(), width));
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
// We have added an instruction to the module, so need to be careful about the // We have added an instruction to the module, so need to be careful about the
// validity of existing analyses. // validity of existing analyses.
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
} }
protobufs::Transformation TransformationAddTypeFloat::ToMessage() const { protobufs::Transformation TransformationAddTypeFloat::ToMessage() const {

View File

@ -15,9 +15,9 @@
#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FLOAT_H_ #ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FLOAT_H_
#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FLOAT_H_ #define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FLOAT_H_
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h" #include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h" #include "source/opt/ir_context.h"
namespace spvtools { namespace spvtools {
@ -33,11 +33,13 @@ class TransformationAddTypeFloat : public Transformation {
// - |message_.fresh_id| must not be used by the module // - |message_.fresh_id| must not be used by the module
// - The module must not contain an OpTypeFloat instruction with width // - The module must not contain an OpTypeFloat instruction with width
// |message_.width| // |message_.width|
bool IsApplicable(opt::IRContext* context, bool IsApplicable(
const FactManager& fact_manager) const override; opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Adds an OpTypeFloat instruction to the module with the given width // Adds an OpTypeFloat instruction to the module with the given width
void Apply(opt::IRContext* context, FactManager* fact_manager) const override; void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
protobufs::Transformation ToMessage() const override; protobufs::Transformation ToMessage() const override;

View File

@ -36,19 +36,18 @@ TransformationAddTypeFunction::TransformationAddTypeFunction(
} }
bool TransformationAddTypeFunction::IsApplicable( bool TransformationAddTypeFunction::IsApplicable(
opt::IRContext* context, opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
const spvtools::fuzz::FactManager& /*unused*/) const {
// The result id must be fresh. // The result id must be fresh.
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
return false; return false;
} }
// The return and argument types must be type ids but not not be function // The return and argument types must be type ids but not not be function
// type ids. // type ids.
if (!fuzzerutil::IsNonFunctionTypeId(context, message_.return_type_id())) { if (!fuzzerutil::IsNonFunctionTypeId(ir_context, message_.return_type_id())) {
return false; return false;
} }
for (auto argument_type_id : message_.argument_type_id()) { for (auto argument_type_id : message_.argument_type_id()) {
if (!fuzzerutil::IsNonFunctionTypeId(context, argument_type_id)) { if (!fuzzerutil::IsNonFunctionTypeId(ir_context, argument_type_id)) {
return false; return false;
} }
} }
@ -56,7 +55,7 @@ bool TransformationAddTypeFunction::IsApplicable(
// exactly the same return and argument type ids. (Note that the type manager // exactly the same return and argument type ids. (Note that the type manager
// does not allow us to check this, as it does not distinguish between // does not allow us to check this, as it does not distinguish between
// function types with different but isomorphic pointer argument types.) // function types with different but isomorphic pointer argument types.)
for (auto& inst : context->module()->types_values()) { for (auto& inst : ir_context->module()->types_values()) {
if (inst.opcode() != SpvOpTypeFunction) { if (inst.opcode() != SpvOpTypeFunction) {
// Consider only OpTypeFunction instructions. // Consider only OpTypeFunction instructions.
continue; continue;
@ -89,18 +88,19 @@ bool TransformationAddTypeFunction::IsApplicable(
} }
void TransformationAddTypeFunction::Apply( void TransformationAddTypeFunction::Apply(
opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
opt::Instruction::OperandList in_operands; opt::Instruction::OperandList in_operands;
in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.return_type_id()}}); in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.return_type_id()}});
for (auto argument_type_id : message_.argument_type_id()) { for (auto argument_type_id : message_.argument_type_id()) {
in_operands.push_back({SPV_OPERAND_TYPE_ID, {argument_type_id}}); in_operands.push_back({SPV_OPERAND_TYPE_ID, {argument_type_id}});
} }
context->module()->AddType(MakeUnique<opt::Instruction>( ir_context->module()->AddType(MakeUnique<opt::Instruction>(
context, SpvOpTypeFunction, 0, message_.fresh_id(), in_operands)); ir_context, SpvOpTypeFunction, 0, message_.fresh_id(), in_operands));
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
// We have added an instruction to the module, so need to be careful about the // We have added an instruction to the module, so need to be careful about the
// validity of existing analyses. // validity of existing analyses.
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
} }
protobufs::Transformation TransformationAddTypeFunction::ToMessage() const { protobufs::Transformation TransformationAddTypeFunction::ToMessage() const {

Some files were not shown because too many files have changed in this diff Show More