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_composite_construct.h
transformation_composite_extract.h
transformation_context.h
transformation_copy_object.h
transformation_equation_instruction.h
transformation_function_call.h
@ -190,6 +191,7 @@ if(SPIRV_BUILD_FUZZER)
transformation_add_type_vector.cpp
transformation_composite_construct.cpp
transformation_composite_extract.cpp
transformation_context.cpp
transformation_copy_object.cpp
transformation_equation_instruction.cpp
transformation_function_call.cpp

View File

@ -17,6 +17,7 @@
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/instruction_descriptor.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/uniform_buffer_element_descriptor.h"
#include "source/opt/build_module.h"
@ -159,7 +160,8 @@ MakeConstantUniformReplacement(opt::IRContext* ir_context,
} // namespace
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,
std::vector<uint32_t>* binary_out) {
auto message_consumer = spvtools::utils::CLIMessageConsumer;
@ -171,7 +173,7 @@ bool ForceRenderRed(
}
// 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, {},
"Initial binary is invalid; stopping.");
return false;
@ -187,6 +189,8 @@ bool ForceRenderRed(
for (auto& fact : initial_facts.fact()) {
fact_manager.AddFact(fact, ir_context.get());
}
TransformationContext transformation_context(&fact_manager,
validator_options);
auto entry_point_function =
FindFragmentShaderEntryPoint(ir_context.get(), message_consumer);
@ -355,8 +359,9 @@ bool ForceRenderRed(
for (auto& replacement : {first_greater_then_operand_replacement.get(),
second_greater_then_operand_replacement.get()}) {
if (replacement) {
assert(replacement->IsApplicable(ir_context.get(), fact_manager));
replacement->Apply(ir_context.get(), &fact_manager);
assert(replacement->IsApplicable(ir_context.get(),
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
// which it is known that 'u < v' holds.
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,
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/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/pseudo_random_generator.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/build_module.h"
#include "source/spirv_fuzzer_options.h"
#include "source/util/make_unique.h"
@ -66,19 +67,19 @@ const uint32_t kTransformationLimit = 500;
const uint32_t kChanceOfApplyingAnotherPass = 85;
// 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
// |transformation_sequence_out| as parameters. Extra arguments can be provided
// via |extra_args|.
// All fuzzer passes take |ir_context|, |transformation_context|,
// |fuzzer_context| and |transformation_sequence_out| as parameters. Extra
// arguments can be provided via |extra_args|.
template <typename T, typename... Args>
void MaybeAddPass(
std::vector<std::unique_ptr<FuzzerPass>>* passes,
opt::IRContext* ir_context, FactManager* fact_manager,
opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformation_sequence_out,
Args&&... extra_args) {
if (fuzzer_context->ChooseEven()) {
passes->push_back(MakeUnique<T>(ir_context, fact_manager, fuzzer_context,
transformation_sequence_out,
passes->push_back(MakeUnique<T>(ir_context, transformation_context,
fuzzer_context, transformation_sequence_out,
std::forward<Args>(extra_args)...));
}
}
@ -182,11 +183,13 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
FactManager fact_manager;
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
// present, such as boolean constants.
FuzzerPassAddUsefulConstructs add_useful_constructs(
ir_context.get(), &fact_manager, &fuzzer_context,
ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
if (!impl_->ApplyPassAndCheckValidity(&add_useful_constructs, *ir_context,
tools)) {
@ -196,69 +199,69 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
// Apply some semantics-preserving passes.
std::vector<std::unique_ptr<FuzzerPass>> passes;
while (passes.empty()) {
MaybeAddPass<FuzzerPassAddAccessChains>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddCompositeTypes>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddDeadBlocks>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddDeadBreaks>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddDeadContinues>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddAccessChains>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddCompositeTypes>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddDeadBlocks>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddDeadBreaks>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddDeadContinues>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddEquationInstructions>(
&passes, ir_context.get(), &fact_manager, &fuzzer_context,
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddFunctionCalls>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddGlobalVariables>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddLoads>(&passes, ir_context.get(), &fact_manager,
&fuzzer_context,
MaybeAddPass<FuzzerPassAddFunctionCalls>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddGlobalVariables>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddLoads>(&passes, ir_context.get(),
&transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddLocalVariables>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddStores>(&passes, ir_context.get(), &fact_manager,
&fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassApplyIdSynonyms>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassConstructComposites>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassCopyObjects>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassDonateModules>(
&passes, ir_context.get(), &fact_manager, &fuzzer_context,
transformation_sequence_out, donor_suppliers);
MaybeAddPass<FuzzerPassMergeBlocks>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassObfuscateConstants>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassOutlineFunctions>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassPermuteBlocks>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassPermuteFunctionParameters>(
&passes, ir_context.get(), &fact_manager, &fuzzer_context,
MaybeAddPass<FuzzerPassAddLocalVariables>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddStores>(&passes, ir_context.get(),
&transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassApplyIdSynonyms>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassConstructComposites>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassCopyObjects>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassDonateModules>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out, donor_suppliers);
MaybeAddPass<FuzzerPassMergeBlocks>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassObfuscateConstants>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassOutlineFunctions>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassPermuteBlocks>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassPermuteFunctionParameters>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassSplitBlocks>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassSplitBlocks>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
}
bool is_first = true;
@ -279,25 +282,25 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
// as they do not unlock other passes.
std::vector<std::unique_ptr<FuzzerPass>> final_passes;
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);
MaybeAddPass<FuzzerPassAdjustLoopControls>(&final_passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAdjustMemoryOperandsMasks>(
&final_passes, ir_context.get(), &fact_manager, &fuzzer_context,
&final_passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAdjustSelectionControls>(
&final_passes, ir_context.get(), &fact_manager, &fuzzer_context,
&final_passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddNoContractionDecorations>(
&final_passes, ir_context.get(), &fact_manager, &fuzzer_context,
&final_passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassSwapCommutableOperands>(
&final_passes, ir_context.get(), &fact_manager, &fuzzer_context,
&final_passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassToggleAccessChainInstruction>(
&final_passes, ir_context.get(), &fact_manager, &fuzzer_context,
&final_passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
for (auto& pass : final_passes) {
if (!impl_->ApplyPassAndCheckValidity(pass.get(), *ir_context, tools)) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -21,10 +21,11 @@ namespace spvtools {
namespace fuzz {
FuzzerPassAddStores::FuzzerPassAddStores(
opt::IRContext* ir_context, FactManager* fact_manager,
opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
: FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAddStores::~FuzzerPassAddStores() = default;
@ -82,9 +83,13 @@ void FuzzerPassAddStores::Apply() {
default:
break;
}
return GetFactManager()->BlockIsDead(block->id()) ||
GetFactManager()->PointeeValueIsIrrelevant(
instruction->result_id());
return GetTransformationContext()
->GetFactManager()
->BlockIsDead(block->id()) ||
GetTransformationContext()
->GetFactManager()
->PointeeValueIsIrrelevant(
instruction->result_id());
});
// 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.
class FuzzerPassAddStores : public FuzzerPass {
public:
FuzzerPassAddStores(opt::IRContext* ir_context, FactManager* fact_manager,
FuzzerPassAddStores(opt::IRContext* ir_context,
TransformationContext* transformation_context,
FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -25,16 +25,19 @@ namespace spvtools {
namespace fuzz {
FuzzerPassApplyIdSynonyms::FuzzerPassApplyIdSynonyms(
opt::IRContext* ir_context, FactManager* fact_manager,
opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
: FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassApplyIdSynonyms::~FuzzerPassApplyIdSynonyms() = default;
void FuzzerPassApplyIdSynonyms::Apply() {
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
// iterate over these uses. We use this separation because, when
// 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;
for (auto& data_descriptor : GetFactManager()->GetSynonymsForId(
for (auto& data_descriptor :
GetTransformationContext()->GetFactManager()->GetSynonymsForId(
id_with_known_synonyms, GetIRContext())) {
protobufs::DataDescriptor descriptor_for_this_id =
MakeDataDescriptor(id_with_known_synonyms, {});

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -40,11 +40,12 @@ namespace spvtools {
namespace fuzz {
FuzzerPassDonateModules::FuzzerPassDonateModules(
opt::IRContext* ir_context, FactManager* fact_manager,
opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations,
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) {}
FuzzerPassDonateModules::~FuzzerPassDonateModules() = default;
@ -62,7 +63,9 @@ void FuzzerPassDonateModules::Apply() {
std::unique_ptr<opt::IRContext> donor_ir_context = donor_suppliers_.at(
GetFuzzerContext()->RandomIndex(donor_suppliers_))();
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");
// Donate the supplied module.
//

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -23,10 +23,11 @@ namespace spvtools {
namespace fuzz {
FuzzerPassSplitBlocks::FuzzerPassSplitBlocks(
opt::IRContext* ir_context, FactManager* fact_manager,
opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
: FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
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
// the block, we apply the split. Otherwise the block just doesn't get
// split.
if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) {
transformation.Apply(GetIRContext(), GetFactManager());
if (transformation.IsApplicable(GetIRContext(),
*GetTransformationContext())) {
transformation.Apply(GetIRContext(), GetTransformationContext());
*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.
class FuzzerPassSplitBlocks : public FuzzerPass {
public:
FuzzerPassSplitBlocks(opt::IRContext* ir_context, FactManager* fact_manager,
FuzzerPassSplitBlocks(opt::IRContext* ir_context,
TransformationContext* transformation_context,
FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations);

View File

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

View File

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

View File

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

View File

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

View File

@ -329,11 +329,11 @@ uint32_t GetArraySize(const opt::Instruction& array_type_instruction,
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;
context->module()->ToBinary(&binary, false);
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) {

View File

@ -132,8 +132,9 @@ uint32_t GetNumberOfStructMembers(
uint32_t GetArraySize(const opt::Instruction& array_type_instruction,
opt::IRContext* context);
// Returns true if and only if |context| is valid, according to the validator.
bool IsValid(opt::IRContext* context);
// Returns true if and only if |context| is valid, according to the validator
// 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
// parsing it again.

View File

@ -26,6 +26,7 @@
#include "source/fuzz/transformation_add_type_float.h"
#include "source/fuzz/transformation_add_type_int.h"
#include "source/fuzz/transformation_add_type_pointer.h"
#include "source/fuzz/transformation_context.h"
#include "source/fuzz/transformation_move_block_down.h"
#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
#include "source/fuzz/transformation_replace_constant_with_uniform.h"
@ -99,16 +100,19 @@ Replayer::ReplayerResultStatus Replayer::Run(
FactManager fact_manager;
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.
for (auto& message : transformation_sequence_in.transformation()) {
auto transformation = Transformation::FromMessage(message);
// 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
// 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;
if (impl_->validate_during_replay) {

View File

@ -195,9 +195,9 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
}
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) {
if (!fuzzerutil::IsFreshId(context, id)) {
if (!fuzzerutil::IsFreshId(ir_context, id)) {
return false;
}
if (ids_used_by_this_transformation->count(id) != 0) {

View File

@ -17,8 +17,8 @@
#include <memory>
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h"
namespace spvtools {
@ -60,19 +60,22 @@ class Transformation {
public:
// A precondition that determines whether the transformation can be cleanly
// 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
// associated header file using precise English. The fact manager is used to
// provide access to facts about the module that are known to be true, on
// associated header file using precise English. The transformation context
// provides access to facts about the module that are known to be true, on
// which the precondition may depend.
virtual bool IsApplicable(opt::IRContext* context,
const FactManager& fact_manager) const = 0;
virtual bool IsApplicable(
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const = 0;
// Requires that IsApplicable(context, fact_manager) holds. Applies the
// transformation, mutating |context| and possibly updating |fact_manager|
// with new facts established by the transformation.
virtual void Apply(opt::IRContext* context,
FactManager* fact_manager) const = 0;
// Requires that IsApplicable(ir_context, *transformation_context) holds.
// Applies the transformation, mutating |ir_context| and possibly updating
// |transformation_context| with new facts established by the transformation.
virtual void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const = 0;
// Turns the transformation into a protobuf message for serialization.
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
// must be distinct.
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);
};

View File

@ -40,19 +40,18 @@ TransformationAccessChain::TransformationAccessChain(
}
bool TransformationAccessChain::IsApplicable(
opt::IRContext* context,
const spvtools::fuzz::FactManager& /*unused*/) const {
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
// The result id must be fresh
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
return false;
}
// 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()) {
return false;
}
// 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) {
return false;
}
@ -60,7 +59,7 @@ bool TransformationAccessChain::IsApplicable(
// The described instruction to insert before must exist and be a suitable
// point where an OpAccessChain instruction could be inserted.
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) {
return false;
}
@ -86,7 +85,7 @@ bool TransformationAccessChain::IsApplicable(
// The pointer on which the access chain is to be based needs to be available
// (according to dominance rules) at the insertion point.
if (!fuzzerutil::IdIsAvailableBeforeInstruction(
context, instruction_to_insert_before, message_.pointer_id())) {
ir_context, instruction_to_insert_before, message_.pointer_id())) {
return false;
}
@ -104,7 +103,7 @@ bool TransformationAccessChain::IsApplicable(
// integer. Otherwise, the integer with which the id is associated is the
// second component.
std::pair<bool, uint32_t> maybe_index_value =
GetIndexValue(context, index_id);
GetIndexValue(ir_context, index_id);
if (!maybe_index_value.first) {
// There was no integer: this index is no good.
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
// the next type otherwise.
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) {
// Either the type was not a composite (so that too many indices were
// 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
// associated with pointers to isomorphic structs being regarded as the same.
return fuzzerutil::MaybeGetPointerType(
context, subobject_type_id,
ir_context, subobject_type_id,
static_cast<SpvStorageClass>(
pointer_type->GetSingleWordInOperand(0))) != 0;
}
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 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
@ -148,8 +148,8 @@ void TransformationAccessChain::Apply(
operands.push_back({SPV_OPERAND_TYPE_ID, {message_.pointer_id()}});
// Start walking the indices, starting with the pointer's base type.
auto pointer_type = context->get_def_use_mgr()->GetDef(
context->get_def_use_mgr()->GetDef(message_.pointer_id())->type_id());
auto pointer_type = ir_context->get_def_use_mgr()->GetDef(
ir_context->get_def_use_mgr()->GetDef(message_.pointer_id())->type_id());
uint32_t subobject_type_id = pointer_type->GetSingleWordInOperand(1);
// Go through the index ids in turn.
@ -157,33 +157,35 @@ void TransformationAccessChain::Apply(
// Add the index id to the operands.
operands.push_back({SPV_OPERAND_TYPE_ID, {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.
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
// was reached after following all indices. The storage class is that of the
// original pointer.
uint32_t result_type = fuzzerutil::MaybeGetPointerType(
context, subobject_type_id,
ir_context, subobject_type_id,
static_cast<SpvStorageClass>(pointer_type->GetSingleWordInOperand(0)));
// Add the access chain instruction to the module, and update the module's id
// bound.
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
FindInstruction(message_.instruction_to_insert_before(), context)
->InsertBefore(
MakeUnique<opt::Instruction>(context, SpvOpAccessChain, result_type,
message_.fresh_id(), operands));
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
FindInstruction(message_.instruction_to_insert_before(), ir_context)
->InsertBefore(MakeUnique<opt::Instruction>(
ir_context, SpvOpAccessChain, result_type, message_.fresh_id(),
operands));
// 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
// pointee value of the result of this access chain.
if (fact_manager->PointeeValueIsIrrelevant(message_.pointer_id())) {
fact_manager->AddFactValueOfPointeeIsIrrelevant(message_.fresh_id());
if (transformation_context->GetFactManager()->PointeeValueIsIrrelevant(
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(
opt::IRContext* context, uint32_t index_id) const {
auto index_instruction = context->get_def_use_mgr()->GetDef(index_id);
opt::IRContext* ir_context, uint32_t index_id) const {
auto index_instruction = ir_context->get_def_use_mgr()->GetDef(index_id);
if (!index_instruction || !spvOpcodeIsConstant(index_instruction->opcode())) {
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3179) We could
// 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};
}
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 ||
index_type->GetSingleWordInOperand(0) != 32) {
return {false, 0};

View File

@ -17,9 +17,9 @@
#include <utility>
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h"
namespace spvtools {
@ -47,8 +47,9 @@ class TransformationAccessChain : public Transformation {
// - 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
// class associated with |message_.pointer_id|
bool IsApplicable(opt::IRContext* context,
const FactManager& fact_manager) const override;
bool IsApplicable(
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Adds an instruction of the form:
// |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
// |message_.pointer_id|.
//
// If |fact_manager| reports that |message_.pointer_id| has an irrelevant
// pointee value, then the fact that |message_.fresh_id| (the result of the
// access chain) also has an irrelevant pointee value is also recorded.
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
// If the fact manager in |transformation_context| reports that
// |message_.pointer_id| has an irrelevant pointee value, then the fact that
// |message_.fresh_id| (the result of the access chain) also has an irrelevant
// pointee value is also recorded.
void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) 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
// constant. Otherwise, returns {true, value}, where value is the value of
// 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;
protobufs::TransformationAccessChain message_;

View File

@ -31,27 +31,28 @@ TransformationAddConstantBoolean::TransformationAddConstantBoolean(
}
bool TransformationAddConstantBoolean::IsApplicable(
opt::IRContext* context, const FactManager& /*unused*/) const {
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
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.
return false;
}
return fuzzerutil::IsFreshId(context, message_.fresh_id());
return fuzzerutil::IsFreshId(ir_context, message_.fresh_id());
}
void TransformationAddConstantBoolean::Apply(opt::IRContext* context,
FactManager* /*unused*/) const {
void TransformationAddConstantBoolean::Apply(
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
opt::analysis::Bool bool_type;
// Add the boolean constant to the module, ensuring the module's id bound is
// high enough.
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
context->module()->AddGlobalValue(
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
ir_context->module()->AddGlobalValue(
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
// validity of existing analyses.
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
}
protobufs::Transformation TransformationAddConstantBoolean::ToMessage() const {

View File

@ -15,9 +15,9 @@
#ifndef 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/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h"
namespace spvtools {
@ -32,12 +32,14 @@ class TransformationAddConstantBoolean : public Transformation {
// - |message_.fresh_id| must not be used by the module.
// - The module must already contain OpTypeBool.
bool IsApplicable(opt::IRContext* context,
const FactManager& fact_manager) const override;
bool IsApplicable(
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// - Adds OpConstantTrue (OpConstantFalse) to the module with id
// |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;

View File

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

View File

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

View File

@ -33,14 +33,13 @@ TransformationAddConstantScalar::TransformationAddConstantScalar(
}
bool TransformationAddConstantScalar::IsApplicable(
opt::IRContext* context,
const spvtools::fuzz::FactManager& /*unused*/) const {
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
// The id needs to be fresh.
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
return false;
}
// 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) {
return false;
}
@ -61,20 +60,21 @@ bool TransformationAddConstantScalar::IsApplicable(
}
void TransformationAddConstantScalar::Apply(
opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const {
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
opt::Instruction::OperandList operand_list;
for (auto word : message_.word()) {
operand_list.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {word}});
}
context->module()->AddGlobalValue(
MakeUnique<opt::Instruction>(context, SpvOpConstant, message_.type_id(),
message_.fresh_id(), operand_list));
ir_context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
ir_context, SpvOpConstant, message_.type_id(), message_.fresh_id(),
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
// validity of existing analyses.
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
}
protobufs::Transformation TransformationAddConstantScalar::ToMessage() const {

View File

@ -17,9 +17,9 @@
#include <vector>
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h"
namespace spvtools {
@ -37,11 +37,13 @@ class TransformationAddConstantScalar : public Transformation {
// - |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
// type
bool IsApplicable(opt::IRContext* context,
const FactManager& fact_manager) const override;
bool IsApplicable(
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// 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;

View File

@ -32,16 +32,15 @@ TransformationAddDeadBlock::TransformationAddDeadBlock(uint32_t fresh_id,
}
bool TransformationAddDeadBlock::IsApplicable(
opt::IRContext* context,
const spvtools::fuzz::FactManager& /*unused*/) const {
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
// 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;
}
// First, we check that a constant with the same value as
// |message_.condition_value| is present.
if (!fuzzerutil::MaybeGetBoolConstantId(context,
if (!fuzzerutil::MaybeGetBoolConstantId(ir_context,
message_.condition_value())) {
// The required constant is not present, so the transformation cannot be
// applied.
@ -50,7 +49,7 @@ bool TransformationAddDeadBlock::IsApplicable(
// The existing block must indeed exist.
auto existing_block =
fuzzerutil::MaybeFindBlock(context, message_.existing_block());
fuzzerutil::MaybeFindBlock(ir_context, message_.existing_block());
if (!existing_block) {
return false;
}
@ -68,13 +67,13 @@ bool TransformationAddDeadBlock::IsApplicable(
// Its successor must not be a merge block nor continue target.
auto successor_block_id =
existing_block->terminator()->GetSingleWordInOperand(0);
if (fuzzerutil::IsMergeOrContinue(context, successor_block_id)) {
if (fuzzerutil::IsMergeOrContinue(ir_context, successor_block_id)) {
return false;
}
// The successor must not be a loop header (i.e., |message_.existing_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;
}
@ -82,34 +81,36 @@ bool TransformationAddDeadBlock::IsApplicable(
}
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.
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
// 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 =
existing_block->terminator()->GetSingleWordInOperand(0);
// Get the id of the boolean value that will be used as the branch condition.
auto bool_id =
fuzzerutil::MaybeGetBoolConstantId(context, message_.condition_value());
auto bool_id = fuzzerutil::MaybeGetBoolConstantId(ir_context,
message_.condition_value());
// Make a new block that unconditionally branches to the original successor
// block.
auto enclosing_function = existing_block->GetParent();
std::unique_ptr<opt::BasicBlock> new_block = MakeUnique<opt::BasicBlock>(
MakeUnique<opt::Instruction>(context, SpvOpLabel, 0, message_.fresh_id(),
opt::Instruction::OperandList()));
std::unique_ptr<opt::BasicBlock> new_block =
MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
ir_context, SpvOpLabel, 0, message_.fresh_id(),
opt::Instruction::OperandList()));
new_block->AddInstruction(MakeUnique<opt::Instruction>(
context, SpvOpBranch, 0, 0,
ir_context, SpvOpBranch, 0, 0,
opt::Instruction::OperandList(
{{SPV_OPERAND_TYPE_ID, {successor_block_id}}})));
// Turn the original block into a selection merge, with its original successor
// as the merge block.
existing_block->terminator()->InsertBefore(MakeUnique<opt::Instruction>(
context, SpvOpSelectionMerge, 0, 0,
ir_context, SpvOpSelectionMerge, 0, 0,
opt::Instruction::OperandList(
{{SPV_OPERAND_TYPE_ID, {successor_block_id}},
{SPV_OPERAND_TYPE_SELECTION_CONTROL,
@ -135,7 +136,8 @@ void TransformationAddDeadBlock::Apply(
existing_block);
// 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
// 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
// construction. Other transformations can change these phi operands to more
// interesting values.
context->cfg()
ir_context->cfg()
->block(successor_block_id)
->ForEachPhiInst([this](opt::Instruction* phi_inst) {
// 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
// of the module has changed.
context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
}
protobufs::Transformation TransformationAddDeadBlock::ToMessage() const {

View File

@ -15,9 +15,9 @@
#ifndef 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/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h"
namespace spvtools {
@ -41,15 +41,17 @@ class TransformationAddDeadBlock : public Transformation {
// - |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
// associated loop header
bool IsApplicable(opt::IRContext* context,
const FactManager& fact_manager) const override;
bool IsApplicable(
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Changes the OpBranch from |message_.existing_block| to its successor 's'
// to an OpBranchConditional to either 's' or a new block,
// |message_.fresh_id|, which itself unconditionally branches to 's'. The
// conditional branch uses |message.condition_value| as its condition, and is
// 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;

View File

@ -14,8 +14,8 @@
#include "source/fuzz/transformation_add_dead_break.h"
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/fuzzer_util.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/basic_block.h"
#include "source/opt/ir_context.h"
#include "source/opt/struct_cfg_analysis.h"
@ -39,7 +39,7 @@ TransformationAddDeadBreak::TransformationAddDeadBreak(
}
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
// 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.
@ -70,7 +70,7 @@ bool TransformationAddDeadBreak::AddingBreakRespectsStructuredControlFlow(
// structured control flow construct.
auto containing_construct =
context->GetStructuredCFGAnalysis()->ContainingConstruct(
ir_context->GetStructuredCFGAnalysis()->ContainingConstruct(
message_.from_block());
if (!containing_construct) {
// |from_block| is not in a construct from which we can break.
@ -79,7 +79,7 @@ bool TransformationAddDeadBreak::AddingBreakRespectsStructuredControlFlow(
// Consider case (2)
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).
// 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
@ -90,28 +90,29 @@ bool TransformationAddDeadBreak::AddingBreakRespectsStructuredControlFlow(
// currently allow a dead break from a back edge block, but we could and
// ultimately should.
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
// innermost loop that contains |from_block|
auto containing_loop_header =
context->GetStructuredCFGAnalysis()->ContainingLoop(
ir_context->GetStructuredCFGAnalysis()->ContainingLoop(
message_.from_block());
if (containing_loop_header &&
message_.to_block() ==
context->cfg()->block(containing_loop_header)->MergeBlockId()) {
ir_context->cfg()->block(containing_loop_header)->MergeBlockId()) {
return !fuzzerutil::BlockIsInLoopContinueConstruct(
context, message_.from_block(), containing_loop_header);
ir_context, message_.from_block(), containing_loop_header);
}
return false;
}
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
// |message_.break_condition_value| is present.
if (!fuzzerutil::MaybeGetBoolConstantId(context,
if (!fuzzerutil::MaybeGetBoolConstantId(ir_context,
message_.break_condition_value())) {
// The required constant is not present, so the transformation cannot be
// applied.
@ -121,17 +122,17 @@ bool TransformationAddDeadBreak::IsApplicable(
// Check that |message_.from_block| and |message_.to_block| really are block
// ids
opt::BasicBlock* bb_from =
fuzzerutil::MaybeFindBlock(context, message_.from_block());
fuzzerutil::MaybeFindBlock(ir_context, message_.from_block());
if (bb_from == nullptr) {
return false;
}
opt::BasicBlock* bb_to =
fuzzerutil::MaybeFindBlock(context, message_.to_block());
fuzzerutil::MaybeFindBlock(ir_context, message_.to_block());
if (bb_to == nullptr) {
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
// allow adding a dead break, to avoid the compilations that arise due to
// 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.");
// 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())) {
return false;
}
// Check that adding the break would respect the rules of structured
// control flow.
if (!AddingBreakRespectsStructuredControlFlow(context, bb_from)) {
if (!AddingBreakRespectsStructuredControlFlow(ir_context, bb_from)) {
return false;
}
@ -177,16 +178,18 @@ bool TransformationAddDeadBreak::IsApplicable(
// being places on the validator. This should be revisited if we are sure
// the validator is complete with respect to checking structured control flow
// rules.
auto cloned_context = fuzzerutil::CloneIRContext(context);
auto cloned_context = fuzzerutil::CloneIRContext(ir_context);
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,
FactManager* /*unused*/) const {
ApplyImpl(context);
void TransformationAddDeadBreak::Apply(
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
ApplyImpl(ir_context);
// Invalidate all analyses
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
}
protobufs::Transformation TransformationAddDeadBreak::ToMessage() const {
@ -196,10 +199,10 @@ protobufs::Transformation TransformationAddDeadBreak::ToMessage() const {
}
void TransformationAddDeadBreak::ApplyImpl(
spvtools::opt::IRContext* context) const {
spvtools::opt::IRContext* ir_context) const {
fuzzerutil::AddUnreachableEdgeAndUpdateOpPhis(
context, context->cfg()->block(message_.from_block()),
context->cfg()->block(message_.to_block()),
ir_context, ir_context->cfg()->block(message_.from_block()),
ir_context->cfg()->block(message_.to_block()),
message_.break_condition_value(), message_.phi_id());
}

View File

@ -17,9 +17,9 @@
#include <vector>
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h"
namespace spvtools {
@ -50,21 +50,23 @@ class TransformationAddDeadBreak : public Transformation {
// maintain validity of the module.
// In particular, the new branch must not lead to violations of the rule
// that a use must be dominated by its definition.
bool IsApplicable(opt::IRContext* context,
const FactManager& fact_manager) const override;
bool IsApplicable(
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Replaces the terminator of a with a conditional branch to b or c.
// 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
// 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;
private:
// Returns true if and only if adding an edge from |bb_from| to
// |message_.to_block| respects structured control flow.
bool AddingBreakRespectsStructuredControlFlow(opt::IRContext* context,
bool AddingBreakRespectsStructuredControlFlow(opt::IRContext* ir_context,
opt::BasicBlock* bb_from) const;
// 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
// applicability checks have been made, ensuring that the invocation of this
// method is legal.
void ApplyImpl(opt::IRContext* context) const;
void ApplyImpl(opt::IRContext* ir_context) const;
protobufs::TransformationAddDeadBreak message_;
};

View File

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

View File

@ -17,9 +17,9 @@
#include <vector>
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h"
namespace spvtools {
@ -52,14 +52,16 @@ class TransformationAddDeadContinue : public Transformation {
// 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
// dominated by the definitions of those ids.
bool IsApplicable(opt::IRContext* context,
const FactManager& fact_manager) const override;
bool IsApplicable(
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Replaces the terminator of a with a conditional branch to b or c.
// 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
// 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;
@ -70,7 +72,7 @@ class TransformationAddDeadContinue : public Transformation {
// module. This is only invoked by 'IsApplicable' after certain basic
// applicability checks have been made, ensuring that the invocation of this
// method is legal.
void ApplyImpl(opt::IRContext* context) const;
void ApplyImpl(opt::IRContext* ir_context) const;
protobufs::TransformationAddDeadContinue message_;
};

View File

@ -56,8 +56,8 @@ TransformationAddFunction::TransformationAddFunction(
}
bool TransformationAddFunction::IsApplicable(
opt::IRContext* context,
const spvtools::fuzz::FactManager& fact_manager) const {
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const {
// This transformation may use a lot of ids, all of which need to be fresh
// and distinct. This set tracks them.
std::set<uint32_t> ids_used_by_this_transformation;
@ -66,7 +66,7 @@ bool TransformationAddFunction::IsApplicable(
for (auto& instruction : message_.instruction()) {
if (instruction.result_id()) {
if (!CheckIdIsFreshAndNotUsedByThisTransformation(
instruction.result_id(), context,
instruction.result_id(), ir_context,
&ids_used_by_this_transformation)) {
return false;
}
@ -77,28 +77,28 @@ bool TransformationAddFunction::IsApplicable(
// Ensure that all ids provided for making the function livesafe are fresh
// and distinct.
if (!CheckIdIsFreshAndNotUsedByThisTransformation(
message_.loop_limiter_variable_id(), context,
message_.loop_limiter_variable_id(), ir_context,
&ids_used_by_this_transformation)) {
return false;
}
for (auto& loop_limiter_info : message_.loop_limiter_info()) {
if (!CheckIdIsFreshAndNotUsedByThisTransformation(
loop_limiter_info.load_id(), context,
loop_limiter_info.load_id(), ir_context,
&ids_used_by_this_transformation)) {
return false;
}
if (!CheckIdIsFreshAndNotUsedByThisTransformation(
loop_limiter_info.increment_id(), context,
loop_limiter_info.increment_id(), ir_context,
&ids_used_by_this_transformation)) {
return false;
}
if (!CheckIdIsFreshAndNotUsedByThisTransformation(
loop_limiter_info.compare_id(), context,
loop_limiter_info.compare_id(), ir_context,
&ids_used_by_this_transformation)) {
return false;
}
if (!CheckIdIsFreshAndNotUsedByThisTransformation(
loop_limiter_info.logical_op_id(), context,
loop_limiter_info.logical_op_id(), ir_context,
&ids_used_by_this_transformation)) {
return false;
}
@ -107,11 +107,11 @@ bool TransformationAddFunction::IsApplicable(
message_.access_chain_clamping_info()) {
for (auto& pair : access_chain_clamping_info.compare_and_select_ids()) {
if (!CheckIdIsFreshAndNotUsedByThisTransformation(
pair.first(), context, &ids_used_by_this_transformation)) {
pair.first(), ir_context, &ids_used_by_this_transformation)) {
return false;
}
if (!CheckIdIsFreshAndNotUsedByThisTransformation(
pair.second(), context, &ids_used_by_this_transformation)) {
pair.second(), ir_context, &ids_used_by_this_transformation)) {
return false;
}
}
@ -123,8 +123,8 @@ bool TransformationAddFunction::IsApplicable(
// is taken here.
// We first clone the current module, so that we can try adding the new
// function without risking wrecking |context|.
auto cloned_module = fuzzerutil::CloneIRContext(context);
// function without risking wrecking |ir_context|.
auto cloned_module = fuzzerutil::CloneIRContext(ir_context);
// We try to add a function to the cloned module, which may fail if
// |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.
// 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;
}
if (message_.is_livesafe()) {
if (!TryToMakeFunctionLivesafe(cloned_module.get(), fact_manager)) {
if (!TryToMakeFunctionLivesafe(cloned_module.get(),
transformation_context)) {
return false;
}
// 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.
// It is simpler to rely on the validator to guard against this than to
// 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;
}
}
@ -156,10 +159,11 @@ bool TransformationAddFunction::IsApplicable(
}
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
// should succeed.
bool success = TryToAddFunction(context);
bool success = TryToAddFunction(ir_context);
assert(success && "The function should be successfully added.");
(void)(success); // Keep release builds happy (otherwise they may complain
// that |success| is not used).
@ -172,16 +176,16 @@ void TransformationAddFunction::Apply(
for (auto& instruction : message_.instruction()) {
switch (instruction.opcode()) {
case SpvOpFunctionParameter:
if (context->get_def_use_mgr()
if (ir_context->get_def_use_mgr()
->GetDef(instruction.result_type_id())
->opcode() == SpvOpTypePointer) {
fact_manager->AddFactValueOfPointeeIsIrrelevant(
instruction.result_id());
transformation_context->GetFactManager()
->AddFactValueOfPointeeIsIrrelevant(instruction.result_id());
}
break;
case SpvOpVariable:
fact_manager->AddFactValueOfPointeeIsIrrelevant(
instruction.result_id());
transformation_context->GetFactManager()
->AddFactValueOfPointeeIsIrrelevant(instruction.result_id());
break;
default:
break;
@ -190,7 +194,7 @@ void TransformationAddFunction::Apply(
if (message_.is_livesafe()) {
// 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.");
(void)(success); // Keep release builds happy.
@ -198,17 +202,18 @@ void TransformationAddFunction::Apply(
assert(message_.instruction(0).opcode() == SpvOpFunction &&
"The first instruction of an 'add function' transformation must be "
"OpFunction.");
fact_manager->AddFactFunctionIsLivesafe(
transformation_context->GetFactManager()->AddFactFunctionIsLivesafe(
message_.instruction(0).result_id());
} else {
// Inform the fact manager that all blocks in the function are dead.
for (auto& inst : message_.instruction()) {
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 {
@ -218,9 +223,9 @@ protobufs::Transformation TransformationAddFunction::ToMessage() const {
}
bool TransformationAddFunction::TryToAddFunction(
opt::IRContext* context) const {
opt::IRContext* ir_context) const {
// 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.
if (message_.instruction().empty()) {
@ -235,7 +240,7 @@ bool TransformationAddFunction::TryToAddFunction(
// Make a function, headed by the OpFunction instruction.
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
// considering.
@ -249,7 +254,7 @@ bool TransformationAddFunction::TryToAddFunction(
message_.instruction(instruction_index).opcode() ==
SpvOpFunctionParameter) {
new_function->AddParameter(InstructionFromMessage(
context, message_.instruction(instruction_index)));
ir_context, message_.instruction(instruction_index)));
instruction_index++;
}
@ -270,7 +275,7 @@ bool TransformationAddFunction::TryToAddFunction(
// as its parent.
std::unique_ptr<opt::BasicBlock> block =
MakeUnique<opt::BasicBlock>(InstructionFromMessage(
context, message_.instruction(instruction_index)));
ir_context, message_.instruction(instruction_index)));
block->SetParent(new_function.get());
// Consider successive instructions until we hit another label or the end
@ -281,7 +286,7 @@ bool TransformationAddFunction::TryToAddFunction(
SpvOpFunctionEnd &&
message_.instruction(instruction_index).opcode() != SpvOpLabel) {
block->AddInstruction(InstructionFromMessage(
context, message_.instruction(instruction_index)));
ir_context, message_.instruction(instruction_index)));
instruction_index++;
}
// 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
// report success.
new_function->SetFunctionEnd(
InstructionFromMessage(context, message_.instruction(instruction_index)));
context->AddFunction(std::move(new_function));
new_function->SetFunctionEnd(InstructionFromMessage(
ir_context, message_.instruction(instruction_index)));
ir_context->AddFunction(std::move(new_function));
context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
return true;
}
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.");
// Get a pointer to the added function.
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()) {
added_function = &function;
break;
@ -318,7 +324,7 @@ bool TransformationAddFunction::TryToMakeFunctionLivesafe(
}
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.
return false;
}
@ -332,20 +338,20 @@ bool TransformationAddFunction::TryToMakeFunctionLivesafe(
switch (inst.opcode()) {
case SpvOpKill:
case SpvOpUnreachable:
if (!TryToTurnKillOrUnreachableIntoReturn(context, added_function,
if (!TryToTurnKillOrUnreachableIntoReturn(ir_context, added_function,
&inst)) {
return false;
}
break;
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
if (!TryToClampAccessChainIndices(context, &inst)) {
if (!TryToClampAccessChainIndices(ir_context, &inst)) {
return false;
}
break;
case SpvOpFunctionCall:
// A livesafe function my only call other livesafe functions.
if (!fact_manager.FunctionIsLivesafe(
if (!transformation_context.GetFactManager()->FunctionIsLivesafe(
inst.GetSingleWordInOperand(0))) {
return false;
}
@ -358,7 +364,7 @@ bool TransformationAddFunction::TryToMakeFunctionLivesafe(
}
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
// limiting logic.
std::vector<opt::BasicBlock*> loop_headers;
@ -377,7 +383,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// manipulating a loop limiter.
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 ||
loop_limit_constant_id_instr->opcode() != SpvOpConstant) {
// The loop limit constant id instruction must exist and have an
@ -385,7 +391,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
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());
if (loop_limit_type->opcode() != SpvOpTypeInt ||
loop_limit_type->GetSingleWordInOperand(0) != 32) {
@ -397,36 +403,36 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// Find the id of the "unsigned int" type.
opt::analysis::Integer unsigned_int_type(32, false);
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) {
// Unsigned int is not available; we need this type in order to add loop
// limiters.
return false;
}
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.
opt::analysis::IntConstant zero(registered_unsigned_int_type->AsInteger(),
{0});
auto registered_zero = context->get_constant_mgr()->FindConstant(&zero);
auto registered_zero = ir_context->get_constant_mgr()->FindConstant(&zero);
if (!registered_zero) {
// We need 0 in order to be able to initialize loop limiters.
return false;
}
uint32_t zero_id = context->get_constant_mgr()
uint32_t zero_id = ir_context->get_constant_mgr()
->GetDefiningInstruction(registered_zero)
->result_id();
// Look for 1 of type unsigned int.
opt::analysis::IntConstant one(registered_unsigned_int_type->AsInteger(),
{1});
auto registered_one = context->get_constant_mgr()->FindConstant(&one);
auto registered_one = ir_context->get_constant_mgr()->FindConstant(&one);
if (!registered_one) {
// We need 1 in order to be able to increment loop limiters.
return false;
}
uint32_t one_id = context->get_constant_mgr()
uint32_t one_id = ir_context->get_constant_mgr()
->GetDefiningInstruction(registered_one)
->result_id();
@ -434,7 +440,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
opt::analysis::Pointer pointer_to_unsigned_int_type(
registered_unsigned_int_type, SpvStorageClassFunction);
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) {
// We need pointer-to-unsigned int in order to declare the loop limiter
// variable.
@ -443,7 +449,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// Look for 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) {
// We need bool in order to compare the loop limiter's value with the loop
// limit constant.
@ -454,22 +460,23 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// block, via an instruction of the form:
// %loop_limiter_var = SpvOpVariable %ptr_to_uint Function %zero
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(),
opt::Instruction::OperandList(
{{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}},
{SPV_OPERAND_TYPE_ID, {zero_id}}})));
// Update the module's id bound since we have added the loop limiter
// variable id.
fuzzerutil::UpdateModuleIdBound(context, message_.loop_limiter_variable_id());
fuzzerutil::UpdateModuleIdBound(ir_context,
message_.loop_limiter_variable_id());
// Consider each loop in turn.
for (auto loop_header : loop_headers) {
// Look for the loop's back-edge block. This is a predecessor of the loop
// header that is dominated by the loop header.
uint32_t back_edge_block_id = 0;
for (auto pred : context->cfg()->preds(loop_header->id())) {
if (context->GetDominatorAnalysis(added_function)
for (auto pred : ir_context->cfg()->preds(loop_header->id())) {
if (ir_context->GetDominatorAnalysis(added_function)
->Dominates(loop_header->id(), pred)) {
back_edge_block_id = pred;
break;
@ -481,7 +488,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// move on from this loop.
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
// corresponding to this loop.
@ -579,14 +586,15 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// Add a load from the loop limiter variable, of the form:
// %t1 = OpLoad %uint32 %loop_limiter
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(
{{SPV_OPERAND_TYPE_ID, {message_.loop_limiter_variable_id()}}})));
// Increment the loaded value:
// %t2 = OpIAdd %uint32 %t1 %one
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(),
opt::Instruction::OperandList(
{{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:
// OpStore %loop_limiter %t2
new_instructions.push_back(MakeUnique<opt::Instruction>(
context, SpvOpStore, 0, 0,
ir_context, SpvOpStore, 0, 0,
opt::Instruction::OperandList(
{{SPV_OPERAND_TYPE_ID, {message_.loop_limiter_variable_id()}},
{SPV_OPERAND_TYPE_ID, {loop_limiter_info.increment_id()}}})));
@ -605,7 +613,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// or
// %t3 = OpULessThan %bool %t1 %loop_limit
new_instructions.push_back(MakeUnique<opt::Instruction>(
context,
ir_context,
compare_using_greater_than_equal ? SpvOpUGreaterThanEqual
: SpvOpULessThan,
bool_type_id, loop_limiter_info.compare_id(),
@ -615,7 +623,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
if (back_edge_block_terminator->opcode() == SpvOpBranchConditional) {
new_instructions.push_back(MakeUnique<opt::Instruction>(
context,
ir_context,
compare_using_greater_than_equal ? SpvOpLogicalOr : SpvOpLogicalAnd,
bool_type_id, loop_limiter_info.logical_op_id(),
opt::Instruction::OperandList(
@ -644,8 +652,9 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// Check that, if the merge block starts with OpPhi instructions, suitable
// ids have been provided to give these instructions a value corresponding
// to the new incoming edge from the back edge block.
auto merge_block = context->cfg()->block(loop_header->MergeBlockId());
if (!fuzzerutil::PhiIdsOkForNewEdge(context, back_edge_block, merge_block,
auto merge_block = ir_context->cfg()->block(loop_header->MergeBlockId());
if (!fuzzerutil::PhiIdsOkForNewEdge(ir_context, back_edge_block,
merge_block,
loop_limiter_info.phi_id())) {
return false;
}
@ -681,16 +690,18 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
// Update the module's id bound with respect to the various ids that
// have been used for loop limiter manipulation.
fuzzerutil::UpdateModuleIdBound(context, loop_limiter_info.load_id());
fuzzerutil::UpdateModuleIdBound(context, loop_limiter_info.increment_id());
fuzzerutil::UpdateModuleIdBound(context, loop_limiter_info.compare_id());
fuzzerutil::UpdateModuleIdBound(context, loop_limiter_info.logical_op_id());
fuzzerutil::UpdateModuleIdBound(ir_context, loop_limiter_info.load_id());
fuzzerutil::UpdateModuleIdBound(ir_context,
loop_limiter_info.increment_id());
fuzzerutil::UpdateModuleIdBound(ir_context, loop_limiter_info.compare_id());
fuzzerutil::UpdateModuleIdBound(ir_context,
loop_limiter_info.logical_op_id());
}
return true;
}
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 {
assert((kill_or_unreachable_inst->opcode() == SpvOpKill ||
kill_or_unreachable_inst->opcode() == SpvOpUnreachable) &&
@ -698,7 +709,7 @@ bool TransformationAddFunction::TryToTurnKillOrUnreachableIntoReturn(
// Get the function's return type.
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) {
// 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
// specifically to turn OpKill and OpUnreachable instructions into
// 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())
->type_id() != function_return_type_inst->result_id()) {
return false;
@ -725,7 +736,7 @@ bool TransformationAddFunction::TryToTurnKillOrUnreachableIntoReturn(
}
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 ||
access_chain_inst->opcode() == SpvOpInBoundsAccessChain) &&
"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
// 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));
assert(base_object && "The base object must exist.");
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 &&
"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));
// 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
// columns of matrix or the size of an array.
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
// type.
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 =
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->GetSingleWordInOperand(0) == 32);
opt::analysis::Integer* index_int_type =
context->get_type_mgr()
ir_context->get_type_mgr()
->GetType(index_type_inst->result_id())
->AsInteger();
@ -805,20 +816,20 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
"Access chain indices into structures are required to be "
"constants.");
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.
return false;
}
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) {
// Bool type is not declared; we cannot do a comparison.
return false;
}
uint32_t bound_minus_one_id =
context->get_constant_mgr()
ir_context->get_constant_mgr()
->GetDefiningInstruction(&bound_minus_one)
->result_id();
@ -832,7 +843,7 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
// Compare the index with the bound via an instruction of the form:
// %t1 = OpULessThanEqual %bool %index %bound_minus_one
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(
{{SPV_OPERAND_TYPE_ID, {index_inst->result_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:
// %t2 = OpSelect %int_type %t1 %index %bound_minus_one
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(
{{SPV_OPERAND_TYPE_ID, {compare_id}},
{SPV_OPERAND_TYPE_ID, {index_inst->result_id()}},
@ -851,8 +862,8 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
// Replace %index with %t2.
access_chain_inst->SetInOperand(index, {select_id});
fuzzerutil::UpdateModuleIdBound(context, compare_id);
fuzzerutil::UpdateModuleIdBound(context, select_id);
fuzzerutil::UpdateModuleIdBound(ir_context, compare_id);
fuzzerutil::UpdateModuleIdBound(ir_context, select_id);
} else {
// 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
@ -870,16 +881,16 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
}
}
should_be_composite_type =
FollowCompositeIndex(context, *should_be_composite_type, index_id);
FollowCompositeIndex(ir_context, *should_be_composite_type, index_id);
}
return true;
}
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()) {
case SpvOpTypeArray:
return fuzzerutil::GetArraySize(composite_type_inst, context);
return fuzzerutil::GetArraySize(composite_type_inst, ir_context);
case SpvOpTypeMatrix:
case SpvOpTypeVector:
return composite_type_inst.GetSingleWordInOperand(1);
@ -893,7 +904,7 @@ uint32_t TransformationAddFunction::GetBoundForCompositeIndex(
}
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 sub_object_type_id;
switch (composite_type_inst.opcode()) {
@ -905,12 +916,12 @@ opt::Instruction* TransformationAddFunction::FollowCompositeIndex(
sub_object_type_id = composite_type_inst.GetSingleWordInOperand(0);
break;
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(
context->get_def_use_mgr()->GetDef(index_inst->type_id())->opcode() ==
SpvOpTypeInt);
assert(context->get_def_use_mgr()
assert(ir_context->get_def_use_mgr()
->GetDef(index_inst->type_id())
->opcode() == SpvOpTypeInt);
assert(ir_context->get_def_use_mgr()
->GetDef(index_inst->type_id())
->GetSingleWordInOperand(0) == 32);
uint32_t index_value = index_inst->GetSingleWordInOperand(0);
@ -924,7 +935,7 @@ opt::Instruction* TransformationAddFunction::FollowCompositeIndex(
break;
}
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

View File

@ -15,9 +15,9 @@
#ifndef 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/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h"
namespace spvtools {
@ -47,12 +47,14 @@ class TransformationAddFunction : public Transformation {
// ingredients to make the function livesafe, and the function must only
// invoke other livesafe functions
// - Adding the created function to the module must lead to a valid module.
bool IsApplicable(opt::IRContext* context,
const FactManager& fact_manager) const override;
bool IsApplicable(
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Adds the function defined by |message_.instruction| to the module, making
// 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;
@ -61,26 +63,26 @@ class TransformationAddFunction : public Transformation {
// an array, the number of components of a vector, or the number of columns of
// a matrix.
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
// type of the sub-object at index |index_id|, which is required to be in-
// bounds.
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);
private:
// 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
// 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
// indeterminate state.
// OpFunction instruction or no blocks; in this case |ir_context| is left in
// an indeterminate state.
//
// Otherwise returns true. Whether |context| is valid after addition of the
// function depends on the contents of |message_.instruction|.
// Otherwise returns true. Whether |ir_context| is valid after addition of
// the function depends on the contents of |message_.instruction|.
//
// Intended usage:
// - 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.
// - If the dry run succeeds, run the method on the real module of interest,
// 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
// the function livesafe (see FactFunctionIsLivesafe for a definition).
// Returns false if this is not possible, due to |message_| or |context| not
// containing sufficient ingredients (such as types and fresh ids) to add
// Returns false if this is not possible, due to |message_| or |ir_context|
// not containing sufficient ingredients (such as types and fresh ids) to add
// the instrumentation necessary to make the function livesafe.
bool TryToMakeFunctionLivesafe(opt::IRContext* context,
const FactManager& fact_manager) const;
bool TryToMakeFunctionLivesafe(
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const;
// A helper for TryToMakeFunctionLivesafe that tries to add loop-limiting
// logic.
bool TryToAddLoopLimiters(opt::IRContext* context,
bool TryToAddLoopLimiters(opt::IRContext* ir_context,
opt::Function* added_function) const;
// A helper for TryToMakeFunctionLivesafe that tries to replace OpKill and
// OpUnreachable instructions into return instructions.
bool TryToTurnKillOrUnreachableIntoReturn(
opt::IRContext* context, opt::Function* added_function,
opt::IRContext* ir_context, opt::Function* added_function,
opt::Instruction* kill_or_unreachable_inst) const;
// A helper for TryToMakeFunctionLivesafe that tries to clamp access chain
// 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;
protobufs::TransformationAddFunction message_;

View File

@ -30,26 +30,26 @@ TransformationAddGlobalUndef::TransformationAddGlobalUndef(uint32_t fresh_id,
}
bool TransformationAddGlobalUndef::IsApplicable(
opt::IRContext* context,
const spvtools::fuzz::FactManager& /*unused*/) const {
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
// A fresh id is required.
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
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.
return type && !type->AsFunction();
}
void TransformationAddGlobalUndef::Apply(
opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const {
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
context, SpvOpUndef, message_.type_id(), message_.fresh_id(),
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
ir_context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
ir_context, SpvOpUndef, message_.type_id(), message_.fresh_id(),
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
// validity of existing analyses.
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
}
protobufs::Transformation TransformationAddGlobalUndef::ToMessage() const {

View File

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

View File

@ -33,14 +33,13 @@ TransformationAddGlobalVariable::TransformationAddGlobalVariable(
}
bool TransformationAddGlobalVariable::IsApplicable(
opt::IRContext* context,
const spvtools::fuzz::FactManager& /*unused*/) const {
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
// The result id must be fresh.
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
return false;
}
// 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) {
return false;
}
@ -55,7 +54,7 @@ bool TransformationAddGlobalVariable::IsApplicable(
}
// The initializer id must be the id of a constant. Check this with the
// constant manager.
auto constant_id = context->get_constant_mgr()->GetConstantsFromIds(
auto constant_id = ir_context->get_constant_mgr()->GetConstantsFromIds(
{message_.initializer_id()});
if (constant_id.empty()) {
return false;
@ -71,7 +70,8 @@ bool TransformationAddGlobalVariable::IsApplicable(
}
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;
input_operands.push_back(
{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassPrivate}});
@ -79,12 +79,12 @@ void TransformationAddGlobalVariable::Apply(
input_operands.push_back(
{SPV_OPERAND_TYPE_ID, {message_.initializer_id()}});
}
context->module()->AddGlobalValue(
MakeUnique<opt::Instruction>(context, SpvOpVariable, message_.type_id(),
message_.fresh_id(), input_operands));
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
ir_context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
ir_context, SpvOpVariable, message_.type_id(), message_.fresh_id(),
input_operands));
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
// the module. This means that the global is available for other
// transformations to use.
@ -94,18 +94,20 @@ void TransformationAddGlobalVariable::Apply(
//
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3111) revisit
// 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()}});
}
}
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
// validity of existing analyses.
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
}
protobufs::Transformation TransformationAddGlobalVariable::ToMessage() const {
@ -116,11 +118,11 @@ protobufs::Transformation TransformationAddGlobalVariable::ToMessage() const {
bool TransformationAddGlobalVariable::
PrivateGlobalsMustBeDeclaredInEntryPointInterfaces(
opt::IRContext* context) {
opt::IRContext* ir_context) {
// TODO(afd): We capture the universal environments for which this requirement
// holds. The check should be refined on demand for other target
// environments.
switch (context->grammar().target_env()) {
switch (ir_context->grammar().target_env()) {
case SPV_ENV_UNIVERSAL_1_0:
case SPV_ENV_UNIVERSAL_1_1:
case SPV_ENV_UNIVERSAL_1_2:

View File

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

View File

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

View File

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

View File

@ -31,10 +31,9 @@ TransformationAddNoContractionDecoration::
}
bool TransformationAddNoContractionDecoration::IsApplicable(
opt::IRContext* context,
const spvtools::fuzz::FactManager& /*unused*/) const {
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
// |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) {
return false;
}
@ -43,10 +42,10 @@ bool TransformationAddNoContractionDecoration::IsApplicable(
}
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|.
context->get_decoration_mgr()->AddDecoration(message_.result_id(),
SpvDecorationNoContraction);
ir_context->get_decoration_mgr()->AddDecoration(message_.result_id(),
SpvDecorationNoContraction);
}
protobufs::Transformation TransformationAddNoContractionDecoration::ToMessage()

View File

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

View File

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

View File

@ -15,9 +15,9 @@
#ifndef 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/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h"
namespace spvtools {
@ -35,13 +35,15 @@ class TransformationAddTypeArray : public Transformation {
// - |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
// positive when interpreted as signed.
bool IsApplicable(opt::IRContext* context,
const FactManager& fact_manager) const override;
bool IsApplicable(
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Adds an OpTypeArray instruction to the module, with element type given by
// |message_.element_type_id| and size given by |message_.size_id|. The
// 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;

View File

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

View File

@ -15,7 +15,6 @@
#ifndef 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/transformation.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.
// - The module must not yet declare OpTypeBoolean
bool IsApplicable(opt::IRContext* context,
const FactManager& fact_manager) const override;
bool IsApplicable(
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// 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;

View File

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

View File

@ -15,9 +15,9 @@
#ifndef 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/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h"
namespace spvtools {
@ -33,11 +33,13 @@ class TransformationAddTypeFloat : public Transformation {
// - |message_.fresh_id| must not be used by the module
// - The module must not contain an OpTypeFloat instruction with width
// |message_.width|
bool IsApplicable(opt::IRContext* context,
const FactManager& fact_manager) const override;
bool IsApplicable(
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// 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;

View File

@ -36,19 +36,18 @@ TransformationAddTypeFunction::TransformationAddTypeFunction(
}
bool TransformationAddTypeFunction::IsApplicable(
opt::IRContext* context,
const spvtools::fuzz::FactManager& /*unused*/) const {
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
// The result id must be fresh.
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
return false;
}
// The return and argument types must be type ids but not not be function
// type ids.
if (!fuzzerutil::IsNonFunctionTypeId(context, message_.return_type_id())) {
if (!fuzzerutil::IsNonFunctionTypeId(ir_context, message_.return_type_id())) {
return false;
}
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;
}
}
@ -56,7 +55,7 @@ bool TransformationAddTypeFunction::IsApplicable(
// 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
// 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) {
// Consider only OpTypeFunction instructions.
continue;
@ -89,18 +88,19 @@ bool TransformationAddTypeFunction::IsApplicable(
}
void TransformationAddTypeFunction::Apply(
opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const {
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
opt::Instruction::OperandList in_operands;
in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.return_type_id()}});
for (auto argument_type_id : message_.argument_type_id()) {
in_operands.push_back({SPV_OPERAND_TYPE_ID, {argument_type_id}});
}
context->module()->AddType(MakeUnique<opt::Instruction>(
context, SpvOpTypeFunction, 0, message_.fresh_id(), in_operands));
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
ir_context->module()->AddType(MakeUnique<opt::Instruction>(
ir_context, SpvOpTypeFunction, 0, message_.fresh_id(), in_operands));
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
// We have added an instruction to the module, so need to be careful about the
// validity of existing analyses.
context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
ir_context->InvalidateAnalysesExceptFor(
opt::IRContext::Analysis::kAnalysisNone);
}
protobufs::Transformation TransformationAddTypeFunction::ToMessage() const {

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