diff options
Diffstat (limited to 'source')
351 files changed, 2419 insertions, 1780 deletions
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 65087f2c..8247f6f8 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -359,7 +359,7 @@ function(spirv_tools_default_target_options target) ) set_property(TARGET ${target} PROPERTY FOLDER "SPIRV-Tools libraries") spvtools_check_symbol_exports(${target}) - add_dependencies(${target} core_tables enum_string_mapping extinst_tables) + add_dependencies(${target} spirv-tools-build-version core_tables enum_string_mapping extinst_tables) endfunction() # Always build ${SPIRV_TOOLS}-shared. This is expected distro packages, and diff --git a/source/fuzz/CMakeLists.txt b/source/fuzz/CMakeLists.txt index d3aa9f1e..804fcf07 100644 --- a/source/fuzz/CMakeLists.txt +++ b/source/fuzz/CMakeLists.txt @@ -37,6 +37,7 @@ if(SPIRV_BUILD_FUZZER) set(SPIRV_TOOLS_FUZZ_SOURCES added_function_reducer.h + available_instructions.h call_graph.h comparator_deep_blocks_first.h counter_overflow_id_source.h @@ -229,6 +230,7 @@ if(SPIRV_BUILD_FUZZER) ${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.h added_function_reducer.cpp + available_instructions.cpp call_graph.cpp counter_overflow_id_source.cpp data_descriptor.cpp diff --git a/source/fuzz/available_instructions.cpp b/source/fuzz/available_instructions.cpp new file mode 100644 index 00000000..e25ed900 --- /dev/null +++ b/source/fuzz/available_instructions.cpp @@ -0,0 +1,191 @@ +// Copyright (c) 2021 Alastair F. Donaldson +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/available_instructions.h" +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +AvailableInstructions::AvailableInstructions( + opt::IRContext* ir_context, + const std::function<bool(opt::IRContext*, opt::Instruction*)>& predicate) + : ir_context_(ir_context) { + // Consider all global declarations + for (auto& global : ir_context->module()->types_values()) { + if (predicate(ir_context, &global)) { + available_globals_.push_back(&global); + } + } + + // Consider every function + for (auto& function : *ir_context->module()) { + // Identify those function parameters that satisfy the predicate. + std::vector<opt::Instruction*> available_params_for_function; + function.ForEachParam( + [&predicate, ir_context, + &available_params_for_function](opt::Instruction* param) { + if (predicate(ir_context, param)) { + available_params_for_function.push_back(param); + } + }); + + // Consider every reachable block in the function. + auto dominator_analysis = ir_context->GetDominatorAnalysis(&function); + for (auto& block : function) { + if (!fuzzerutil::BlockIsReachableInItsFunction(ir_context, &block)) { + // The block is not reachable. + continue; + } + if (&block == &*function.begin()) { + // The function entry block is special: only the relevant globals and + // function parameters are available at its entry point. + num_available_at_block_entry_.insert( + {&block, + static_cast<uint32_t>(available_params_for_function.size() + + available_globals_.size())}); + } else { + // |block| is not the entry block and is reachable, so it must have an + // immediate dominator. The number of instructions available on entry to + // |block| is thus the number of instructions available on entry to the + // immediate dominator + the number of instructions generated_by_block + // by the immediate dominator. + auto immediate_dominator = + dominator_analysis->ImmediateDominator(&block); + assert(immediate_dominator != nullptr && + "The block is reachable so should have an immediate dominator."); + assert(generated_by_block_.count(immediate_dominator) != 0 && + "Immediate dominator should have already been processed."); + assert(num_available_at_block_entry_.count(immediate_dominator) != 0 && + "Immediate dominator should have already been processed."); + num_available_at_block_entry_.insert( + {&block, + static_cast<uint32_t>( + generated_by_block_.at(immediate_dominator).size()) + + num_available_at_block_entry_.at(immediate_dominator)}); + } + // Now consider each instruction in the block. + std::vector<opt::Instruction*> generated_by_block; + for (auto& inst : block) { + assert(num_available_at_block_entry_.count(&block) != 0 && + "Block should have already been processed."); + // The number of available instructions before |inst| is the number + // available at the start of the block + the number of relevant + // instructions generated by the block so far. + num_available_before_instruction_.insert( + {&inst, num_available_at_block_entry_.at(&block) + + static_cast<uint32_t>(generated_by_block.size())}); + if (predicate(ir_context, &inst)) { + // This instruction satisfies the predicate, so note that it is + // generated by |block|. + generated_by_block.push_back(&inst); + } + } + generated_by_block_.emplace(&block, std::move(generated_by_block)); + } + available_params_.emplace(&function, + std::move(available_params_for_function)); + } +} + +AvailableInstructions::AvailableBeforeInstruction +AvailableInstructions::GetAvailableBeforeInstruction( + opt::Instruction* inst) const { + assert(num_available_before_instruction_.count(inst) != 0 && + "Availability can only be queried for reachable instructions."); + return {*this, inst}; +} + +AvailableInstructions::AvailableBeforeInstruction::AvailableBeforeInstruction( + const AvailableInstructions& available_instructions, opt::Instruction* inst) + : available_instructions_(available_instructions), inst_(inst) {} + +uint32_t AvailableInstructions::AvailableBeforeInstruction::size() const { + return available_instructions_.num_available_before_instruction_.at(inst_); +} + +bool AvailableInstructions::AvailableBeforeInstruction::empty() const { + return size() == 0; +} + +opt::Instruction* AvailableInstructions::AvailableBeforeInstruction::operator[]( + uint32_t index) const { + assert(index < size() && "Index out of bounds."); + + // First, check the cache to see whether we can return the available + // instruction in constant time. + auto cached_result = index_cache.find(index); + if (cached_result != index_cache.end()) { + return cached_result->second; + } + + // Next check whether the index falls into the global region. + if (index < available_instructions_.available_globals_.size()) { + auto result = available_instructions_.available_globals_[index]; + index_cache.insert({index, result}); + return result; + } + + auto block = available_instructions_.ir_context_->get_instr_block(inst_); + auto function = block->GetParent(); + + // Next check whether the index falls into the available instructions that + // correspond to function parameters. + if (index < + available_instructions_.available_globals_.size() + + available_instructions_.available_params_.at(function).size()) { + auto result = available_instructions_.available_params_.at( + function)[index - available_instructions_.available_globals_.size()]; + index_cache.insert({index, result}); + return result; + } + + auto dominator_analysis = + available_instructions_.ir_context_->GetDominatorAnalysis(function); + + // Now the expensive part (which is why we have the cache): walk the dominator + // tree backwards starting from the block containing |inst_| until we get to + // the block in which the instruction corresponding to |index| exists. + for (auto* ancestor = block; true; + ancestor = dominator_analysis->ImmediateDominator(ancestor)) { + uint32_t num_available_at_ancestor_entry = + available_instructions_.num_available_at_block_entry_.at(ancestor); + if (index_cache.count(num_available_at_ancestor_entry) == 0) { + // This is the first time we have traversed this block, so we populate the + // cache with the index of each instruction, so that if a future index + // query relates to indices associated with this block we can return the + // result in constant time. + auto& generated_by_ancestor = + available_instructions_.generated_by_block_.at(ancestor); + for (uint32_t local_index = 0; local_index < generated_by_ancestor.size(); + local_index++) { + index_cache.insert({num_available_at_ancestor_entry + local_index, + generated_by_ancestor[local_index]}); + } + } + if (index >= num_available_at_ancestor_entry) { + // This block contains the instruction we want, so by now it will be in + // the cache. + return index_cache.at(index); + } + assert(ancestor != &*function->begin() && + "By construction we should find a block associated with the index."); + } + + assert(false && "Unreachable."); + return nullptr; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/source/fuzz/available_instructions.h b/source/fuzz/available_instructions.h new file mode 100644 index 00000000..5c0b4175 --- /dev/null +++ b/source/fuzz/available_instructions.h @@ -0,0 +1,111 @@ +// Copyright (c) 2021 Alastair F. Donaldson +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_AVAILABLE_INSTRUCTIONS_H_ +#define SOURCE_FUZZ_AVAILABLE_INSTRUCTIONS_H_ + +#include <unordered_map> +#include <vector> + +#include "source/opt/instruction.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +// A class for allowing efficient querying of the instruction that satisfy a +// particular predicate that are available before a given instruction. +// Availability information is only computed for instructions in *reachable* +// basic blocks. +class AvailableInstructions { + public: + // The outer class captures availability information for a whole module, and + // each instance of this inner class captures availability for a particular + // instruction. + class AvailableBeforeInstruction { + public: + AvailableBeforeInstruction( + const AvailableInstructions& available_instructions, + opt::Instruction* inst); + + // Returns the number of instructions that are available before the + // instruction associated with this class. + uint32_t size() const; + + // Returns true if and only if |size()| is 0. + bool empty() const; + + // Requires |index| < |size()|. Returns the ith available instruction. + opt::Instruction* operator[](uint32_t index) const; + + private: + // A references to an instance of the outer class. + const AvailableInstructions& available_instructions_; + + // The instruction for which availability information is captured. + opt::Instruction* inst_; + + // A cache to improve the efficiency of the [] operator. The [] operator + // requires walking the instruction's dominator tree to find an instruction + // at a particular index, which is a linear time operation. By inserting all + // instructions that are traversed during this search into a cache, future + // lookups will take constant time unless they require traversing the + // dominator tree more deeply. + mutable std::unordered_map<uint32_t, opt::Instruction*> index_cache; + }; + + // Constructs availability instructions for |ir_context|, where instructions + // are only available if they satisfy |predicate|. + AvailableInstructions( + opt::IRContext* ir_context, + const std::function<bool(opt::IRContext*, opt::Instruction*)>& predicate); + + // Yields instruction availability for |inst|. + AvailableBeforeInstruction GetAvailableBeforeInstruction( + opt::Instruction* inst) const; + + private: + // The module in which all instructions are contained. + opt::IRContext* ir_context_; + + // The global instructions that satisfy the predicate. + std::vector<opt::Instruction*> available_globals_; + + // Per function, the parameters that satisfy the predicate. + std::unordered_map<opt::Function*, std::vector<opt::Instruction*>> + available_params_; + + // The number of instructions that satisfy the predicate and that are + // available at the entry to a block. For the entry block of a function this + // is the number of available globals + the number of available function + // parameters. For any other block it is the number of available instructions + // for the blocks immediate dominator + the number of instructions generated + // by the immediate dominator. + std::unordered_map<opt::BasicBlock*, uint32_t> num_available_at_block_entry_; + + // For each block this records those instructions in the block that satisfy + // the predicate. + std::unordered_map<opt::BasicBlock*, std::vector<opt::Instruction*>> + generated_by_block_; + + // For each instruction this records how many instructions satisfying the + // predicate are available before the instruction. + std::unordered_map<opt::Instruction*, uint32_t> + num_available_before_instruction_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_AVAILABLE_INSTRUCTIONS_H_ diff --git a/source/fuzz/force_render_red.cpp b/source/fuzz/force_render_red.cpp index fd0587a3..3267487a 100644 --- a/source/fuzz/force_render_red.cpp +++ b/source/fuzz/force_render_red.cpp @@ -19,12 +19,10 @@ #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" #include "source/opt/ir_context.h" #include "source/opt/types.h" #include "source/util/make_unique.h" -#include "tools/util/cli_consumer.h" namespace spvtools { namespace fuzz { @@ -160,8 +158,8 @@ bool ForceRenderRed( const spv_target_env& target_env, spv_validator_options validator_options, const std::vector<uint32_t>& binary_in, const spvtools::fuzz::protobufs::FactSequence& initial_facts, + const MessageConsumer& message_consumer, std::vector<uint32_t>* binary_out) { - auto message_consumer = spvtools::utils::CLIMessageConsumer; spvtools::SpirvTools tools(target_env); if (!tools.IsValid()) { message_consumer(SPV_MSG_ERROR, nullptr, {}, diff --git a/source/fuzz/force_render_red.h b/source/fuzz/force_render_red.h index b51c72b4..5b8eab1b 100644 --- a/source/fuzz/force_render_red.h +++ b/source/fuzz/force_render_red.h @@ -41,7 +41,7 @@ bool ForceRenderRed( 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); + const MessageConsumer& message_consumer, std::vector<uint32_t>* binary_out); } // namespace fuzz } // namespace spvtools diff --git a/source/fuzz/fuzzer.cpp b/source/fuzz/fuzzer.cpp index 40da4974..9d1af752 100644 --- a/source/fuzz/fuzzer.cpp +++ b/source/fuzz/fuzzer.cpp @@ -17,9 +17,7 @@ #include <cassert> #include <memory> #include <numeric> -#include <sstream> -#include "source/fuzz/fact_manager/fact_manager.h" #include "source/fuzz/fuzzer_context.h" #include "source/fuzz/fuzzer_pass_add_access_chains.h" #include "source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h" @@ -91,9 +89,6 @@ #include "source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h" #include "source/fuzz/fuzzer_pass_wrap_regions_in_selections.h" #include "source/fuzz/pass_management/repeated_pass_manager.h" -#include "source/fuzz/pass_management/repeated_pass_manager_looped_with_recommendations.h" -#include "source/fuzz/pass_management/repeated_pass_manager_random_with_recommendations.h" -#include "source/fuzz/pass_management/repeated_pass_manager_simple.h" #include "source/fuzz/pass_management/repeated_pass_recommender_standard.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/transformation_context.h" @@ -104,35 +99,147 @@ namespace spvtools { namespace fuzz { -namespace { -const uint32_t kIdBoundGap = 100; - -} // namespace - -Fuzzer::Fuzzer(spv_target_env target_env, MessageConsumer consumer, - const std::vector<uint32_t>& binary_in, - const protobufs::FactSequence& initial_facts, +Fuzzer::Fuzzer(std::unique_ptr<opt::IRContext> ir_context, + std::unique_ptr<TransformationContext> transformation_context, + std::unique_ptr<FuzzerContext> fuzzer_context, + MessageConsumer consumer, const std::vector<fuzzerutil::ModuleSupplier>& donor_suppliers, - std::unique_ptr<RandomGenerator> random_generator, bool enable_all_passes, RepeatedPassStrategy repeated_pass_strategy, bool validate_after_each_fuzzer_pass, spv_validator_options validator_options) - : target_env_(target_env), - consumer_(std::move(consumer)), - binary_in_(binary_in), - initial_facts_(initial_facts), - donor_suppliers_(donor_suppliers), - random_generator_(std::move(random_generator)), + : consumer_(std::move(consumer)), enable_all_passes_(enable_all_passes), - repeated_pass_strategy_(repeated_pass_strategy), validate_after_each_fuzzer_pass_(validate_after_each_fuzzer_pass), validator_options_(validator_options), num_repeated_passes_applied_(0), - ir_context_(nullptr), - fuzzer_context_(nullptr), - transformation_context_(nullptr), - transformation_sequence_out_() {} + is_valid_(true), + ir_context_(std::move(ir_context)), + transformation_context_(std::move(transformation_context)), + fuzzer_context_(std::move(fuzzer_context)), + transformation_sequence_out_(), + pass_instances_(), + repeated_pass_recommender_(nullptr), + repeated_pass_manager_(nullptr), + final_passes_() { + assert(ir_context_ && "IRContext is not initialized"); + assert(fuzzer_context_ && "FuzzerContext is not initialized"); + assert(transformation_context_ && "TransformationContext is not initialized"); + assert(fuzzerutil::IsValidAndWellFormed(ir_context_.get(), validator_options_, + consumer_) && + "IRContext is invalid"); + + // The following passes are likely to be very useful: many other passes + // introduce synonyms, irrelevant ids and constants that these passes can work + // with. We thus enable them with high probability. + MaybeAddRepeatedPass<FuzzerPassObfuscateConstants>(90, &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassApplyIdSynonyms>(90, &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassReplaceIrrelevantIds>(90, &pass_instances_); + + do { + // Each call to MaybeAddRepeatedPass randomly decides whether the given pass + // should be enabled, and adds an instance of the pass to |pass_instances| + // if it is enabled. + MaybeAddRepeatedPass<FuzzerPassAddAccessChains>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddBitInstructionSynonyms>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddCompositeExtract>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddCompositeInserts>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddCompositeTypes>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddCopyMemory>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddDeadBlocks>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddDeadBreaks>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddDeadContinues>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddEquationInstructions>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddFunctionCalls>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddGlobalVariables>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddImageSampleUnusedComponents>( + &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddLoads>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddLocalVariables>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddLoopPreheaders>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddLoopsToCreateIntConstantSynonyms>( + &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddOpPhiSynonyms>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddParameters>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddRelaxedDecorations>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddStores>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddSynonyms>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassAddVectorShuffleInstructions>( + &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassConstructComposites>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassCopyObjects>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassDonateModules>(&pass_instances_, + donor_suppliers); + MaybeAddRepeatedPass<FuzzerPassDuplicateRegionsWithSelections>( + &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassExpandVectorReductions>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassFlattenConditionalBranches>( + &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassInlineFunctions>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassInvertComparisonOperators>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassMakeVectorOperationsDynamic>( + &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassMergeBlocks>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassMergeFunctionReturns>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassMutatePointers>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassOutlineFunctions>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassPermuteBlocks>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassPermuteFunctionParameters>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassPermuteInstructions>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassPropagateInstructionsDown>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassPropagateInstructionsUp>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassPushIdsThroughVariables>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassReplaceAddsSubsMulsWithCarryingExtended>( + &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassReplaceBranchesFromDeadBlocksWithExits>( + &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassReplaceCopyMemoriesWithLoadsStores>( + &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassReplaceCopyObjectsWithStoresLoads>( + &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassReplaceLoadsStoresWithCopyMemories>( + &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassReplaceParameterWithGlobal>( + &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassReplaceLinearAlgebraInstructions>( + &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassReplaceOpPhiIdsFromDeadPredecessors>( + &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassReplaceOpSelectsWithConditionalBranches>( + &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassReplaceParamsWithStruct>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassSplitBlocks>(&pass_instances_); + MaybeAddRepeatedPass<FuzzerPassSwapBranchConditionalOperands>( + &pass_instances_); + MaybeAddRepeatedPass<FuzzerPassWrapRegionsInSelections>(&pass_instances_); + // There is a theoretical possibility that no pass instances were created + // until now; loop again if so. + } while (pass_instances_.GetPasses().empty()); + + repeated_pass_recommender_ = MakeUnique<RepeatedPassRecommenderStandard>( + &pass_instances_, fuzzer_context_.get()); + repeated_pass_manager_ = RepeatedPassManager::Create( + repeated_pass_strategy, fuzzer_context_.get(), &pass_instances_, + repeated_pass_recommender_.get()); + + MaybeAddFinalPass<FuzzerPassAdjustBranchWeights>(&final_passes_); + MaybeAddFinalPass<FuzzerPassAdjustFunctionControls>(&final_passes_); + MaybeAddFinalPass<FuzzerPassAdjustLoopControls>(&final_passes_); + MaybeAddFinalPass<FuzzerPassAdjustMemoryOperandsMasks>(&final_passes_); + MaybeAddFinalPass<FuzzerPassAdjustSelectionControls>(&final_passes_); + MaybeAddFinalPass<FuzzerPassAddNoContractionDecorations>(&final_passes_); + if (!fuzzer_context_->IsWgslCompatible()) { + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/4214): + // this is disabled temporarily due to some issues in the Tint compiler. + // Enable it back when the issues are resolved. + MaybeAddFinalPass<FuzzerPassInterchangeSignednessOfIntegerOperands>( + &final_passes_); + } + MaybeAddFinalPass<FuzzerPassInterchangeZeroLikeConstants>(&final_passes_); + MaybeAddFinalPass<FuzzerPassPermutePhiOperands>(&final_passes_); + MaybeAddFinalPass<FuzzerPassSwapCommutableOperands>(&final_passes_); + MaybeAddFinalPass<FuzzerPassToggleAccessChainInstruction>(&final_passes_); +} Fuzzer::~Fuzzer() = default; @@ -165,240 +272,107 @@ bool Fuzzer::ApplyPassAndCheckValidity(FuzzerPass* pass) const { consumer_); } -Fuzzer::FuzzerResult Fuzzer::Run() { - // Check compatibility between the library version being linked with and the - // header files being used. - GOOGLE_PROTOBUF_VERIFY_VERSION; +opt::IRContext* Fuzzer::GetIRContext() { return ir_context_.get(); } - assert(ir_context_ == nullptr && fuzzer_context_ == nullptr && - transformation_context_ == nullptr && - transformation_sequence_out_.transformation_size() == 0 && - "'Run' must not be invoked more than once."); - - spvtools::SpirvTools tools(target_env_); - tools.SetMessageConsumer(consumer_); - if (!tools.IsValid()) { - consumer_(SPV_MSG_ERROR, nullptr, {}, - "Failed to create SPIRV-Tools interface; stopping."); - return {Fuzzer::FuzzerResultStatus::kFailedToCreateSpirvToolsInterface, - std::vector<uint32_t>(), protobufs::TransformationSequence()}; - } - - // Initial binary should be valid. - if (!tools.Validate(&binary_in_[0], binary_in_.size(), validator_options_)) { - consumer_(SPV_MSG_ERROR, nullptr, {}, - "Initial binary is invalid; stopping."); - return {Fuzzer::FuzzerResultStatus::kInitialBinaryInvalid, - std::vector<uint32_t>(), protobufs::TransformationSequence()}; - } - - // Build the module from the input binary. - ir_context_ = - BuildModule(target_env_, consumer_, binary_in_.data(), binary_in_.size()); - assert(ir_context_); - - // The fuzzer will introduce new ids into the module. The module's id bound - // gives the smallest id that can be used for this purpose. We add an offset - // to this so that there is a sizeable gap between the ids used in the - // original module and the ids used for fuzzing, as a readability aid. - // - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2541) consider the - // case where the maximum id bound is reached. - auto minimum_fresh_id = ir_context_->module()->id_bound() + kIdBoundGap; - fuzzer_context_ = - MakeUnique<FuzzerContext>(random_generator_.get(), minimum_fresh_id); - - transformation_context_ = MakeUnique<TransformationContext>( - MakeUnique<FactManager>(ir_context_.get()), validator_options_); - transformation_context_->GetFactManager()->AddInitialFacts(consumer_, - initial_facts_); +const protobufs::TransformationSequence& Fuzzer::GetTransformationSequence() + const { + return transformation_sequence_out_; +} - RepeatedPassInstances pass_instances{}; +Fuzzer::Result Fuzzer::Run(uint32_t num_of_transformations_to_apply) { + assert(is_valid_ && "The module was invalidated during the previous fuzzing"); - // The following passes are likely to be very useful: many other passes - // introduce synonyms, irrelevant ids and constants that these passes can work - // with. We thus enable them with high probability. - MaybeAddRepeatedPass<FuzzerPassObfuscateConstants>(90, &pass_instances); - MaybeAddRepeatedPass<FuzzerPassApplyIdSynonyms>(90, &pass_instances); - MaybeAddRepeatedPass<FuzzerPassReplaceIrrelevantIds>(90, &pass_instances); + const auto initial_num_of_transformations = + static_cast<uint32_t>(transformation_sequence_out_.transformation_size()); + auto status = Status::kComplete; do { - // Each call to MaybeAddRepeatedPass randomly decides whether the given pass - // should be enabled, and adds an instance of the pass to |pass_instances| - // if it is enabled. - MaybeAddRepeatedPass<FuzzerPassAddAccessChains>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddBitInstructionSynonyms>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddCompositeExtract>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddCompositeInserts>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddCompositeTypes>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddCopyMemory>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddDeadBlocks>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddDeadBreaks>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddDeadContinues>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddEquationInstructions>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddFunctionCalls>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddGlobalVariables>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddImageSampleUnusedComponents>( - &pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddLoads>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddLocalVariables>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddLoopPreheaders>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddLoopsToCreateIntConstantSynonyms>( - &pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddOpPhiSynonyms>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddParameters>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddRelaxedDecorations>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddStores>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddSynonyms>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassAddVectorShuffleInstructions>( - &pass_instances); - MaybeAddRepeatedPass<FuzzerPassConstructComposites>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassCopyObjects>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassDonateModules>(&pass_instances, - donor_suppliers_); - MaybeAddRepeatedPass<FuzzerPassDuplicateRegionsWithSelections>( - &pass_instances); - MaybeAddRepeatedPass<FuzzerPassExpandVectorReductions>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassFlattenConditionalBranches>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassInlineFunctions>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassInvertComparisonOperators>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassMakeVectorOperationsDynamic>( - &pass_instances); - MaybeAddRepeatedPass<FuzzerPassMergeBlocks>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassMergeFunctionReturns>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassMutatePointers>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassOutlineFunctions>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassPermuteBlocks>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassPermuteFunctionParameters>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassPermuteInstructions>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassPropagateInstructionsDown>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassPropagateInstructionsUp>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassPushIdsThroughVariables>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassReplaceAddsSubsMulsWithCarryingExtended>( - &pass_instances); - MaybeAddRepeatedPass<FuzzerPassReplaceBranchesFromDeadBlocksWithExits>( - &pass_instances); - MaybeAddRepeatedPass<FuzzerPassReplaceCopyMemoriesWithLoadsStores>( - &pass_instances); - MaybeAddRepeatedPass<FuzzerPassReplaceCopyObjectsWithStoresLoads>( - &pass_instances); - MaybeAddRepeatedPass<FuzzerPassReplaceLoadsStoresWithCopyMemories>( - &pass_instances); - MaybeAddRepeatedPass<FuzzerPassReplaceParameterWithGlobal>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassReplaceLinearAlgebraInstructions>( - &pass_instances); - MaybeAddRepeatedPass<FuzzerPassReplaceOpPhiIdsFromDeadPredecessors>( - &pass_instances); - MaybeAddRepeatedPass<FuzzerPassReplaceOpSelectsWithConditionalBranches>( - &pass_instances); - MaybeAddRepeatedPass<FuzzerPassReplaceParamsWithStruct>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassSplitBlocks>(&pass_instances); - MaybeAddRepeatedPass<FuzzerPassSwapBranchConditionalOperands>( - &pass_instances); - MaybeAddRepeatedPass<FuzzerPassWrapRegionsInSelections>(&pass_instances); - // There is a theoretical possibility that no pass instances were created - // until now; loop again if so. - } while (pass_instances.GetPasses().empty()); - - RepeatedPassRecommenderStandard pass_recommender(&pass_instances, - fuzzer_context_.get()); + if (!ApplyPassAndCheckValidity( + repeated_pass_manager_->ChoosePass(transformation_sequence_out_))) { + status = Status::kFuzzerPassLedToInvalidModule; + break; + } - std::unique_ptr<RepeatedPassManager> repeated_pass_manager = nullptr; - switch (repeated_pass_strategy_) { - case RepeatedPassStrategy::kSimple: - repeated_pass_manager = MakeUnique<RepeatedPassManagerSimple>( - fuzzer_context_.get(), &pass_instances); + // Check that the module is small enough. + if (ir_context_->module()->id_bound() >= + fuzzer_context_->GetIdBoundLimit()) { + status = Status::kModuleTooBig; break; - case RepeatedPassStrategy::kLoopedWithRecommendations: - repeated_pass_manager = - MakeUnique<RepeatedPassManagerLoopedWithRecommendations>( - fuzzer_context_.get(), &pass_instances, &pass_recommender); + } + + auto transformations_applied_so_far = static_cast<uint32_t>( + transformation_sequence_out_.transformation_size()); + assert(transformations_applied_so_far >= initial_num_of_transformations && + "Number of transformations cannot decrease"); + + // Check if we've already applied the maximum number of transformations. + if (transformations_applied_so_far >= + fuzzer_context_->GetTransformationLimit()) { + status = Status::kTransformationLimitReached; break; - case RepeatedPassStrategy::kRandomWithRecommendations: - repeated_pass_manager = - MakeUnique<RepeatedPassManagerRandomWithRecommendations>( - fuzzer_context_.get(), &pass_instances, &pass_recommender); + } + + // Check that we've not got stuck (this can happen if the only available + // fuzzer passes are not able to apply any transformations, or can only + // apply very few transformations). + if (num_repeated_passes_applied_ >= + fuzzer_context_->GetTransformationLimit()) { + status = Status::kFuzzerStuck; break; - } + } - do { - if (!ApplyPassAndCheckValidity( - repeated_pass_manager->ChoosePass(transformation_sequence_out_))) { - return {Fuzzer::FuzzerResultStatus::kFuzzerPassLedToInvalidModule, - std::vector<uint32_t>(), protobufs::TransformationSequence()}; + // Check whether we've exceeded the number of transformations we can apply + // in a single call to this method. + if (num_of_transformations_to_apply != 0 && + transformations_applied_so_far - initial_num_of_transformations >= + num_of_transformations_to_apply) { + status = Status::kComplete; + break; } - } while (ShouldContinueFuzzing()); - // Now apply some passes that it does not make sense to apply repeatedly, - // as they do not unlock other passes. - std::vector<std::unique_ptr<FuzzerPass>> final_passes; - MaybeAddFinalPass<FuzzerPassAdjustBranchWeights>(&final_passes); - MaybeAddFinalPass<FuzzerPassAdjustFunctionControls>(&final_passes); - MaybeAddFinalPass<FuzzerPassAdjustLoopControls>(&final_passes); - MaybeAddFinalPass<FuzzerPassAdjustMemoryOperandsMasks>(&final_passes); - MaybeAddFinalPass<FuzzerPassAdjustSelectionControls>(&final_passes); - MaybeAddFinalPass<FuzzerPassAddNoContractionDecorations>(&final_passes); - MaybeAddFinalPass<FuzzerPassInterchangeSignednessOfIntegerOperands>( - &final_passes); - MaybeAddFinalPass<FuzzerPassInterchangeZeroLikeConstants>(&final_passes); - MaybeAddFinalPass<FuzzerPassPermutePhiOperands>(&final_passes); - MaybeAddFinalPass<FuzzerPassSwapCommutableOperands>(&final_passes); - MaybeAddFinalPass<FuzzerPassToggleAccessChainInstruction>(&final_passes); - for (auto& pass : final_passes) { - if (!ApplyPassAndCheckValidity(pass.get())) { - return {Fuzzer::FuzzerResultStatus::kFuzzerPassLedToInvalidModule, - std::vector<uint32_t>(), protobufs::TransformationSequence()}; + } while (ShouldContinueRepeatedPasses(num_of_transformations_to_apply == 0)); + + if (status != Status::kFuzzerPassLedToInvalidModule) { + // We apply this transformations despite the fact that we might exceed + // |num_of_transformations_to_apply|. This is not a problem for us since + // these fuzzer passes are relatively simple yet might trigger some bugs. + for (auto& pass : final_passes_) { + if (!ApplyPassAndCheckValidity(pass.get())) { + status = Status::kFuzzerPassLedToInvalidModule; + break; + } } } - // Encode the module as a binary. - std::vector<uint32_t> binary_out; - ir_context_->module()->ToBinary(&binary_out, false); - return {Fuzzer::FuzzerResultStatus::kComplete, std::move(binary_out), - std::move(transformation_sequence_out_)}; + is_valid_ = status != Status::kFuzzerPassLedToInvalidModule; + return {status, static_cast<uint32_t>( + transformation_sequence_out_.transformation_size()) != + initial_num_of_transformations}; } -bool Fuzzer::ShouldContinueFuzzing() { - // There's a risk that fuzzing could get stuck, if none of the enabled fuzzer - // passes are able to apply any transformations. To guard against this we - // count the number of times some repeated pass has been applied and ensure - // that fuzzing stops if the number of repeated passes hits the limit on the - // number of transformations that can be applied. - assert( - num_repeated_passes_applied_ <= - fuzzer_context_->GetTransformationLimit() && - "The number of repeated passes applied must not exceed its upper limit."); - if (ir_context_->module()->id_bound() >= fuzzer_context_->GetIdBoundLimit()) { - return false; - } - if (num_repeated_passes_applied_ == - fuzzer_context_->GetTransformationLimit()) { - // Stop because fuzzing has got stuck. - return false; - } - auto transformations_applied_so_far = - static_cast<uint32_t>(transformation_sequence_out_.transformation_size()); - if (transformations_applied_so_far >= - fuzzer_context_->GetTransformationLimit()) { - // Stop because we have reached the transformation limit. - return false; - } - // If we have applied T transformations so far, and the limit on the number of - // transformations to apply is L (where T < L), the chance that we will - // continue fuzzing is: - // - // 1 - T/(2*L) - // - // That is, the chance of continuing decreases as more transformations are - // applied. Using 2*L instead of L increases the number of transformations - // that are applied on average. - auto chance_of_continuing = static_cast<uint32_t>( - 100.0 * (1.0 - (static_cast<double>(transformations_applied_so_far) / - (2.0 * static_cast<double>( - fuzzer_context_->GetTransformationLimit()))))); - if (!fuzzer_context_->ChoosePercentage(chance_of_continuing)) { - // We have probabilistically decided to stop. - return false; +bool Fuzzer::ShouldContinueRepeatedPasses( + bool continue_fuzzing_probabilistically) { + if (continue_fuzzing_probabilistically) { + // If we have applied T transformations so far, and the limit on the number + // of transformations to apply is L (where T < L), the chance that we will + // continue fuzzing is: + // + // 1 - T/(2*L) + // + // That is, the chance of continuing decreases as more transformations are + // applied. Using 2*L instead of L increases the number of transformations + // that are applied on average. + auto transformations_applied_so_far = static_cast<uint32_t>( + transformation_sequence_out_.transformation_size()); + auto chance_of_continuing = static_cast<uint32_t>( + 100.0 * + (1.0 - (static_cast<double>(transformations_applied_so_far) / + (2.0 * static_cast<double>( + fuzzer_context_->GetTransformationLimit()))))); + if (!fuzzer_context_->ChoosePercentage(chance_of_continuing)) { + // We have probabilistically decided to stop. + return false; + } } // Continue fuzzing! num_repeated_passes_applied_++; diff --git a/source/fuzz/fuzzer.h b/source/fuzz/fuzzer.h index 774457f5..1e7d6860 100644 --- a/source/fuzz/fuzzer.h +++ b/source/fuzz/fuzzer.h @@ -23,6 +23,7 @@ #include "source/fuzz/fuzzer_pass.h" #include "source/fuzz/fuzzer_util.h" #include "source/fuzz/pass_management/repeated_pass_instances.h" +#include "source/fuzz/pass_management/repeated_pass_manager.h" #include "source/fuzz/pass_management/repeated_pass_recommender.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/random_generator.h" @@ -37,33 +38,28 @@ namespace fuzz { class Fuzzer { public: // Possible statuses that can result from running the fuzzer. - enum class FuzzerResultStatus { + enum class Status { kComplete, - kFailedToCreateSpirvToolsInterface, + kModuleTooBig, + kTransformationLimitReached, + kFuzzerStuck, kFuzzerPassLedToInvalidModule, - kInitialBinaryInvalid, }; - struct FuzzerResult { - FuzzerResultStatus status; - std::vector<uint32_t> transformed_binary; - protobufs::TransformationSequence applied_transformations; - }; + struct Result { + // Status of the fuzzing session. + Status status; - // Each field of this enum corresponds to an available repeated pass - // strategy, and is used to decide which kind of RepeatedPassManager object - // to create. - enum class RepeatedPassStrategy { - kSimple, - kRandomWithRecommendations, - kLoopedWithRecommendations + // Equals to true if new transformations were applied during the previous + // fuzzing session. + bool is_changed; }; - Fuzzer(spv_target_env target_env, MessageConsumer consumer, - const std::vector<uint32_t>& binary_in, - const protobufs::FactSequence& initial_facts, + Fuzzer(std::unique_ptr<opt::IRContext> ir_context, + std::unique_ptr<TransformationContext> transformation_context, + std::unique_ptr<FuzzerContext> fuzzer_context, + MessageConsumer consumer, const std::vector<fuzzerutil::ModuleSupplier>& donor_suppliers, - std::unique_ptr<RandomGenerator> random_generator, bool enable_all_passes, RepeatedPassStrategy repeated_pass_strategy, bool validate_after_each_fuzzer_pass, spv_validator_options validator_options); @@ -76,15 +72,23 @@ class Fuzzer { ~Fuzzer(); - // Transforms |binary_in_| by running a number of randomized fuzzer passes. - // Initial facts about the input binary and the context in which it will - // execute are provided via |initial_facts_|. A source of donor modules to be - // used by transformations is provided via |donor_suppliers_|. On success, - // returns a successful result status together with the transformed binary and - // the sequence of transformations that were applied. Otherwise, returns an - // appropriate result status together with an empty binary and empty - // transformation sequence. - FuzzerResult Run(); + // Transforms |ir_context_| by running a number of randomized fuzzer passes. + // Initial facts about the input binary and the context in which it will be + // executed are provided with |transformation_context_|. + // |num_of_transformations| is equal to the maximum number of transformations + // applied in a single call to this method. This parameter is ignored if its + // value is equal to 0. Because fuzzing cannot stop mid way through a fuzzer + // pass, fuzzing will stop after the fuzzer pass that exceeds + // |num_of_transformations| has completed, so that the total number of + // transformations may be somewhat larger than this number. + Result Run(uint32_t num_of_transformations_to_apply); + + // Returns the current IR context. It may be invalid if the Run method + // returned Status::kFuzzerPassLedToInvalidModule previously. + opt::IRContext* GetIRContext(); + + // Returns the sequence of applied transformations. + const protobufs::TransformationSequence& GetTransformationSequence() const; private: // A convenience method to add a repeated fuzzer pass to |pass_instances| with @@ -119,7 +123,9 @@ class Fuzzer { // Decides whether to apply more repeated passes. The probability decreases as // the number of transformations that have been applied increases. - bool ShouldContinueFuzzing(); + // The described probability is only applied if + // |continue_fuzzing_probabilistically| is true. + bool ShouldContinueRepeatedPasses(bool continue_fuzzing_probabilistically); // Applies |pass|, which must be a pass constructed with |ir_context|. // If |validate_after_each_fuzzer_pass_| is not set, true is always returned. @@ -128,57 +134,59 @@ class Fuzzer { // instruction has a distinct unique id. bool ApplyPassAndCheckValidity(FuzzerPass* pass) const; - // Target environment. - const spv_target_env target_env_; - // Message consumer that will be invoked once for each message communicated // from the library. - MessageConsumer consumer_; - - // The initial binary to which fuzzing should be applied. - const std::vector<uint32_t>& binary_in_; - - // Initial facts known to hold in advance of applying any transformations. - const protobufs::FactSequence& initial_facts_; - - // A source of modules whose contents can be donated into the module being - // fuzzed. - const std::vector<fuzzerutil::ModuleSupplier>& donor_suppliers_; - - // Random number generator to control decision making during fuzzing. - std::unique_ptr<RandomGenerator> random_generator_; + const MessageConsumer consumer_; // Determines whether all passes should be enabled, vs. having passes be // probabilistically enabled. - bool enable_all_passes_; - - // Controls which type of RepeatedPassManager object to create. - RepeatedPassStrategy repeated_pass_strategy_; + const bool enable_all_passes_; // Determines whether the validator should be invoked after every fuzzer pass. - bool validate_after_each_fuzzer_pass_; + const bool validate_after_each_fuzzer_pass_; // Options to control validation. - spv_validator_options validator_options_; + const spv_validator_options validator_options_; // The number of repeated fuzzer passes that have been applied is kept track // of, in order to enforce a hard limit on the number of times such passes // can be applied. uint32_t num_repeated_passes_applied_; + // We use this to determine whether we can continue fuzzing incrementally + // since the previous call to the Run method could've returned + // kFuzzerPassLedToInvalidModule. + bool is_valid_; + // Intermediate representation for the module being fuzzed, which gets // mutated as fuzzing proceeds. std::unique_ptr<opt::IRContext> ir_context_; + // Contextual information that is required in order to apply + // transformations. + std::unique_ptr<TransformationContext> transformation_context_; + // Provides probabilities that control the fuzzing process. std::unique_ptr<FuzzerContext> fuzzer_context_; - // Contextual information that is required in order to apply transformations. - std::unique_ptr<TransformationContext> transformation_context_; - - // The sequence of transformations that have been applied during fuzzing. It + // The sequence of transformations that have been applied during fuzzing. It // is initially empty and grows as fuzzer passes are applied. protobufs::TransformationSequence transformation_sequence_out_; + + // This object contains instances of all fuzzer passes that will participate + // in the fuzzing. + RepeatedPassInstances pass_instances_; + + // This object defines the recommendation logic for fuzzer passes. + std::unique_ptr<RepeatedPassRecommender> repeated_pass_recommender_; + + // This object manager a list of fuzzer pass and their available + // recommendations. + std::unique_ptr<RepeatedPassManager> repeated_pass_manager_; + + // Some passes that it does not make sense to apply repeatedly, as they do not + // unlock other passes. + std::vector<std::unique_ptr<FuzzerPass>> final_passes_; }; } // namespace fuzz diff --git a/source/fuzz/fuzzer_context.cpp b/source/fuzz/fuzzer_context.cpp index 47bf4e25..ef93e719 100644 --- a/source/fuzz/fuzzer_context.cpp +++ b/source/fuzz/fuzzer_context.cpp @@ -21,6 +21,12 @@ namespace fuzz { namespace { +// An offset between the the module's id bound and the minimum fresh id. +// +// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2541): consider +// the case where the maximum id bound is reached. +const uint32_t kIdBoundGap = 100; + // Limits to help control the overall fuzzing process and rein in individual // fuzzer passes. const uint32_t kIdBoundLimit = 50000; @@ -177,10 +183,11 @@ const std::function<bool(uint32_t, RandomGenerator*)> } // namespace -FuzzerContext::FuzzerContext(RandomGenerator* random_generator, - uint32_t min_fresh_id) - : random_generator_(random_generator), +FuzzerContext::FuzzerContext(std::unique_ptr<RandomGenerator> random_generator, + uint32_t min_fresh_id, bool is_wgsl_compatible) + : random_generator_(std::move(random_generator)), next_fresh_id_(min_fresh_id), + is_wgsl_compatible_(is_wgsl_compatible), max_equivalence_class_size_for_data_synonym_fact_closure_( kDefaultMaxEquivalenceClassSizeForDataSynonymFactClosure), max_loop_control_partial_count_(kDefaultMaxLoopControlPartialCount), @@ -403,5 +410,9 @@ uint32_t FuzzerContext::GetTransformationLimit() const { return kTransformationLimit; } +uint32_t FuzzerContext::GetMinFreshId(opt::IRContext* ir_context) { + return ir_context->module()->id_bound() + kIdBoundGap; +} + } // namespace fuzz } // namespace spvtools diff --git a/source/fuzz/fuzzer_context.h b/source/fuzz/fuzzer_context.h index 8c510418..40fd8783 100644 --- a/source/fuzz/fuzzer_context.h +++ b/source/fuzz/fuzzer_context.h @@ -21,6 +21,7 @@ #include "source/fuzz/protobufs/spirvfuzz_protobufs.h" #include "source/fuzz/random_generator.h" #include "source/opt/function.h" +#include "source/opt/ir_context.h" namespace spvtools { namespace fuzz { @@ -32,7 +33,8 @@ class FuzzerContext { public: // Constructs a fuzzer context with a given random generator and the minimum // value that can be used for fresh ids. - FuzzerContext(RandomGenerator* random_generator, uint32_t min_fresh_id); + FuzzerContext(std::unique_ptr<RandomGenerator> random_generator, + uint32_t min_fresh_id, bool is_wgsl_compatible); ~FuzzerContext(); @@ -64,7 +66,7 @@ class FuzzerContext { } // Randomly shuffles a |sequence| between |lo| and |hi| indices inclusively. - // |lo| and |hi| must be valid indices to the |sequence| + // |lo| and |hi| must be valid indices to the |sequence|. template <typename T> void Shuffle(std::vector<T>* sequence, size_t lo, size_t hi) const { auto& array = *sequence; @@ -89,7 +91,7 @@ class FuzzerContext { } } - // Ramdomly shuffles a |sequence| + // Randomly shuffles a |sequence|. template <typename T> void Shuffle(std::vector<T>* sequence) const { if (!sequence->empty()) { @@ -102,7 +104,7 @@ class FuzzerContext { uint32_t GetFreshId(); // Returns a vector of |count| fresh ids. - std::vector<uint32_t> GetFreshIds(const uint32_t count); + std::vector<uint32_t> GetFreshIds(uint32_t count); // A suggested limit on the id bound for the module being fuzzed. This is // useful for deciding when to stop the overall fuzzing process. Furthermore, @@ -115,6 +117,14 @@ class FuzzerContext { // fuzzer passes. uint32_t GetTransformationLimit() const; + // Returns the minimum fresh id that can be used given the |ir_context|. + static uint32_t GetMinFreshId(opt::IRContext* ir_context); + + // Returns true if all transformations should be compatible with WGSL. + bool IsWgslCompatible() const { + return is_wgsl_compatible_; + } + // Probabilities associated with applying various transformations. // Keep them in alphabetical order. uint32_t GetChanceOfAcceptingRepeatedPassRecommendation() const { @@ -442,15 +452,18 @@ class FuzzerContext { return random_generator_->RandomUint32(max_unused_component_count) + 1; } bool GoDeeperInConstantObfuscation(uint32_t depth) { - return go_deeper_in_constant_obfuscation_(depth, random_generator_); + return go_deeper_in_constant_obfuscation_(depth, random_generator_.get()); } private: // The source of randomness. - RandomGenerator* random_generator_; + std::unique_ptr<RandomGenerator> random_generator_; // The next fresh id to be issued. uint32_t next_fresh_id_; + // True if all transformations should be compatible with WGSL spec. + bool is_wgsl_compatible_; + // Probabilities associated with applying various transformations. // Keep them in alphabetical order. uint32_t chance_of_accepting_repeated_pass_recommendation_; diff --git a/source/fuzz/fuzzer_pass_add_access_chains.cpp b/source/fuzz/fuzzer_pass_add_access_chains.cpp index 11155f23..c498642c 100644 --- a/source/fuzz/fuzzer_pass_add_access_chains.cpp +++ b/source/fuzz/fuzzer_pass_add_access_chains.cpp @@ -27,8 +27,6 @@ FuzzerPassAddAccessChains::FuzzerPassAddAccessChains( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddAccessChains::~FuzzerPassAddAccessChains() = default; - void FuzzerPassAddAccessChains::Apply() { ForEachInstructionWithInstructionDescriptor( [this](opt::Function* function, opt::BasicBlock* block, diff --git a/source/fuzz/fuzzer_pass_add_access_chains.h b/source/fuzz/fuzzer_pass_add_access_chains.h index 8649296f..e80c2c6c 100644 --- a/source/fuzz/fuzzer_pass_add_access_chains.h +++ b/source/fuzz/fuzzer_pass_add_access_chains.h @@ -30,8 +30,6 @@ class FuzzerPassAddAccessChains : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddAccessChains(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.cpp b/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.cpp index 7b9ac4e2..b2edc194 100644 --- a/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.cpp +++ b/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.cpp @@ -28,9 +28,6 @@ FuzzerPassAddBitInstructionSynonyms::FuzzerPassAddBitInstructionSynonyms( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddBitInstructionSynonyms::~FuzzerPassAddBitInstructionSynonyms() = - default; - void FuzzerPassAddBitInstructionSynonyms::Apply() { for (auto& function : *GetIRContext()->module()) { for (auto& block : function) { diff --git a/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h b/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h index 0194425d..28f95779 100644 --- a/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h +++ b/source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h @@ -30,8 +30,6 @@ class FuzzerPassAddBitInstructionSynonyms : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddBitInstructionSynonyms(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_add_composite_extract.cpp b/source/fuzz/fuzzer_pass_add_composite_extract.cpp index 132a49da..19f99024 100644 --- a/source/fuzz/fuzzer_pass_add_composite_extract.cpp +++ b/source/fuzz/fuzzer_pass_add_composite_extract.cpp @@ -14,6 +14,7 @@ #include "source/fuzz/fuzzer_pass_add_composite_extract.h" +#include "source/fuzz/available_instructions.h" #include "source/fuzz/fuzzer_context.h" #include "source/fuzz/fuzzer_util.h" #include "source/fuzz/instruction_descriptor.h" @@ -29,8 +30,6 @@ FuzzerPassAddCompositeExtract::FuzzerPassAddCompositeExtract( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddCompositeExtract::~FuzzerPassAddCompositeExtract() = default; - void FuzzerPassAddCompositeExtract::Apply() { std::vector<const protobufs::DataDescriptor*> composite_synonyms; for (const auto* dd : @@ -41,14 +40,16 @@ void FuzzerPassAddCompositeExtract::Apply() { } } - // We don't want to invalidate the module every time we apply this - // transformation since rebuilding DominatorAnalysis can be expensive, so we - // collect up the transformations we wish to apply and apply them all later. - std::vector<TransformationCompositeExtract> transformations; + AvailableInstructions available_composites( + GetIRContext(), [](opt::IRContext* ir_context, opt::Instruction* inst) { + return inst->type_id() && inst->result_id() && + fuzzerutil::IsCompositeType( + ir_context->get_type_mgr()->GetType(inst->type_id())); + }); ForEachInstructionWithInstructionDescriptor( - [this, &composite_synonyms, &transformations]( - opt::Function* function, opt::BasicBlock* block, + [this, &available_composites, &composite_synonyms]( + opt::Function* /*unused*/, opt::BasicBlock* /*unused*/, opt::BasicBlock::iterator inst_it, const protobufs::InstructionDescriptor& instruction_descriptor) { if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCompositeExtract, @@ -61,14 +62,6 @@ void FuzzerPassAddCompositeExtract::Apply() { return; } - auto available_composites = FindAvailableInstructions( - function, block, inst_it, - [](opt::IRContext* ir_context, opt::Instruction* inst) { - return inst->type_id() && inst->result_id() && - fuzzerutil::IsCompositeType( - ir_context->get_type_mgr()->GetType(inst->type_id())); - }); - std::vector<const protobufs::DataDescriptor*> available_synonyms; for (const auto* dd : composite_synonyms) { if (fuzzerutil::IdIsAvailableBeforeInstruction( @@ -77,18 +70,21 @@ void FuzzerPassAddCompositeExtract::Apply() { } } - if (available_synonyms.empty() && available_composites.empty()) { + auto candidate_composites = + available_composites.GetAvailableBeforeInstruction(&*inst_it); + + if (available_synonyms.empty() && candidate_composites.empty()) { return; } uint32_t composite_id = 0; std::vector<uint32_t> indices; - if (available_synonyms.empty() || (!available_composites.empty() && + if (available_synonyms.empty() || (!candidate_composites.empty() && GetFuzzerContext()->ChooseEven())) { const auto* inst = - available_composites[GetFuzzerContext()->RandomIndex( - available_composites)]; + candidate_composites[GetFuzzerContext()->RandomIndex( + candidate_composites)]; composite_id = inst->result_id(); auto type_id = inst->type_id(); @@ -153,14 +149,10 @@ void FuzzerPassAddCompositeExtract::Apply() { assert(composite_id != 0 && !indices.empty() && "Composite object should have been chosen correctly"); - transformations.emplace_back(instruction_descriptor, - GetFuzzerContext()->GetFreshId(), - composite_id, indices); + ApplyTransformation(TransformationCompositeExtract( + instruction_descriptor, GetFuzzerContext()->GetFreshId(), + composite_id, indices)); }); - - for (const auto& transformation : transformations) { - ApplyTransformation(transformation); - } } } // namespace fuzz diff --git a/source/fuzz/fuzzer_pass_add_composite_extract.h b/source/fuzz/fuzzer_pass_add_composite_extract.h index 8bcb825f..32ac190a 100644 --- a/source/fuzz/fuzzer_pass_add_composite_extract.h +++ b/source/fuzz/fuzzer_pass_add_composite_extract.h @@ -29,8 +29,6 @@ class FuzzerPassAddCompositeExtract : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddCompositeExtract() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_add_composite_inserts.cpp b/source/fuzz/fuzzer_pass_add_composite_inserts.cpp index e58c754c..cf314d30 100644 --- a/source/fuzz/fuzzer_pass_add_composite_inserts.cpp +++ b/source/fuzz/fuzzer_pass_add_composite_inserts.cpp @@ -29,8 +29,6 @@ FuzzerPassAddCompositeInserts::FuzzerPassAddCompositeInserts( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddCompositeInserts::~FuzzerPassAddCompositeInserts() = default; - void FuzzerPassAddCompositeInserts::Apply() { ForEachInstructionWithInstructionDescriptor( [this](opt::Function* function, opt::BasicBlock* block, diff --git a/source/fuzz/fuzzer_pass_add_composite_inserts.h b/source/fuzz/fuzzer_pass_add_composite_inserts.h index c4f51034..4d511f6c 100644 --- a/source/fuzz/fuzzer_pass_add_composite_inserts.h +++ b/source/fuzz/fuzzer_pass_add_composite_inserts.h @@ -29,7 +29,6 @@ class FuzzerPassAddCompositeInserts : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddCompositeInserts(); void Apply() override; // Checks if any component of a composite is a pointer. diff --git a/source/fuzz/fuzzer_pass_add_composite_types.cpp b/source/fuzz/fuzzer_pass_add_composite_types.cpp index c4d8d1c9..3dfbd690 100644 --- a/source/fuzz/fuzzer_pass_add_composite_types.cpp +++ b/source/fuzz/fuzzer_pass_add_composite_types.cpp @@ -28,8 +28,6 @@ FuzzerPassAddCompositeTypes::FuzzerPassAddCompositeTypes( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddCompositeTypes::~FuzzerPassAddCompositeTypes() = default; - void FuzzerPassAddCompositeTypes::Apply() { MaybeAddMissingVectorTypes(); MaybeAddMissingMatrixTypes(); @@ -125,7 +123,9 @@ uint32_t FuzzerPassAddCompositeTypes::ChooseScalarOrCompositeType() { break; case SpvOpTypeStruct: { if (!fuzzerutil::MembersHaveBuiltInDecoration(GetIRContext(), - inst.result_id())) { + inst.result_id()) && + !fuzzerutil::HasBlockOrBufferBlockDecoration(GetIRContext(), + inst.result_id())) { candidates.push_back(inst.result_id()); } } break; diff --git a/source/fuzz/fuzzer_pass_add_composite_types.h b/source/fuzz/fuzzer_pass_add_composite_types.h index 87bc0ff3..89d48f8a 100644 --- a/source/fuzz/fuzzer_pass_add_composite_types.h +++ b/source/fuzz/fuzzer_pass_add_composite_types.h @@ -29,8 +29,6 @@ class FuzzerPassAddCompositeTypes : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddCompositeTypes(); - void Apply() override; private: diff --git a/source/fuzz/fuzzer_pass_add_copy_memory.cpp b/source/fuzz/fuzzer_pass_add_copy_memory.cpp index d98619c2..b654927f 100644 --- a/source/fuzz/fuzzer_pass_add_copy_memory.cpp +++ b/source/fuzz/fuzzer_pass_add_copy_memory.cpp @@ -29,8 +29,6 @@ FuzzerPassAddCopyMemory::FuzzerPassAddCopyMemory( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddCopyMemory::~FuzzerPassAddCopyMemory() = default; - void FuzzerPassAddCopyMemory::Apply() { ForEachInstructionWithInstructionDescriptor( [this](opt::Function* function, opt::BasicBlock* block, diff --git a/source/fuzz/fuzzer_pass_add_copy_memory.h b/source/fuzz/fuzzer_pass_add_copy_memory.h index 321e4a1d..0f7db0c7 100644 --- a/source/fuzz/fuzzer_pass_add_copy_memory.h +++ b/source/fuzz/fuzzer_pass_add_copy_memory.h @@ -29,8 +29,6 @@ class FuzzerPassAddCopyMemory : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddCopyMemory() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_add_dead_blocks.cpp b/source/fuzz/fuzzer_pass_add_dead_blocks.cpp index 84ed1fb9..8c166a20 100644 --- a/source/fuzz/fuzzer_pass_add_dead_blocks.cpp +++ b/source/fuzz/fuzzer_pass_add_dead_blocks.cpp @@ -14,12 +14,20 @@ #include "source/fuzz/fuzzer_pass_add_dead_blocks.h" +#include <algorithm> + #include "source/fuzz/fuzzer_util.h" #include "source/fuzz/transformation_add_dead_block.h" namespace spvtools { namespace fuzz { +namespace { + +const size_t kMaxTransformationsInOnePass = 100U; + +} // namespace + FuzzerPassAddDeadBlocks::FuzzerPassAddDeadBlocks( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, @@ -27,8 +35,6 @@ FuzzerPassAddDeadBlocks::FuzzerPassAddDeadBlocks( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddDeadBlocks::~FuzzerPassAddDeadBlocks() = default; - void FuzzerPassAddDeadBlocks::Apply() { // We iterate over all blocks in the module collecting up those at which we // might add a branch to a new dead block. We then loop over all such @@ -57,9 +63,18 @@ void FuzzerPassAddDeadBlocks::Apply() { GetFuzzerContext()->GetFreshId(), block.id(), condition_value)); } } - // Apply all those transformations that are in fact applicable. - for (auto& transformation : candidate_transformations) { - MaybeApplyTransformation(transformation); + // Applying transformations can be expensive as each transformation requires + // dominator information and also invalidates dominator information. We thus + // limit the number of transformations that one application of this fuzzer + // pass can apply. We choose to do this after identifying all the + // transformations that we *might* want to apply, rather than breaking the + // above loops once the limit is reached, to avoid biasing towards + // transformations that target early parts of the module. + GetFuzzerContext()->Shuffle(&candidate_transformations); + for (size_t i = 0; i < std::min(kMaxTransformationsInOnePass, + candidate_transformations.size()); + i++) { + MaybeApplyTransformation(candidate_transformations[i]); } } diff --git a/source/fuzz/fuzzer_pass_add_dead_blocks.h b/source/fuzz/fuzzer_pass_add_dead_blocks.h index d78f0883..a87c05c3 100644 --- a/source/fuzz/fuzzer_pass_add_dead_blocks.h +++ b/source/fuzz/fuzzer_pass_add_dead_blocks.h @@ -29,8 +29,6 @@ class FuzzerPassAddDeadBlocks : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddDeadBlocks(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_add_dead_breaks.cpp b/source/fuzz/fuzzer_pass_add_dead_breaks.cpp index e726c63e..0c18da90 100644 --- a/source/fuzz/fuzzer_pass_add_dead_breaks.cpp +++ b/source/fuzz/fuzzer_pass_add_dead_breaks.cpp @@ -28,8 +28,6 @@ FuzzerPassAddDeadBreaks::FuzzerPassAddDeadBreaks( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddDeadBreaks::~FuzzerPassAddDeadBreaks() = default; - void FuzzerPassAddDeadBreaks::Apply() { // We first collect up lots of possibly-applicable transformations. std::vector<TransformationAddDeadBreak> candidate_transformations; diff --git a/source/fuzz/fuzzer_pass_add_dead_breaks.h b/source/fuzz/fuzzer_pass_add_dead_breaks.h index c379eed5..d1086fc4 100644 --- a/source/fuzz/fuzzer_pass_add_dead_breaks.h +++ b/source/fuzz/fuzzer_pass_add_dead_breaks.h @@ -28,8 +28,6 @@ class FuzzerPassAddDeadBreaks : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddDeadBreaks(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_add_dead_continues.cpp b/source/fuzz/fuzzer_pass_add_dead_continues.cpp index 24617ae3..1ab40b73 100644 --- a/source/fuzz/fuzzer_pass_add_dead_continues.cpp +++ b/source/fuzz/fuzzer_pass_add_dead_continues.cpp @@ -28,8 +28,6 @@ FuzzerPassAddDeadContinues::FuzzerPassAddDeadContinues( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddDeadContinues::~FuzzerPassAddDeadContinues() = default; - void FuzzerPassAddDeadContinues::Apply() { // Consider every block in every function. for (auto& function : *GetIRContext()->module()) { diff --git a/source/fuzz/fuzzer_pass_add_dead_continues.h b/source/fuzz/fuzzer_pass_add_dead_continues.h index b2acb935..bf0009e4 100644 --- a/source/fuzz/fuzzer_pass_add_dead_continues.h +++ b/source/fuzz/fuzzer_pass_add_dead_continues.h @@ -28,8 +28,6 @@ class FuzzerPassAddDeadContinues : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddDeadContinues(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_add_equation_instructions.cpp b/source/fuzz/fuzzer_pass_add_equation_instructions.cpp index 6376c9fc..15554b7a 100644 --- a/source/fuzz/fuzzer_pass_add_equation_instructions.cpp +++ b/source/fuzz/fuzzer_pass_add_equation_instructions.cpp @@ -49,9 +49,6 @@ FuzzerPassAddEquationInstructions::FuzzerPassAddEquationInstructions( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddEquationInstructions::~FuzzerPassAddEquationInstructions() = - default; - void FuzzerPassAddEquationInstructions::Apply() { ForEachInstructionWithInstructionDescriptor( [this](opt::Function* function, opt::BasicBlock* block, diff --git a/source/fuzz/fuzzer_pass_add_equation_instructions.h b/source/fuzz/fuzzer_pass_add_equation_instructions.h index 9ce581eb..dbec5bac 100644 --- a/source/fuzz/fuzzer_pass_add_equation_instructions.h +++ b/source/fuzz/fuzzer_pass_add_equation_instructions.h @@ -31,8 +31,6 @@ class FuzzerPassAddEquationInstructions : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddEquationInstructions(); - void Apply() override; private: diff --git a/source/fuzz/fuzzer_pass_add_function_calls.cpp b/source/fuzz/fuzzer_pass_add_function_calls.cpp index 74005579..2240696b 100644 --- a/source/fuzz/fuzzer_pass_add_function_calls.cpp +++ b/source/fuzz/fuzzer_pass_add_function_calls.cpp @@ -30,8 +30,6 @@ FuzzerPassAddFunctionCalls::FuzzerPassAddFunctionCalls( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddFunctionCalls::~FuzzerPassAddFunctionCalls() = default; - void FuzzerPassAddFunctionCalls::Apply() { ForEachInstructionWithInstructionDescriptor( [this](opt::Function* function, opt::BasicBlock* block, diff --git a/source/fuzz/fuzzer_pass_add_function_calls.h b/source/fuzz/fuzzer_pass_add_function_calls.h index 4ed87911..081510c1 100644 --- a/source/fuzz/fuzzer_pass_add_function_calls.h +++ b/source/fuzz/fuzzer_pass_add_function_calls.h @@ -29,8 +29,6 @@ class FuzzerPassAddFunctionCalls : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddFunctionCalls(); - void Apply() override; private: diff --git a/source/fuzz/fuzzer_pass_add_global_variables.cpp b/source/fuzz/fuzzer_pass_add_global_variables.cpp index 9a45a374..06797413 100644 --- a/source/fuzz/fuzzer_pass_add_global_variables.cpp +++ b/source/fuzz/fuzzer_pass_add_global_variables.cpp @@ -27,8 +27,6 @@ FuzzerPassAddGlobalVariables::FuzzerPassAddGlobalVariables( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddGlobalVariables::~FuzzerPassAddGlobalVariables() = default; - void FuzzerPassAddGlobalVariables::Apply() { SpvStorageClass variable_storage_class = SpvStorageClassPrivate; for (auto& entry_point : GetIRContext()->module()->entry_points()) { diff --git a/source/fuzz/fuzzer_pass_add_global_variables.h b/source/fuzz/fuzzer_pass_add_global_variables.h index a907d360..3745c5c3 100644 --- a/source/fuzz/fuzzer_pass_add_global_variables.h +++ b/source/fuzz/fuzzer_pass_add_global_variables.h @@ -29,8 +29,6 @@ class FuzzerPassAddGlobalVariables : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddGlobalVariables(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp b/source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp index 3095bb6e..c10db720 100644 --- a/source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp +++ b/source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp @@ -31,9 +31,6 @@ FuzzerPassAddImageSampleUnusedComponents:: : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddImageSampleUnusedComponents:: - ~FuzzerPassAddImageSampleUnusedComponents() = default; - void FuzzerPassAddImageSampleUnusedComponents::Apply() { // SPIR-V module to help understand the transformation. // diff --git a/source/fuzz/fuzzer_pass_add_image_sample_unused_components.h b/source/fuzz/fuzzer_pass_add_image_sample_unused_components.h index 26374c32..f5dea8bf 100644 --- a/source/fuzz/fuzzer_pass_add_image_sample_unused_components.h +++ b/source/fuzz/fuzzer_pass_add_image_sample_unused_components.h @@ -30,8 +30,6 @@ class FuzzerPassAddImageSampleUnusedComponents : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddImageSampleUnusedComponents(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_add_loads.cpp b/source/fuzz/fuzzer_pass_add_loads.cpp index 256255bc..2e50da26 100644 --- a/source/fuzz/fuzzer_pass_add_loads.cpp +++ b/source/fuzz/fuzzer_pass_add_loads.cpp @@ -27,8 +27,6 @@ FuzzerPassAddLoads::FuzzerPassAddLoads( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddLoads::~FuzzerPassAddLoads() = default; - void FuzzerPassAddLoads::Apply() { ForEachInstructionWithInstructionDescriptor( [this](opt::Function* function, opt::BasicBlock* block, diff --git a/source/fuzz/fuzzer_pass_add_loads.h b/source/fuzz/fuzzer_pass_add_loads.h index c4d5b27e..3913c624 100644 --- a/source/fuzz/fuzzer_pass_add_loads.h +++ b/source/fuzz/fuzzer_pass_add_loads.h @@ -28,8 +28,6 @@ class FuzzerPassAddLoads : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddLoads(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_add_local_variables.cpp b/source/fuzz/fuzzer_pass_add_local_variables.cpp index ef8b5d0e..a50b0b07 100644 --- a/source/fuzz/fuzzer_pass_add_local_variables.cpp +++ b/source/fuzz/fuzzer_pass_add_local_variables.cpp @@ -28,8 +28,6 @@ FuzzerPassAddLocalVariables::FuzzerPassAddLocalVariables( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddLocalVariables::~FuzzerPassAddLocalVariables() = default; - void FuzzerPassAddLocalVariables::Apply() { auto basic_type_ids_and_pointers = GetAvailableBasicTypesAndPointers(SpvStorageClassFunction); diff --git a/source/fuzz/fuzzer_pass_add_local_variables.h b/source/fuzz/fuzzer_pass_add_local_variables.h index 08d26d8c..d73dae29 100644 --- a/source/fuzz/fuzzer_pass_add_local_variables.h +++ b/source/fuzz/fuzzer_pass_add_local_variables.h @@ -29,8 +29,6 @@ class FuzzerPassAddLocalVariables : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddLocalVariables(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_add_loop_preheaders.cpp b/source/fuzz/fuzzer_pass_add_loop_preheaders.cpp index bdc31513..1cfed866 100644 --- a/source/fuzz/fuzzer_pass_add_loop_preheaders.cpp +++ b/source/fuzz/fuzzer_pass_add_loop_preheaders.cpp @@ -27,8 +27,6 @@ FuzzerPassAddLoopPreheaders::FuzzerPassAddLoopPreheaders( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddLoopPreheaders::~FuzzerPassAddLoopPreheaders() = default; - void FuzzerPassAddLoopPreheaders::Apply() { for (auto& function : *GetIRContext()->module()) { // Keep track of all the loop headers we want to add a preheader to. diff --git a/source/fuzz/fuzzer_pass_add_loop_preheaders.h b/source/fuzz/fuzzer_pass_add_loop_preheaders.h index a8350567..8ac2dac8 100644 --- a/source/fuzz/fuzzer_pass_add_loop_preheaders.h +++ b/source/fuzz/fuzzer_pass_add_loop_preheaders.h @@ -32,8 +32,6 @@ class FuzzerPassAddLoopPreheaders : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddLoopPreheaders(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.cpp b/source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.cpp index 31a57798..69e0697f 100644 --- a/source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.cpp +++ b/source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.cpp @@ -33,9 +33,6 @@ FuzzerPassAddLoopsToCreateIntConstantSynonyms:: : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddLoopsToCreateIntConstantSynonyms:: - ~FuzzerPassAddLoopsToCreateIntConstantSynonyms() = default; - void FuzzerPassAddLoopsToCreateIntConstantSynonyms::Apply() { std::vector<uint32_t> constants; diff --git a/source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.h b/source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.h index ee98c4e7..2eacef5f 100644 --- a/source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.h +++ b/source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.h @@ -30,8 +30,6 @@ class FuzzerPassAddLoopsToCreateIntConstantSynonyms : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddLoopsToCreateIntConstantSynonyms(); - void Apply() override; private: diff --git a/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp b/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp index 09627d09..d0753100 100644 --- a/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp +++ b/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp @@ -26,9 +26,6 @@ FuzzerPassAddNoContractionDecorations::FuzzerPassAddNoContractionDecorations( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddNoContractionDecorations:: - ~FuzzerPassAddNoContractionDecorations() = default; - void FuzzerPassAddNoContractionDecorations::Apply() { // Consider every instruction in every block in every function. for (auto& function : *GetIRContext()->module()) { diff --git a/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h b/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h index c0c1e09d..74212d87 100644 --- a/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h +++ b/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h @@ -28,8 +28,6 @@ class FuzzerPassAddNoContractionDecorations : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddNoContractionDecorations() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp b/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp index 2b339ca0..be6e7ea1 100644 --- a/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp +++ b/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp @@ -27,8 +27,6 @@ FuzzerPassAddOpPhiSynonyms::FuzzerPassAddOpPhiSynonyms( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddOpPhiSynonyms::~FuzzerPassAddOpPhiSynonyms() = default; - void FuzzerPassAddOpPhiSynonyms::Apply() { // Get a list of synonymous ids with the same type that can be used in the // same OpPhi instruction. diff --git a/source/fuzz/fuzzer_pass_add_opphi_synonyms.h b/source/fuzz/fuzzer_pass_add_opphi_synonyms.h index 6c7d7522..9077118e 100644 --- a/source/fuzz/fuzzer_pass_add_opphi_synonyms.h +++ b/source/fuzz/fuzzer_pass_add_opphi_synonyms.h @@ -30,8 +30,6 @@ class FuzzerPassAddOpPhiSynonyms : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddOpPhiSynonyms() override; - void Apply() override; // Computes the equivalence classes for the non-pointer and non-irrelevant ids diff --git a/source/fuzz/fuzzer_pass_add_parameters.cpp b/source/fuzz/fuzzer_pass_add_parameters.cpp index 35532e90..784653d8 100644 --- a/source/fuzz/fuzzer_pass_add_parameters.cpp +++ b/source/fuzz/fuzzer_pass_add_parameters.cpp @@ -29,8 +29,6 @@ FuzzerPassAddParameters::FuzzerPassAddParameters( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddParameters::~FuzzerPassAddParameters() = default; - void FuzzerPassAddParameters::Apply() { // Compute type candidates for the new parameter. std::vector<uint32_t> type_candidates; diff --git a/source/fuzz/fuzzer_pass_add_parameters.h b/source/fuzz/fuzzer_pass_add_parameters.h index f1261ae5..47dde390 100644 --- a/source/fuzz/fuzzer_pass_add_parameters.h +++ b/source/fuzz/fuzzer_pass_add_parameters.h @@ -32,8 +32,6 @@ class FuzzerPassAddParameters : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddParameters() override; - void Apply() override; private: diff --git a/source/fuzz/fuzzer_pass_add_relaxed_decorations.cpp b/source/fuzz/fuzzer_pass_add_relaxed_decorations.cpp index a2497df7..58c6d1b2 100644 --- a/source/fuzz/fuzzer_pass_add_relaxed_decorations.cpp +++ b/source/fuzz/fuzzer_pass_add_relaxed_decorations.cpp @@ -26,8 +26,6 @@ FuzzerPassAddRelaxedDecorations::FuzzerPassAddRelaxedDecorations( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddRelaxedDecorations::~FuzzerPassAddRelaxedDecorations() = default; - void FuzzerPassAddRelaxedDecorations::Apply() { // Consider every instruction in every block in every function. for (auto& function : *GetIRContext()->module()) { diff --git a/source/fuzz/fuzzer_pass_add_relaxed_decorations.h b/source/fuzz/fuzzer_pass_add_relaxed_decorations.h index 897b8216..723c4a0a 100644 --- a/source/fuzz/fuzzer_pass_add_relaxed_decorations.h +++ b/source/fuzz/fuzzer_pass_add_relaxed_decorations.h @@ -28,8 +28,6 @@ class FuzzerPassAddRelaxedDecorations : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddRelaxedDecorations() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_add_stores.cpp b/source/fuzz/fuzzer_pass_add_stores.cpp index 46efc643..f89428d3 100644 --- a/source/fuzz/fuzzer_pass_add_stores.cpp +++ b/source/fuzz/fuzzer_pass_add_stores.cpp @@ -27,8 +27,6 @@ FuzzerPassAddStores::FuzzerPassAddStores( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddStores::~FuzzerPassAddStores() = default; - void FuzzerPassAddStores::Apply() { ForEachInstructionWithInstructionDescriptor( [this](opt::Function* function, opt::BasicBlock* block, diff --git a/source/fuzz/fuzzer_pass_add_stores.h b/source/fuzz/fuzzer_pass_add_stores.h index 55ec67f2..9519c385 100644 --- a/source/fuzz/fuzzer_pass_add_stores.h +++ b/source/fuzz/fuzzer_pass_add_stores.h @@ -30,8 +30,6 @@ class FuzzerPassAddStores : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddStores(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_add_synonyms.cpp b/source/fuzz/fuzzer_pass_add_synonyms.cpp index 2fa07000..2a85e52c 100644 --- a/source/fuzz/fuzzer_pass_add_synonyms.cpp +++ b/source/fuzz/fuzzer_pass_add_synonyms.cpp @@ -29,8 +29,6 @@ FuzzerPassAddSynonyms::FuzzerPassAddSynonyms( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddSynonyms::~FuzzerPassAddSynonyms() = default; - void FuzzerPassAddSynonyms::Apply() { ForEachInstructionWithInstructionDescriptor( [this](opt::Function* function, opt::BasicBlock* block, diff --git a/source/fuzz/fuzzer_pass_add_synonyms.h b/source/fuzz/fuzzer_pass_add_synonyms.h index dcfb9389..ccf4a886 100644 --- a/source/fuzz/fuzzer_pass_add_synonyms.h +++ b/source/fuzz/fuzzer_pass_add_synonyms.h @@ -29,8 +29,6 @@ class FuzzerPassAddSynonyms : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddSynonyms() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp b/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp index 453448ba..e2eaaa0a 100644 --- a/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp +++ b/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp @@ -28,9 +28,6 @@ FuzzerPassAddVectorShuffleInstructions::FuzzerPassAddVectorShuffleInstructions( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAddVectorShuffleInstructions:: - ~FuzzerPassAddVectorShuffleInstructions() = default; - void FuzzerPassAddVectorShuffleInstructions::Apply() { ForEachInstructionWithInstructionDescriptor( [this](opt::Function* function, opt::BasicBlock* block, diff --git a/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h b/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h index 99b9f244..c5af374c 100644 --- a/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h +++ b/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h @@ -28,8 +28,6 @@ class FuzzerPassAddVectorShuffleInstructions : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAddVectorShuffleInstructions(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_adjust_branch_weights.cpp b/source/fuzz/fuzzer_pass_adjust_branch_weights.cpp index 1d6d4347..3c4f3803 100644 --- a/source/fuzz/fuzzer_pass_adjust_branch_weights.cpp +++ b/source/fuzz/fuzzer_pass_adjust_branch_weights.cpp @@ -28,8 +28,6 @@ FuzzerPassAdjustBranchWeights::FuzzerPassAdjustBranchWeights( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAdjustBranchWeights::~FuzzerPassAdjustBranchWeights() = default; - void FuzzerPassAdjustBranchWeights::Apply() { // For all OpBranchConditional instructions, // randomly applies the transformation. diff --git a/source/fuzz/fuzzer_pass_adjust_branch_weights.h b/source/fuzz/fuzzer_pass_adjust_branch_weights.h index 5b2b33f1..de2f33d3 100644 --- a/source/fuzz/fuzzer_pass_adjust_branch_weights.h +++ b/source/fuzz/fuzzer_pass_adjust_branch_weights.h @@ -30,8 +30,6 @@ class FuzzerPassAdjustBranchWeights : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAdjustBranchWeights(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_adjust_function_controls.cpp b/source/fuzz/fuzzer_pass_adjust_function_controls.cpp index aa62d2f8..b38bd212 100644 --- a/source/fuzz/fuzzer_pass_adjust_function_controls.cpp +++ b/source/fuzz/fuzzer_pass_adjust_function_controls.cpp @@ -26,8 +26,6 @@ FuzzerPassAdjustFunctionControls::FuzzerPassAdjustFunctionControls( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAdjustFunctionControls::~FuzzerPassAdjustFunctionControls() = default; - void FuzzerPassAdjustFunctionControls::Apply() { // Consider every function in the module. for (auto& function : *GetIRContext()->module()) { diff --git a/source/fuzz/fuzzer_pass_adjust_function_controls.h b/source/fuzz/fuzzer_pass_adjust_function_controls.h index 5fdbe432..5ef32a18 100644 --- a/source/fuzz/fuzzer_pass_adjust_function_controls.h +++ b/source/fuzz/fuzzer_pass_adjust_function_controls.h @@ -28,8 +28,6 @@ class FuzzerPassAdjustFunctionControls : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAdjustFunctionControls() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp b/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp index f7addffe..0f7cf037 100644 --- a/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp +++ b/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp @@ -26,8 +26,6 @@ FuzzerPassAdjustLoopControls::FuzzerPassAdjustLoopControls( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAdjustLoopControls::~FuzzerPassAdjustLoopControls() = default; - void FuzzerPassAdjustLoopControls::Apply() { // Consider every merge instruction in the module (via looking through all // functions and blocks). diff --git a/source/fuzz/fuzzer_pass_adjust_loop_controls.h b/source/fuzz/fuzzer_pass_adjust_loop_controls.h index f133b2d1..4ca670b7 100644 --- a/source/fuzz/fuzzer_pass_adjust_loop_controls.h +++ b/source/fuzz/fuzzer_pass_adjust_loop_controls.h @@ -28,8 +28,6 @@ class FuzzerPassAdjustLoopControls : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAdjustLoopControls() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp b/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp index 68f0ca7e..778d43ff 100644 --- a/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp +++ b/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp @@ -27,9 +27,6 @@ FuzzerPassAdjustMemoryOperandsMasks::FuzzerPassAdjustMemoryOperandsMasks( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAdjustMemoryOperandsMasks::~FuzzerPassAdjustMemoryOperandsMasks() = - default; - void FuzzerPassAdjustMemoryOperandsMasks::Apply() { // Consider every block in every function. for (auto& function : *GetIRContext()->module()) { diff --git a/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h b/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h index 699dcb5a..a068b8dd 100644 --- a/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h +++ b/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h @@ -29,8 +29,6 @@ class FuzzerPassAdjustMemoryOperandsMasks : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAdjustMemoryOperandsMasks(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp b/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp index 83b1854e..d9b4e293 100644 --- a/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp +++ b/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp @@ -26,9 +26,6 @@ FuzzerPassAdjustSelectionControls::FuzzerPassAdjustSelectionControls( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassAdjustSelectionControls::~FuzzerPassAdjustSelectionControls() = - default; - void FuzzerPassAdjustSelectionControls::Apply() { // Consider every merge instruction in the module (via looking through all // functions and blocks). diff --git a/source/fuzz/fuzzer_pass_adjust_selection_controls.h b/source/fuzz/fuzzer_pass_adjust_selection_controls.h index 910b40d6..6931f942 100644 --- a/source/fuzz/fuzzer_pass_adjust_selection_controls.h +++ b/source/fuzz/fuzzer_pass_adjust_selection_controls.h @@ -28,8 +28,6 @@ class FuzzerPassAdjustSelectionControls : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassAdjustSelectionControls() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp b/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp index 38553d25..71208313 100644 --- a/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp +++ b/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp @@ -32,8 +32,6 @@ FuzzerPassApplyIdSynonyms::FuzzerPassApplyIdSynonyms( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassApplyIdSynonyms::~FuzzerPassApplyIdSynonyms() = default; - void FuzzerPassApplyIdSynonyms::Apply() { // Compute a closure of data synonym facts, to enrich the pool of synonyms // that are available. diff --git a/source/fuzz/fuzzer_pass_apply_id_synonyms.h b/source/fuzz/fuzzer_pass_apply_id_synonyms.h index 5deac105..b402b509 100644 --- a/source/fuzz/fuzzer_pass_apply_id_synonyms.h +++ b/source/fuzz/fuzzer_pass_apply_id_synonyms.h @@ -30,8 +30,6 @@ class FuzzerPassApplyIdSynonyms : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassApplyIdSynonyms() override; - void Apply() override; private: diff --git a/source/fuzz/fuzzer_pass_construct_composites.cpp b/source/fuzz/fuzzer_pass_construct_composites.cpp index 584fa1a9..1a174cf1 100644 --- a/source/fuzz/fuzzer_pass_construct_composites.cpp +++ b/source/fuzz/fuzzer_pass_construct_composites.cpp @@ -16,6 +16,7 @@ #include <memory> +#include "source/fuzz/available_instructions.h" #include "source/fuzz/fuzzer_util.h" #include "source/fuzz/transformation_composite_construct.h" @@ -29,8 +30,6 @@ FuzzerPassConstructComposites::FuzzerPassConstructComposites( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassConstructComposites::~FuzzerPassConstructComposites() = default; - void FuzzerPassConstructComposites::Apply() { // Gather up the ids of all composite types, but skip block-/buffer // block-decorated struct types. @@ -44,12 +43,40 @@ void FuzzerPassConstructComposites::Apply() { } } + if (composite_type_ids.empty()) { + // There are no composite types, so this fuzzer pass cannot do anything. + return; + } + + AvailableInstructions available_composite_constituents( + GetIRContext(), + [this](opt::IRContext* ir_context, opt::Instruction* inst) -> bool { + if (!inst->result_id() || !inst->type_id()) { + return false; + } + + // If the id is irrelevant, we can use it since it will not + // participate in DataSynonym fact. Otherwise, we should be able + // to produce a synonym out of the id. + return GetTransformationContext()->GetFactManager()->IdIsIrrelevant( + inst->result_id()) || + fuzzerutil::CanMakeSynonymOf(ir_context, + *GetTransformationContext(), inst); + }); + ForEachInstructionWithInstructionDescriptor( - [this, &composite_type_ids]( - opt::Function* function, opt::BasicBlock* block, + [this, &available_composite_constituents, &composite_type_ids]( + opt::Function* /*unused*/, opt::BasicBlock* /*unused*/, opt::BasicBlock::iterator inst_it, const protobufs::InstructionDescriptor& instruction_descriptor) -> void { + // Randomly decide whether to try inserting a composite construction + // here. + if (!GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfConstructingComposite())) { + return; + } + // Check whether it is legitimate to insert a composite construction // before the instruction. if (!fuzzerutil::CanInsertOpcodeBeforeInstruction( @@ -57,36 +84,21 @@ void FuzzerPassConstructComposites::Apply() { return; } - // Randomly decide whether to try inserting an object copy here. - if (!GetFuzzerContext()->ChoosePercentage( - GetFuzzerContext()->GetChanceOfConstructingComposite())) { - return; - } - // For each instruction that is available at this program point (i.e. an // instruction that is global or whose definition strictly dominates the // program point) and suitable for making a synonym of, associate it // with the id of its result type. TypeIdToInstructions type_id_to_available_instructions; - auto available_instructions = FindAvailableInstructions( - function, block, inst_it, - [this](opt::IRContext* ir_context, opt::Instruction* inst) { - if (!inst->result_id() || !inst->type_id()) { - return false; - } - - // If the id is irrelevant, we can use it since it will not - // participate in DataSynonym fact. Otherwise, we should be able - // to produce a synonym out of the id. - return GetTransformationContext() - ->GetFactManager() - ->IdIsIrrelevant(inst->result_id()) || - fuzzerutil::CanMakeSynonymOf( - ir_context, *GetTransformationContext(), inst); - }); - for (auto instruction : available_instructions) { - RecordAvailableInstruction(instruction, - &type_id_to_available_instructions); + auto available_instructions = + available_composite_constituents.GetAvailableBeforeInstruction( + &*inst_it); + for (uint32_t available_instruction_index = 0; + available_instruction_index < available_instructions.size(); + available_instruction_index++) { + opt::Instruction* inst = + available_instructions[available_instruction_index]; + type_id_to_available_instructions[inst->type_id()].push_back( + inst->result_id()); } // At this point, |composite_type_ids| captures all the composite types @@ -94,68 +106,41 @@ void FuzzerPassConstructComposites::Apply() { // captures all the available result ids we might use, organized by // type. - // Now we try to find a composite that we can construct. We might not - // manage, if there is a paucity of available ingredients in the module - // (e.g. if our only available composite was a boolean vector and we had - // no instructions generating boolean result types available). - // - // If we succeed, |chosen_composite_type| will end up being non-zero, - // and |constructor_arguments| will end up giving us result ids suitable - // for constructing a composite of that type. Otherwise these variables - // will remain 0 and null respectively. - uint32_t chosen_composite_type = 0; - std::vector<uint32_t> constructor_arguments; + // Now we choose a composite type to construct, building it from + // available constituent components and using zero constants if suitable + // components are not available. - // Initially, all composite type ids are available for us to try. Keep - // trying until we run out of options. - auto composites_to_try_constructing = composite_type_ids; - while (!composites_to_try_constructing.empty()) { - // Remove a composite type from the composite types left for us to - // try. - auto next_composite_to_try_constructing = - GetFuzzerContext()->RemoveAtRandomIndex( - &composites_to_try_constructing); - - // Now try to construct a composite of this type, using an appropriate - // helper method depending on the kind of composite type. - auto composite_type_inst = GetIRContext()->get_def_use_mgr()->GetDef( - next_composite_to_try_constructing); - switch (composite_type_inst->opcode()) { - case SpvOpTypeArray: - constructor_arguments = FindComponentsToConstructArray( - *composite_type_inst, type_id_to_available_instructions); - break; - case SpvOpTypeMatrix: - constructor_arguments = FindComponentsToConstructMatrix( - *composite_type_inst, type_id_to_available_instructions); - break; - case SpvOpTypeStruct: - constructor_arguments = FindComponentsToConstructStruct( - *composite_type_inst, type_id_to_available_instructions); - break; - case SpvOpTypeVector: - constructor_arguments = FindComponentsToConstructVector( - *composite_type_inst, type_id_to_available_instructions); - break; - default: - assert(false && - "The space of possible composite types should be covered " - "by the above cases."); - break; - } - if (!constructor_arguments.empty()) { - // We succeeded! Note the composite type we finally settled on, and - // exit from the loop. - chosen_composite_type = next_composite_to_try_constructing; + std::vector<uint32_t> constructor_arguments; + uint32_t chosen_composite_type = + composite_type_ids[GetFuzzerContext()->RandomIndex( + composite_type_ids)]; + + // Construct a composite of this type, using an appropriate helper + // method depending on the kind of composite type. + auto composite_type_inst = + GetIRContext()->get_def_use_mgr()->GetDef(chosen_composite_type); + switch (composite_type_inst->opcode()) { + case SpvOpTypeArray: + constructor_arguments = FindComponentsToConstructArray( + *composite_type_inst, type_id_to_available_instructions); + break; + case SpvOpTypeMatrix: + constructor_arguments = FindComponentsToConstructMatrix( + *composite_type_inst, type_id_to_available_instructions); + break; + case SpvOpTypeStruct: + constructor_arguments = FindComponentsToConstructStruct( + *composite_type_inst, type_id_to_available_instructions); + break; + case SpvOpTypeVector: + constructor_arguments = FindComponentsToConstructVector( + *composite_type_inst, type_id_to_available_instructions); + break; + default: + assert(false && + "The space of possible composite types should be covered " + "by the above cases."); break; - } - } - - if (!chosen_composite_type) { - // We did not manage to make a composite; return 0 to indicate that no - // instructions were added. - assert(constructor_arguments.empty()); - return; } assert(!constructor_arguments.empty()); @@ -166,15 +151,6 @@ void FuzzerPassConstructComposites::Apply() { }); } -void FuzzerPassConstructComposites::RecordAvailableInstruction( - opt::Instruction* inst, - TypeIdToInstructions* type_id_to_available_instructions) { - if (type_id_to_available_instructions->count(inst->type_id()) == 0) { - (*type_id_to_available_instructions)[inst->type_id()] = {}; - } - type_id_to_available_instructions->at(inst->type_id()).push_back(inst); -} - std::vector<uint32_t> FuzzerPassConstructComposites::FindComponentsToConstructArray( const opt::Instruction& array_type_instruction, @@ -190,13 +166,6 @@ FuzzerPassConstructComposites::FindComponentsToConstructArray( auto available_instructions = type_id_to_available_instructions.find(element_type_id); - if (available_instructions == type_id_to_available_instructions.cend()) { - // If there are not any instructions available that compute the element type - // of the array then we are not in a position to construct a composite with - // this array type. - return {}; - } - uint32_t array_length = GetIRContext() ->get_def_use_mgr() @@ -205,10 +174,14 @@ FuzzerPassConstructComposites::FindComponentsToConstructArray( std::vector<uint32_t> result; for (uint32_t index = 0; index < array_length; index++) { - result.push_back(available_instructions - ->second[GetFuzzerContext()->RandomIndex( - available_instructions->second)] - ->result_id()); + if (available_instructions == type_id_to_available_instructions.cend()) { + // No suitable instructions are available, so use a zero constant + result.push_back(FindOrCreateZeroConstant(element_type_id, true)); + } else { + result.push_back( + available_instructions->second[GetFuzzerContext()->RandomIndex( + available_instructions->second)]); + } } return result; } @@ -228,19 +201,17 @@ FuzzerPassConstructComposites::FindComponentsToConstructMatrix( auto available_instructions = type_id_to_available_instructions.find(element_type_id); - if (available_instructions == type_id_to_available_instructions.cend()) { - // If there are not any instructions available that compute the element type - // of the matrix then we are not in a position to construct a composite with - // this matrix type. - return {}; - } std::vector<uint32_t> result; for (uint32_t index = 0; index < matrix_type_instruction.GetSingleWordInOperand(1); index++) { - result.push_back(available_instructions - ->second[GetFuzzerContext()->RandomIndex( - available_instructions->second)] - ->result_id()); + if (available_instructions == type_id_to_available_instructions.cend()) { + // No suitable components are available, so use a zero constant. + result.push_back(FindOrCreateZeroConstant(element_type_id, true)); + } else { + result.push_back( + available_instructions->second[GetFuzzerContext()->RandomIndex( + available_instructions->second)]); + } } return result; } @@ -263,14 +234,14 @@ FuzzerPassConstructComposites::FindComponentsToConstructStruct( auto available_instructions = type_id_to_available_instructions.find(element_type_id); if (available_instructions == type_id_to_available_instructions.cend()) { - // If there are no such instructions, we cannot construct a composite of - // this struct type. - return {}; + // No suitable component is available for this element type, so use a zero + // constant. + result.push_back(FindOrCreateZeroConstant(element_type_id, true)); + } else { + result.push_back( + available_instructions->second[GetFuzzerContext()->RandomIndex( + available_instructions->second)]); } - result.push_back(available_instructions - ->second[GetFuzzerContext()->RandomIndex( - available_instructions->second)] - ->result_id()); } return result; } @@ -325,12 +296,13 @@ FuzzerPassConstructComposites::FindComponentsToConstructVector( // (otherwise there will not be space left for a vec3). uint32_t vector_slots_used = 0; - // The instructions we will use to construct the vector, in no particular - // order at this stage. - std::vector<opt::Instruction*> instructions_to_use; + + // The instructions result ids we will use to construct the vector, in no + // particular order at this stage. + std::vector<uint32_t> result; while (vector_slots_used < element_count) { - std::vector<opt::Instruction*> instructions_to_choose_from; + std::vector<uint32_t> instructions_to_choose_from; for (auto& entry : smaller_vector_type_id_to_width) { if (entry.second > std::min(element_count - 1, element_count - vector_slots_used)) { @@ -345,19 +317,16 @@ FuzzerPassConstructComposites::FindComponentsToConstructVector( available_instructions->second.begin(), available_instructions->second.end()); } - if (instructions_to_choose_from.empty()) { - // We may get unlucky and find that there are not any instructions to - // choose from. In this case we give up constructing a composite of this - // vector type. It might be that we could construct the composite in - // another manner, so we could opt to retry a few times here, but it is - // simpler to just give up on the basis that this will not happen - // frequently. - return {}; - } - auto instruction_to_use = - instructions_to_choose_from[GetFuzzerContext()->RandomIndex( - instructions_to_choose_from)]; - instructions_to_use.push_back(instruction_to_use); + // If there are no instructions to choose from then use a zero constant, + // otherwise select one of the instructions at random. + uint32_t id_of_instruction_to_use = + instructions_to_choose_from.empty() + ? FindOrCreateZeroConstant(element_type_id, true) + : instructions_to_choose_from[GetFuzzerContext()->RandomIndex( + instructions_to_choose_from)]; + opt::Instruction* instruction_to_use = + GetIRContext()->get_def_use_mgr()->GetDef(id_of_instruction_to_use); + result.push_back(instruction_to_use->result_id()); auto chosen_type = GetIRContext()->get_type_mgr()->GetType(instruction_to_use->type_id()); if (chosen_type->AsVector()) { @@ -373,14 +342,7 @@ FuzzerPassConstructComposites::FindComponentsToConstructVector( } assert(vector_slots_used == element_count); - std::vector<uint32_t> result; - std::vector<uint32_t> operands; - while (!instructions_to_use.empty()) { - auto index = GetFuzzerContext()->RandomIndex(instructions_to_use); - result.push_back(instructions_to_use[index]->result_id()); - instructions_to_use.erase(instructions_to_use.begin() + index); - } - assert(result.size() > 1); + GetFuzzerContext()->Shuffle(&result); return result; } diff --git a/source/fuzz/fuzzer_pass_construct_composites.h b/source/fuzz/fuzzer_pass_construct_composites.h index c140bded..333ac931 100644 --- a/source/fuzz/fuzzer_pass_construct_composites.h +++ b/source/fuzz/fuzzer_pass_construct_composites.h @@ -15,7 +15,7 @@ #ifndef SOURCE_FUZZ_FUZZER_PASS_CONSTRUCT_COMPOSITES_H_ #define SOURCE_FUZZ_FUZZER_PASS_CONSTRUCT_COMPOSITES_H_ -#include <map> +#include <unordered_map> #include <vector> #include "source/fuzz/fuzzer_pass.h" @@ -31,23 +31,12 @@ class FuzzerPassConstructComposites : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassConstructComposites(); - void Apply() override; private: - // Used to map a type id to relevant instructions whose result type matches - // the type id. - typedef std::map<uint32_t, std::vector<opt::Instruction*>> - TypeIdToInstructions; - - // Considers all instructions that are available at |inst| - instructions - // whose results could be packed into a composite - and updates - // |type_id_to_available_instructions| so that each such instruction is - // associated with its the id of its result type. - void RecordAvailableInstruction( - opt::Instruction* inst, - TypeIdToInstructions* type_id_to_available_instructions); + // Used to map a type id to the ids of relevant instructions of the type. + using TypeIdToInstructions = + std::unordered_map<uint32_t, std::vector<uint32_t>>; // Requires that |array_type_instruction| has opcode OpTypeArray. // Attempts to find suitable instruction result ids from the values of diff --git a/source/fuzz/fuzzer_pass_copy_objects.cpp b/source/fuzz/fuzzer_pass_copy_objects.cpp index 9f7bbd63..09b5368a 100644 --- a/source/fuzz/fuzzer_pass_copy_objects.cpp +++ b/source/fuzz/fuzzer_pass_copy_objects.cpp @@ -28,8 +28,6 @@ FuzzerPassCopyObjects::FuzzerPassCopyObjects( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassCopyObjects::~FuzzerPassCopyObjects() = default; - void FuzzerPassCopyObjects::Apply() { ForEachInstructionWithInstructionDescriptor( [this](opt::Function* function, opt::BasicBlock* block, diff --git a/source/fuzz/fuzzer_pass_copy_objects.h b/source/fuzz/fuzzer_pass_copy_objects.h index 8de382e7..461cd979 100644 --- a/source/fuzz/fuzzer_pass_copy_objects.h +++ b/source/fuzz/fuzzer_pass_copy_objects.h @@ -28,8 +28,6 @@ class FuzzerPassCopyObjects : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassCopyObjects(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_donate_modules.cpp b/source/fuzz/fuzzer_pass_donate_modules.cpp index 4cd48045..2f2ed50a 100644 --- a/source/fuzz/fuzzer_pass_donate_modules.cpp +++ b/source/fuzz/fuzzer_pass_donate_modules.cpp @@ -50,8 +50,6 @@ FuzzerPassDonateModules::FuzzerPassDonateModules( transformations), donor_suppliers_(donor_suppliers) {} -FuzzerPassDonateModules::~FuzzerPassDonateModules() = default; - void FuzzerPassDonateModules::Apply() { // If there are no donor suppliers, this fuzzer pass is a no-op. if (donor_suppliers_.empty()) { @@ -1202,11 +1200,14 @@ bool FuzzerPassDonateModules::MaybeAddLivesafeFunction( false); } - // Add the function in a livesafe manner. - ApplyTransformation(TransformationAddFunction( + // Try to add the function in a livesafe manner. This may fail due to edge + // cases, e.g. where adding loop limiters changes dominance such that the + // module becomes invalid. It would be ideal to handle all such edge cases, + // but as they are rare it is more pragmatic to bail out of making the + // function livesafe if the transformation's precondition fails to hold. + return MaybeApplyTransformation(TransformationAddFunction( donated_instructions, loop_limiter_variable_id, loop_limit, loop_limiters, kill_unreachable_return_value_id, access_chain_clamping_info)); - return true; } } // namespace fuzz diff --git a/source/fuzz/fuzzer_pass_donate_modules.h b/source/fuzz/fuzzer_pass_donate_modules.h index 0424cece..1581a8a4 100644 --- a/source/fuzz/fuzzer_pass_donate_modules.h +++ b/source/fuzz/fuzzer_pass_donate_modules.h @@ -33,8 +33,6 @@ class FuzzerPassDonateModules : public FuzzerPass { protobufs::TransformationSequence* transformations, const std::vector<fuzzerutil::ModuleSupplier>& donor_suppliers); - ~FuzzerPassDonateModules(); - void Apply() override; // Donates the global declarations and functions of |donor_ir_context| into diff --git a/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.cpp b/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.cpp index 1651a9d5..e08d65b1 100644 --- a/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.cpp +++ b/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.cpp @@ -29,9 +29,6 @@ FuzzerPassDuplicateRegionsWithSelections:: : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassDuplicateRegionsWithSelections:: - ~FuzzerPassDuplicateRegionsWithSelections() = default; - void FuzzerPassDuplicateRegionsWithSelections::Apply() { // Iterate over all of the functions in the module. for (auto& function : *GetIRContext()->module()) { diff --git a/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.h b/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.h index 3fae6983..7cb1197d 100644 --- a/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.h +++ b/source/fuzz/fuzzer_pass_duplicate_regions_with_selections.h @@ -31,8 +31,6 @@ class FuzzerPassDuplicateRegionsWithSelections : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassDuplicateRegionsWithSelections() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_expand_vector_reductions.cpp b/source/fuzz/fuzzer_pass_expand_vector_reductions.cpp index 1416fe0b..e25dcbc3 100644 --- a/source/fuzz/fuzzer_pass_expand_vector_reductions.cpp +++ b/source/fuzz/fuzzer_pass_expand_vector_reductions.cpp @@ -28,8 +28,6 @@ FuzzerPassExpandVectorReductions::FuzzerPassExpandVectorReductions( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassExpandVectorReductions::~FuzzerPassExpandVectorReductions() = default; - void FuzzerPassExpandVectorReductions::Apply() { for (auto& function : *GetIRContext()->module()) { for (auto& block : function) { diff --git a/source/fuzz/fuzzer_pass_expand_vector_reductions.h b/source/fuzz/fuzzer_pass_expand_vector_reductions.h index ae3238b6..ed0225df 100644 --- a/source/fuzz/fuzzer_pass_expand_vector_reductions.h +++ b/source/fuzz/fuzzer_pass_expand_vector_reductions.h @@ -30,8 +30,6 @@ class FuzzerPassExpandVectorReductions : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassExpandVectorReductions(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_flatten_conditional_branches.cpp b/source/fuzz/fuzzer_pass_flatten_conditional_branches.cpp index 1e21aa50..84da7a74 100644 --- a/source/fuzz/fuzzer_pass_flatten_conditional_branches.cpp +++ b/source/fuzz/fuzzer_pass_flatten_conditional_branches.cpp @@ -30,9 +30,6 @@ FuzzerPassFlattenConditionalBranches::FuzzerPassFlattenConditionalBranches( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassFlattenConditionalBranches::~FuzzerPassFlattenConditionalBranches() = - default; - void FuzzerPassFlattenConditionalBranches::Apply() { for (auto& function : *GetIRContext()->module()) { // Get all the selection headers that we want to flatten. We need to collect diff --git a/source/fuzz/fuzzer_pass_flatten_conditional_branches.h b/source/fuzz/fuzzer_pass_flatten_conditional_branches.h index 76f7782c..e7d7dc36 100644 --- a/source/fuzz/fuzzer_pass_flatten_conditional_branches.h +++ b/source/fuzz/fuzzer_pass_flatten_conditional_branches.h @@ -27,8 +27,6 @@ class FuzzerPassFlattenConditionalBranches : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassFlattenConditionalBranches() override; - void Apply() override; private: diff --git a/source/fuzz/fuzzer_pass_inline_functions.cpp b/source/fuzz/fuzzer_pass_inline_functions.cpp index 90160d83..405afd8b 100644 --- a/source/fuzz/fuzzer_pass_inline_functions.cpp +++ b/source/fuzz/fuzzer_pass_inline_functions.cpp @@ -29,8 +29,6 @@ FuzzerPassInlineFunctions::FuzzerPassInlineFunctions( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassInlineFunctions::~FuzzerPassInlineFunctions() = default; - void FuzzerPassInlineFunctions::Apply() { // |function_call_instructions| are the instructions that will be inlined. // First, they will be collected and then do the inlining in another loop. diff --git a/source/fuzz/fuzzer_pass_inline_functions.h b/source/fuzz/fuzzer_pass_inline_functions.h index 37295d1c..a6ed8cad 100644 --- a/source/fuzz/fuzzer_pass_inline_functions.h +++ b/source/fuzz/fuzzer_pass_inline_functions.h @@ -30,8 +30,6 @@ class FuzzerPassInlineFunctions : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassInlineFunctions() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.cpp b/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.cpp index 0e40b496..675cae9a 100644 --- a/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.cpp +++ b/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.cpp @@ -31,10 +31,10 @@ FuzzerPassInterchangeSignednessOfIntegerOperands:: : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassInterchangeSignednessOfIntegerOperands:: - ~FuzzerPassInterchangeSignednessOfIntegerOperands() = default; - void FuzzerPassInterchangeSignednessOfIntegerOperands::Apply() { + assert(!GetFuzzerContext()->IsWgslCompatible() && + "Cannot interchange signedness in WGSL"); + // Make vector keeping track of all the uses we want to replace. // This is a vector of pairs, where the first element is an id use descriptor // identifying the use of a constant id and the second is the id that should diff --git a/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.h b/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.h index 06882f47..11b8fb6e 100644 --- a/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.h +++ b/source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.h @@ -34,8 +34,6 @@ class FuzzerPassInterchangeSignednessOfIntegerOperands : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassInterchangeSignednessOfIntegerOperands() override; - void Apply() override; private: diff --git a/source/fuzz/fuzzer_pass_interchange_zero_like_constants.cpp b/source/fuzz/fuzzer_pass_interchange_zero_like_constants.cpp index 20575e11..5d0a2223 100644 --- a/source/fuzz/fuzzer_pass_interchange_zero_like_constants.cpp +++ b/source/fuzz/fuzzer_pass_interchange_zero_like_constants.cpp @@ -29,9 +29,6 @@ FuzzerPassInterchangeZeroLikeConstants::FuzzerPassInterchangeZeroLikeConstants( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassInterchangeZeroLikeConstants:: - ~FuzzerPassInterchangeZeroLikeConstants() = default; - uint32_t FuzzerPassInterchangeZeroLikeConstants::FindOrCreateToggledConstant( opt::Instruction* declaration) { // |declaration| must not be a specialization constant because we do not know diff --git a/source/fuzz/fuzzer_pass_interchange_zero_like_constants.h b/source/fuzz/fuzzer_pass_interchange_zero_like_constants.h index ef0f7655..012f03d3 100644 --- a/source/fuzz/fuzzer_pass_interchange_zero_like_constants.h +++ b/source/fuzz/fuzzer_pass_interchange_zero_like_constants.h @@ -35,8 +35,6 @@ class FuzzerPassInterchangeZeroLikeConstants : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassInterchangeZeroLikeConstants() override; - void Apply() override; private: diff --git a/source/fuzz/fuzzer_pass_invert_comparison_operators.cpp b/source/fuzz/fuzzer_pass_invert_comparison_operators.cpp index de4ff1de..542748e9 100644 --- a/source/fuzz/fuzzer_pass_invert_comparison_operators.cpp +++ b/source/fuzz/fuzzer_pass_invert_comparison_operators.cpp @@ -28,9 +28,6 @@ FuzzerPassInvertComparisonOperators::FuzzerPassInvertComparisonOperators( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassInvertComparisonOperators::~FuzzerPassInvertComparisonOperators() = - default; - void FuzzerPassInvertComparisonOperators::Apply() { GetIRContext()->module()->ForEachInst([this](const opt::Instruction* inst) { if (!TransformationInvertComparisonOperator::IsInversionSupported( diff --git a/source/fuzz/fuzzer_pass_invert_comparison_operators.h b/source/fuzz/fuzzer_pass_invert_comparison_operators.h index 9c80bbbb..5f015c28 100644 --- a/source/fuzz/fuzzer_pass_invert_comparison_operators.h +++ b/source/fuzz/fuzzer_pass_invert_comparison_operators.h @@ -29,8 +29,6 @@ class FuzzerPassInvertComparisonOperators : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassInvertComparisonOperators() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.cpp b/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.cpp index f4f2a802..7bf07a49 100644 --- a/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.cpp +++ b/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.cpp @@ -28,9 +28,6 @@ FuzzerPassMakeVectorOperationsDynamic::FuzzerPassMakeVectorOperationsDynamic( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassMakeVectorOperationsDynamic:: - ~FuzzerPassMakeVectorOperationsDynamic() = default; - void FuzzerPassMakeVectorOperationsDynamic::Apply() { for (auto& function : *GetIRContext()->module()) { for (auto& block : function) { diff --git a/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.h b/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.h index dd51cde7..da27825a 100644 --- a/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.h +++ b/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.h @@ -29,8 +29,6 @@ class FuzzerPassMakeVectorOperationsDynamic : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassMakeVectorOperationsDynamic() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_merge_blocks.cpp b/source/fuzz/fuzzer_pass_merge_blocks.cpp index e66fc444..a8ec784c 100644 --- a/source/fuzz/fuzzer_pass_merge_blocks.cpp +++ b/source/fuzz/fuzzer_pass_merge_blocks.cpp @@ -28,8 +28,6 @@ FuzzerPassMergeBlocks::FuzzerPassMergeBlocks( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassMergeBlocks::~FuzzerPassMergeBlocks() = default; - void FuzzerPassMergeBlocks::Apply() { // First we populate a sequence of transformations that we might consider // applying. diff --git a/source/fuzz/fuzzer_pass_merge_blocks.h b/source/fuzz/fuzzer_pass_merge_blocks.h index 1a6c2c27..66cf4c64 100644 --- a/source/fuzz/fuzzer_pass_merge_blocks.h +++ b/source/fuzz/fuzzer_pass_merge_blocks.h @@ -28,8 +28,6 @@ class FuzzerPassMergeBlocks : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassMergeBlocks(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_merge_function_returns.cpp b/source/fuzz/fuzzer_pass_merge_function_returns.cpp index fc9c74d0..70fa8200 100644 --- a/source/fuzz/fuzzer_pass_merge_function_returns.cpp +++ b/source/fuzz/fuzzer_pass_merge_function_returns.cpp @@ -30,8 +30,6 @@ FuzzerPassMergeFunctionReturns::FuzzerPassMergeFunctionReturns( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassMergeFunctionReturns::~FuzzerPassMergeFunctionReturns() = default; - void FuzzerPassMergeFunctionReturns::Apply() { // The pass might add new functions to the module (due to wrapping early // terminator instructions in function calls), so we record the functions that diff --git a/source/fuzz/fuzzer_pass_merge_function_returns.h b/source/fuzz/fuzzer_pass_merge_function_returns.h index 3b5a668f..ddd2c9dc 100644 --- a/source/fuzz/fuzzer_pass_merge_function_returns.h +++ b/source/fuzz/fuzzer_pass_merge_function_returns.h @@ -33,8 +33,6 @@ class FuzzerPassMergeFunctionReturns : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassMergeFunctionReturns(); - void Apply() override; private: diff --git a/source/fuzz/fuzzer_pass_mutate_pointers.cpp b/source/fuzz/fuzzer_pass_mutate_pointers.cpp index 89f5f5c0..f021a978 100644 --- a/source/fuzz/fuzzer_pass_mutate_pointers.cpp +++ b/source/fuzz/fuzzer_pass_mutate_pointers.cpp @@ -28,8 +28,6 @@ FuzzerPassMutatePointers::FuzzerPassMutatePointers( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassMutatePointers::~FuzzerPassMutatePointers() = default; - void FuzzerPassMutatePointers::Apply() { ForEachInstructionWithInstructionDescriptor( [this](opt::Function* function, opt::BasicBlock* block, diff --git a/source/fuzz/fuzzer_pass_mutate_pointers.h b/source/fuzz/fuzzer_pass_mutate_pointers.h index f77523ef..5ef6a2ab 100644 --- a/source/fuzz/fuzzer_pass_mutate_pointers.h +++ b/source/fuzz/fuzzer_pass_mutate_pointers.h @@ -28,8 +28,6 @@ class FuzzerPassMutatePointers : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassMutatePointers() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_obfuscate_constants.cpp b/source/fuzz/fuzzer_pass_obfuscate_constants.cpp index d87662ee..32318e89 100644 --- a/source/fuzz/fuzzer_pass_obfuscate_constants.cpp +++ b/source/fuzz/fuzzer_pass_obfuscate_constants.cpp @@ -34,8 +34,6 @@ FuzzerPassObfuscateConstants::FuzzerPassObfuscateConstants( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassObfuscateConstants::~FuzzerPassObfuscateConstants() = default; - void FuzzerPassObfuscateConstants::ObfuscateBoolConstantViaConstantPair( uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, const std::vector<SpvOp>& greater_than_opcodes, diff --git a/source/fuzz/fuzzer_pass_obfuscate_constants.h b/source/fuzz/fuzzer_pass_obfuscate_constants.h index d48b37f6..82b1092c 100644 --- a/source/fuzz/fuzzer_pass_obfuscate_constants.h +++ b/source/fuzz/fuzzer_pass_obfuscate_constants.h @@ -32,8 +32,6 @@ class FuzzerPassObfuscateConstants : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassObfuscateConstants() override; - void Apply() override; private: diff --git a/source/fuzz/fuzzer_pass_outline_functions.cpp b/source/fuzz/fuzzer_pass_outline_functions.cpp index 42101256..bfde61f7 100644 --- a/source/fuzz/fuzzer_pass_outline_functions.cpp +++ b/source/fuzz/fuzzer_pass_outline_functions.cpp @@ -31,8 +31,6 @@ FuzzerPassOutlineFunctions::FuzzerPassOutlineFunctions( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassOutlineFunctions::~FuzzerPassOutlineFunctions() = default; - void FuzzerPassOutlineFunctions::Apply() { std::vector<opt::Function*> original_functions; for (auto& function : *GetIRContext()->module()) { diff --git a/source/fuzz/fuzzer_pass_outline_functions.h b/source/fuzz/fuzzer_pass_outline_functions.h index 02022aa7..45e52ff4 100644 --- a/source/fuzz/fuzzer_pass_outline_functions.h +++ b/source/fuzz/fuzzer_pass_outline_functions.h @@ -29,8 +29,6 @@ class FuzzerPassOutlineFunctions : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassOutlineFunctions(); - void Apply() override; // Returns a block suitable to be an entry block for a region that can be diff --git a/source/fuzz/fuzzer_pass_permute_blocks.cpp b/source/fuzz/fuzzer_pass_permute_blocks.cpp index 24c16fbb..769c49f0 100644 --- a/source/fuzz/fuzzer_pass_permute_blocks.cpp +++ b/source/fuzz/fuzzer_pass_permute_blocks.cpp @@ -26,8 +26,6 @@ FuzzerPassPermuteBlocks::FuzzerPassPermuteBlocks( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassPermuteBlocks::~FuzzerPassPermuteBlocks() = default; - void FuzzerPassPermuteBlocks::Apply() { // For now we do something very simple: we randomly decide whether to move a // block, and for each block that we do move, we push it down as far as we diff --git a/source/fuzz/fuzzer_pass_permute_blocks.h b/source/fuzz/fuzzer_pass_permute_blocks.h index e5a672cb..e40178e6 100644 --- a/source/fuzz/fuzzer_pass_permute_blocks.h +++ b/source/fuzz/fuzzer_pass_permute_blocks.h @@ -29,8 +29,6 @@ class FuzzerPassPermuteBlocks : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassPermuteBlocks() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_permute_function_parameters.cpp b/source/fuzz/fuzzer_pass_permute_function_parameters.cpp index de6b03f3..9a61bea0 100644 --- a/source/fuzz/fuzzer_pass_permute_function_parameters.cpp +++ b/source/fuzz/fuzzer_pass_permute_function_parameters.cpp @@ -32,9 +32,6 @@ FuzzerPassPermuteFunctionParameters::FuzzerPassPermuteFunctionParameters( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassPermuteFunctionParameters::~FuzzerPassPermuteFunctionParameters() = - default; - void FuzzerPassPermuteFunctionParameters::Apply() { for (const auto& function : *GetIRContext()->module()) { uint32_t function_id = function.result_id(); diff --git a/source/fuzz/fuzzer_pass_permute_function_parameters.h b/source/fuzz/fuzzer_pass_permute_function_parameters.h index bc1031cb..a4bf2ca5 100644 --- a/source/fuzz/fuzzer_pass_permute_function_parameters.h +++ b/source/fuzz/fuzzer_pass_permute_function_parameters.h @@ -34,8 +34,6 @@ class FuzzerPassPermuteFunctionParameters : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassPermuteFunctionParameters() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_permute_instructions.cpp b/source/fuzz/fuzzer_pass_permute_instructions.cpp index 6867053c..f17e0187 100644 --- a/source/fuzz/fuzzer_pass_permute_instructions.cpp +++ b/source/fuzz/fuzzer_pass_permute_instructions.cpp @@ -29,8 +29,6 @@ FuzzerPassPermuteInstructions::FuzzerPassPermuteInstructions( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassPermuteInstructions::~FuzzerPassPermuteInstructions() = default; - void FuzzerPassPermuteInstructions::Apply() { // We are iterating over all instructions in all basic blocks. for (auto& function : *GetIRContext()->module()) { diff --git a/source/fuzz/fuzzer_pass_permute_instructions.h b/source/fuzz/fuzzer_pass_permute_instructions.h index e02ddfae..027101dd 100644 --- a/source/fuzz/fuzzer_pass_permute_instructions.h +++ b/source/fuzz/fuzzer_pass_permute_instructions.h @@ -29,8 +29,6 @@ class FuzzerPassPermuteInstructions : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassPermuteInstructions() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_permute_phi_operands.cpp b/source/fuzz/fuzzer_pass_permute_phi_operands.cpp index c379c535..f2cc5231 100644 --- a/source/fuzz/fuzzer_pass_permute_phi_operands.cpp +++ b/source/fuzz/fuzzer_pass_permute_phi_operands.cpp @@ -32,8 +32,6 @@ FuzzerPassPermutePhiOperands::FuzzerPassPermutePhiOperands( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassPermutePhiOperands::~FuzzerPassPermutePhiOperands() = default; - void FuzzerPassPermutePhiOperands::Apply() { ForEachInstructionWithInstructionDescriptor( [this](opt::Function* /*unused*/, opt::BasicBlock* /*unused*/, diff --git a/source/fuzz/fuzzer_pass_permute_phi_operands.h b/source/fuzz/fuzzer_pass_permute_phi_operands.h index 974c2c1e..79999562 100644 --- a/source/fuzz/fuzzer_pass_permute_phi_operands.h +++ b/source/fuzz/fuzzer_pass_permute_phi_operands.h @@ -29,8 +29,6 @@ class FuzzerPassPermutePhiOperands : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassPermutePhiOperands() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_propagate_instructions_down.cpp b/source/fuzz/fuzzer_pass_propagate_instructions_down.cpp index 7a115aec..af27a5da 100644 --- a/source/fuzz/fuzzer_pass_propagate_instructions_down.cpp +++ b/source/fuzz/fuzzer_pass_propagate_instructions_down.cpp @@ -27,9 +27,6 @@ FuzzerPassPropagateInstructionsDown::FuzzerPassPropagateInstructionsDown( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassPropagateInstructionsDown::~FuzzerPassPropagateInstructionsDown() = - default; - void FuzzerPassPropagateInstructionsDown::Apply() { for (const auto& function : *GetIRContext()->module()) { std::vector<const opt::BasicBlock*> reachable_blocks; diff --git a/source/fuzz/fuzzer_pass_propagate_instructions_down.h b/source/fuzz/fuzzer_pass_propagate_instructions_down.h index 536bf000..a2a0aac8 100644 --- a/source/fuzz/fuzzer_pass_propagate_instructions_down.h +++ b/source/fuzz/fuzzer_pass_propagate_instructions_down.h @@ -28,8 +28,6 @@ class FuzzerPassPropagateInstructionsDown : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassPropagateInstructionsDown() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_propagate_instructions_up.cpp b/source/fuzz/fuzzer_pass_propagate_instructions_up.cpp index 16ec680e..8cd7437b 100644 --- a/source/fuzz/fuzzer_pass_propagate_instructions_up.cpp +++ b/source/fuzz/fuzzer_pass_propagate_instructions_up.cpp @@ -29,9 +29,6 @@ FuzzerPassPropagateInstructionsUp::FuzzerPassPropagateInstructionsUp( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassPropagateInstructionsUp::~FuzzerPassPropagateInstructionsUp() = - default; - void FuzzerPassPropagateInstructionsUp::Apply() { for (const auto& function : *GetIRContext()->module()) { for (const auto& block : function) { diff --git a/source/fuzz/fuzzer_pass_propagate_instructions_up.h b/source/fuzz/fuzzer_pass_propagate_instructions_up.h index d915b31e..b89be48d 100644 --- a/source/fuzz/fuzzer_pass_propagate_instructions_up.h +++ b/source/fuzz/fuzzer_pass_propagate_instructions_up.h @@ -29,8 +29,6 @@ class FuzzerPassPropagateInstructionsUp : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassPropagateInstructionsUp() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp b/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp index 8d9acaa0..54e589c9 100644 --- a/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp +++ b/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp @@ -28,9 +28,6 @@ FuzzerPassPushIdsThroughVariables::FuzzerPassPushIdsThroughVariables( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassPushIdsThroughVariables::~FuzzerPassPushIdsThroughVariables() = - default; - void FuzzerPassPushIdsThroughVariables::Apply() { ForEachInstructionWithInstructionDescriptor( [this](opt::Function* function, opt::BasicBlock* block, diff --git a/source/fuzz/fuzzer_pass_push_ids_through_variables.h b/source/fuzz/fuzzer_pass_push_ids_through_variables.h index 3ad54042..53008ee2 100644 --- a/source/fuzz/fuzzer_pass_push_ids_through_variables.h +++ b/source/fuzz/fuzzer_pass_push_ids_through_variables.h @@ -30,8 +30,6 @@ class FuzzerPassPushIdsThroughVariables : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassPushIdsThroughVariables() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.cpp b/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.cpp index 139dc6e2..8a83d3bc 100644 --- a/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.cpp +++ b/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.cpp @@ -33,9 +33,6 @@ FuzzerPassReplaceAddsSubsMulsWithCarryingExtended:: : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassReplaceAddsSubsMulsWithCarryingExtended:: - ~FuzzerPassReplaceAddsSubsMulsWithCarryingExtended() = default; - void FuzzerPassReplaceAddsSubsMulsWithCarryingExtended::Apply() { std::vector<opt::Instruction> instructions_for_transformation; for (auto& function : *GetIRContext()->module()) { diff --git a/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h b/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h index dd39e6b0..0e29a6c6 100644 --- a/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h +++ b/source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h @@ -31,8 +31,6 @@ class FuzzerPassReplaceAddsSubsMulsWithCarryingExtended : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassReplaceAddsSubsMulsWithCarryingExtended() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.cpp b/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.cpp index e6bebead..a516f3d4 100644 --- a/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.cpp +++ b/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.cpp @@ -32,9 +32,6 @@ FuzzerPassReplaceBranchesFromDeadBlocksWithExits:: : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassReplaceBranchesFromDeadBlocksWithExits:: - ~FuzzerPassReplaceBranchesFromDeadBlocksWithExits() = default; - void FuzzerPassReplaceBranchesFromDeadBlocksWithExits::Apply() { // OpKill can only be used as a terminator in a function that is guaranteed // to be executed with the Fragment execution model. We conservatively only diff --git a/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.h b/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.h index 62164b32..ab7e00e5 100644 --- a/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.h +++ b/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.h @@ -30,8 +30,6 @@ class FuzzerPassReplaceBranchesFromDeadBlocksWithExits : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassReplaceBranchesFromDeadBlocksWithExits() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.cpp b/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.cpp index 68471466..f17339a9 100644 --- a/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.cpp +++ b/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.cpp @@ -30,9 +30,6 @@ FuzzerPassReplaceCopyMemoriesWithLoadsStores:: : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassReplaceCopyMemoriesWithLoadsStores:: - ~FuzzerPassReplaceCopyMemoriesWithLoadsStores() = default; - void FuzzerPassReplaceCopyMemoriesWithLoadsStores::Apply() { GetIRContext()->module()->ForEachInst([this](opt::Instruction* instruction) { // Randomly decide whether to replace the OpCopyMemory. diff --git a/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.h b/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.h index 9c24ac73..cffe1cb9 100644 --- a/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.h +++ b/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.h @@ -30,8 +30,6 @@ class FuzzerPassReplaceCopyMemoriesWithLoadsStores : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassReplaceCopyMemoriesWithLoadsStores() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.cpp b/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.cpp index e3729245..24f2255b 100644 --- a/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.cpp +++ b/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.cpp @@ -30,9 +30,6 @@ FuzzerPassReplaceCopyObjectsWithStoresLoads:: : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassReplaceCopyObjectsWithStoresLoads:: - ~FuzzerPassReplaceCopyObjectsWithStoresLoads() = default; - void FuzzerPassReplaceCopyObjectsWithStoresLoads::Apply() { GetIRContext()->module()->ForEachInst([this](opt::Instruction* instruction) { // Randomly decide whether to replace OpCopyObject. diff --git a/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.h b/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.h index ae03a450..e7b11ce1 100644 --- a/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.h +++ b/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.h @@ -30,8 +30,6 @@ class FuzzerPassReplaceCopyObjectsWithStoresLoads : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassReplaceCopyObjectsWithStoresLoads() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp b/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp index 432addbc..7e9d7baa 100644 --- a/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp +++ b/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp @@ -31,8 +31,6 @@ FuzzerPassReplaceIrrelevantIds::FuzzerPassReplaceIrrelevantIds( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassReplaceIrrelevantIds::~FuzzerPassReplaceIrrelevantIds() = default; - void FuzzerPassReplaceIrrelevantIds::Apply() { // Keep track of the irrelevant ids. This includes all the ids that are // irrelevant according to the fact manager and that are still present in the diff --git a/source/fuzz/fuzzer_pass_replace_irrelevant_ids.h b/source/fuzz/fuzzer_pass_replace_irrelevant_ids.h index ab3f01d1..1dc6b5d3 100644 --- a/source/fuzz/fuzzer_pass_replace_irrelevant_ids.h +++ b/source/fuzz/fuzzer_pass_replace_irrelevant_ids.h @@ -30,8 +30,6 @@ class FuzzerPassReplaceIrrelevantIds : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassReplaceIrrelevantIds(); - void Apply() override; }; } // namespace fuzz diff --git a/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.cpp b/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.cpp index c3e65789..0890c2fe 100644 --- a/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.cpp +++ b/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.cpp @@ -30,9 +30,6 @@ FuzzerPassReplaceLinearAlgebraInstructions:: : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassReplaceLinearAlgebraInstructions:: - ~FuzzerPassReplaceLinearAlgebraInstructions() = default; - void FuzzerPassReplaceLinearAlgebraInstructions::Apply() { // For each instruction, checks whether it is a linear algebra instruction. In // this case, the transformation is randomly applied. diff --git a/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h b/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h index 2c6126cd..5d2f2042 100644 --- a/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h +++ b/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h @@ -29,8 +29,6 @@ class FuzzerPassReplaceLinearAlgebraInstructions : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassReplaceLinearAlgebraInstructions(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.cpp b/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.cpp index 7690ac41..f2cf80fa 100644 --- a/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.cpp +++ b/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.cpp @@ -31,9 +31,6 @@ FuzzerPassReplaceLoadsStoresWithCopyMemories:: : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassReplaceLoadsStoresWithCopyMemories:: - ~FuzzerPassReplaceLoadsStoresWithCopyMemories() = default; - void FuzzerPassReplaceLoadsStoresWithCopyMemories::Apply() { // We look for matching pairs of instructions OpLoad and // OpStore within the same block. Potential instructions OpLoad to be matched diff --git a/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.h b/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.h index 67871db2..f30fc2b7 100644 --- a/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.h +++ b/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.h @@ -30,8 +30,6 @@ class FuzzerPassReplaceLoadsStoresWithCopyMemories : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassReplaceLoadsStoresWithCopyMemories() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.cpp b/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.cpp index 433cf744..b0a3d57c 100644 --- a/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.cpp +++ b/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.cpp @@ -28,9 +28,6 @@ FuzzerPassReplaceOpPhiIdsFromDeadPredecessors:: : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassReplaceOpPhiIdsFromDeadPredecessors:: - ~FuzzerPassReplaceOpPhiIdsFromDeadPredecessors() = default; - void FuzzerPassReplaceOpPhiIdsFromDeadPredecessors::Apply() { // Keep a vector of the transformations to apply. std::vector<TransformationReplaceOpPhiIdFromDeadPredecessor> transformations; diff --git a/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.h b/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.h index 972c5f9d..a2bc1886 100644 --- a/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.h +++ b/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.h @@ -29,8 +29,6 @@ class FuzzerPassReplaceOpPhiIdsFromDeadPredecessors : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassReplaceOpPhiIdsFromDeadPredecessors(); - void Apply() override; }; } // namespace fuzz diff --git a/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.cpp b/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.cpp index c3db0ef1..10bb90ad 100644 --- a/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.cpp +++ b/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.cpp @@ -31,9 +31,6 @@ FuzzerPassReplaceOpSelectsWithConditionalBranches:: : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassReplaceOpSelectsWithConditionalBranches:: - ~FuzzerPassReplaceOpSelectsWithConditionalBranches() = default; - void FuzzerPassReplaceOpSelectsWithConditionalBranches::Apply() { // Keep track of the instructions that we want to replace. We need to collect // them in a vector, since it's not safe to modify the module while iterating diff --git a/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.h b/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.h index 04c6cc6d..ec743890 100644 --- a/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.h +++ b/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.h @@ -29,8 +29,6 @@ class FuzzerPassReplaceOpSelectsWithConditionalBranches : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassReplaceOpSelectsWithConditionalBranches() override; - void Apply() override; private: diff --git a/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp b/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp index 6b3a63ba..5c256bb0 100644 --- a/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp +++ b/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp @@ -31,9 +31,6 @@ FuzzerPassReplaceParameterWithGlobal::FuzzerPassReplaceParameterWithGlobal( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassReplaceParameterWithGlobal::~FuzzerPassReplaceParameterWithGlobal() = - default; - void FuzzerPassReplaceParameterWithGlobal::Apply() { for (const auto& function : *GetIRContext()->module()) { if (fuzzerutil::FunctionIsEntryPoint(GetIRContext(), diff --git a/source/fuzz/fuzzer_pass_replace_parameter_with_global.h b/source/fuzz/fuzzer_pass_replace_parameter_with_global.h index 25011bdc..2ae49469 100644 --- a/source/fuzz/fuzzer_pass_replace_parameter_with_global.h +++ b/source/fuzz/fuzzer_pass_replace_parameter_with_global.h @@ -29,8 +29,6 @@ class FuzzerPassReplaceParameterWithGlobal : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassReplaceParameterWithGlobal() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_replace_params_with_struct.cpp b/source/fuzz/fuzzer_pass_replace_params_with_struct.cpp index 0e0610f7..c045e19f 100644 --- a/source/fuzz/fuzzer_pass_replace_params_with_struct.cpp +++ b/source/fuzz/fuzzer_pass_replace_params_with_struct.cpp @@ -31,9 +31,6 @@ FuzzerPassReplaceParamsWithStruct::FuzzerPassReplaceParamsWithStruct( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassReplaceParamsWithStruct::~FuzzerPassReplaceParamsWithStruct() = - default; - void FuzzerPassReplaceParamsWithStruct::Apply() { for (const auto& function : *GetIRContext()->module()) { auto params = diff --git a/source/fuzz/fuzzer_pass_replace_params_with_struct.h b/source/fuzz/fuzzer_pass_replace_params_with_struct.h index ed1aa6b5..f17f5207 100644 --- a/source/fuzz/fuzzer_pass_replace_params_with_struct.h +++ b/source/fuzz/fuzzer_pass_replace_params_with_struct.h @@ -29,8 +29,6 @@ class FuzzerPassReplaceParamsWithStruct : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassReplaceParamsWithStruct() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_split_blocks.cpp b/source/fuzz/fuzzer_pass_split_blocks.cpp index 481cd960..7b493559 100644 --- a/source/fuzz/fuzzer_pass_split_blocks.cpp +++ b/source/fuzz/fuzzer_pass_split_blocks.cpp @@ -29,8 +29,6 @@ FuzzerPassSplitBlocks::FuzzerPassSplitBlocks( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassSplitBlocks::~FuzzerPassSplitBlocks() = default; - void FuzzerPassSplitBlocks::Apply() { // Gather up pointers to all the blocks in the module. We are then able to // iterate over these pointers and split the blocks to which they point; diff --git a/source/fuzz/fuzzer_pass_split_blocks.h b/source/fuzz/fuzzer_pass_split_blocks.h index 0ece48a0..58f10ddb 100644 --- a/source/fuzz/fuzzer_pass_split_blocks.h +++ b/source/fuzz/fuzzer_pass_split_blocks.h @@ -29,8 +29,6 @@ class FuzzerPassSplitBlocks : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassSplitBlocks() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_swap_commutable_operands.cpp b/source/fuzz/fuzzer_pass_swap_commutable_operands.cpp index 321e8efd..27fadd17 100644 --- a/source/fuzz/fuzzer_pass_swap_commutable_operands.cpp +++ b/source/fuzz/fuzzer_pass_swap_commutable_operands.cpp @@ -28,8 +28,6 @@ FuzzerPassSwapCommutableOperands::FuzzerPassSwapCommutableOperands( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassSwapCommutableOperands::~FuzzerPassSwapCommutableOperands() = default; - void FuzzerPassSwapCommutableOperands::Apply() { auto context = GetIRContext(); // Iterates over the module's instructions and checks whether it is diff --git a/source/fuzz/fuzzer_pass_swap_commutable_operands.h b/source/fuzz/fuzzer_pass_swap_commutable_operands.h index 74d937d8..93de1728 100644 --- a/source/fuzz/fuzzer_pass_swap_commutable_operands.h +++ b/source/fuzz/fuzzer_pass_swap_commutable_operands.h @@ -30,8 +30,6 @@ class FuzzerPassSwapCommutableOperands : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassSwapCommutableOperands(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.cpp b/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.cpp index 9433a61f..b145b3bc 100644 --- a/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.cpp +++ b/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.cpp @@ -31,9 +31,6 @@ FuzzerPassSwapBranchConditionalOperands:: : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassSwapBranchConditionalOperands:: - ~FuzzerPassSwapBranchConditionalOperands() = default; - void FuzzerPassSwapBranchConditionalOperands::Apply() { ForEachInstructionWithInstructionDescriptor( [this](opt::Function* /*unused*/, opt::BasicBlock* /*unused*/, diff --git a/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h b/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h index f84f3ba4..0137f38b 100644 --- a/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h +++ b/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h @@ -29,8 +29,6 @@ class FuzzerPassSwapBranchConditionalOperands : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassSwapBranchConditionalOperands() override; - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.cpp b/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.cpp index 4f26cba3..e5afd9ee 100644 --- a/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.cpp +++ b/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.cpp @@ -28,9 +28,6 @@ FuzzerPassToggleAccessChainInstruction::FuzzerPassToggleAccessChainInstruction( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassToggleAccessChainInstruction:: - ~FuzzerPassToggleAccessChainInstruction() = default; - void FuzzerPassToggleAccessChainInstruction::Apply() { auto context = GetIRContext(); // Iterates over the module's instructions and checks whether it is diff --git a/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h b/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h index d77c7cbe..ff2f5d45 100644 --- a/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h +++ b/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h @@ -29,8 +29,6 @@ class FuzzerPassToggleAccessChainInstruction : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassToggleAccessChainInstruction(); - void Apply() override; }; diff --git a/source/fuzz/fuzzer_pass_wrap_regions_in_selections.cpp b/source/fuzz/fuzzer_pass_wrap_regions_in_selections.cpp index e6cdca41..66bbcd81 100644 --- a/source/fuzz/fuzzer_pass_wrap_regions_in_selections.cpp +++ b/source/fuzz/fuzzer_pass_wrap_regions_in_selections.cpp @@ -29,9 +29,6 @@ FuzzerPassWrapRegionsInSelections::FuzzerPassWrapRegionsInSelections( : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} -FuzzerPassWrapRegionsInSelections::~FuzzerPassWrapRegionsInSelections() = - default; - void FuzzerPassWrapRegionsInSelections::Apply() { for (auto& function : *GetIRContext()->module()) { if (!GetFuzzerContext()->ChoosePercentage( diff --git a/source/fuzz/fuzzer_pass_wrap_regions_in_selections.h b/source/fuzz/fuzzer_pass_wrap_regions_in_selections.h index eb28d208..822c308f 100644 --- a/source/fuzz/fuzzer_pass_wrap_regions_in_selections.h +++ b/source/fuzz/fuzzer_pass_wrap_regions_in_selections.h @@ -29,8 +29,6 @@ class FuzzerPassWrapRegionsInSelections : public FuzzerPass { FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations); - ~FuzzerPassWrapRegionsInSelections() override; - void Apply() override; private: diff --git a/source/fuzz/fuzzer_util.cpp b/source/fuzz/fuzzer_util.cpp index 8c14db4b..aa0d30e2 100644 --- a/source/fuzz/fuzzer_util.cpp +++ b/source/fuzz/fuzzer_util.cpp @@ -25,6 +25,25 @@ namespace fuzz { namespace fuzzerutil { namespace { +// A utility class that uses RAII to change and restore the terminator +// instruction of the |block|. +class ChangeTerminatorRAII { + public: + explicit ChangeTerminatorRAII(opt::BasicBlock* block, + opt::Instruction new_terminator) + : block_(block), old_terminator_(std::move(*block->terminator())) { + *block_->terminator() = std::move(new_terminator); + } + + ~ChangeTerminatorRAII() { + *block_->terminator() = std::move(old_terminator_); + } + + private: + opt::BasicBlock* block_; + opt::Instruction old_terminator_; +}; + uint32_t MaybeGetOpConstant(opt::IRContext* ir_context, const TransformationContext& transformation_context, const std::vector<uint32_t>& words, @@ -47,6 +66,34 @@ const spvtools::MessageConsumer kSilentMessageConsumer = [](spv_message_level_t, const char*, const spv_position_t&, const char*) -> void {}; +bool BuildIRContext(spv_target_env target_env, + const spvtools::MessageConsumer& message_consumer, + const std::vector<uint32_t>& binary_in, + spv_validator_options validator_options, + std::unique_ptr<spvtools::opt::IRContext>* ir_context) { + SpirvTools tools(target_env); + tools.SetMessageConsumer(message_consumer); + if (!tools.IsValid()) { + message_consumer(SPV_MSG_ERROR, nullptr, {}, + "Failed to create SPIRV-Tools interface; stopping."); + return false; + } + + // Initial binary should be valid. + if (!tools.Validate(binary_in.data(), binary_in.size(), validator_options)) { + message_consumer(SPV_MSG_ERROR, nullptr, {}, + "Initial binary is invalid; stopping."); + return false; + } + + // Build the module from the input binary. + auto result = BuildModule(target_env, message_consumer, binary_in.data(), + binary_in.size()); + assert(result && "IRContext must be valid"); + *ir_context = std::move(result); + return true; +} + bool IsFreshId(opt::IRContext* context, uint32_t id) { return !context->get_def_use_mgr()->GetDef(id); } @@ -135,35 +182,46 @@ bool PhiIdsOkForNewEdge( return true; } -void AddUnreachableEdgeAndUpdateOpPhis( - opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to, - uint32_t bool_id, - const google::protobuf::RepeatedField<google::protobuf::uint32>& phi_ids) { - assert(PhiIdsOkForNewEdge(context, bb_from, bb_to, phi_ids) && - "Precondition on phi_ids is not satisfied"); +opt::Instruction CreateUnreachableEdgeInstruction(opt::IRContext* ir_context, + uint32_t bb_from_id, + uint32_t bb_to_id, + uint32_t bool_id) { + const auto* bb_from = MaybeFindBlock(ir_context, bb_from_id); + assert(bb_from && "|bb_from_id| is invalid"); + assert(MaybeFindBlock(ir_context, bb_to_id) && "|bb_to_id| is invalid"); assert(bb_from->terminator()->opcode() == SpvOpBranch && "Precondition on terminator of bb_from is not satisfied"); // Get the id of the boolean constant to be used as the condition. - auto condition_inst = context->get_def_use_mgr()->GetDef(bool_id); + auto condition_inst = ir_context->get_def_use_mgr()->GetDef(bool_id); assert(condition_inst && (condition_inst->opcode() == SpvOpConstantTrue || condition_inst->opcode() == SpvOpConstantFalse) && "|bool_id| is invalid"); auto condition_value = condition_inst->opcode() == SpvOpConstantTrue; - - const bool from_to_edge_already_exists = bb_from->IsSuccessor(bb_to); - auto successor = bb_from->terminator()->GetSingleWordInOperand(0); + auto successor_id = bb_from->terminator()->GetSingleWordInOperand(0); // Add the dead branch, by turning OpBranch into OpBranchConditional, and // ordering the targets depending on whether the given boolean corresponds to // true or false. - bb_from->terminator()->SetOpcode(SpvOpBranchConditional); - bb_from->terminator()->SetInOperands( + return opt::Instruction( + ir_context, SpvOpBranchConditional, 0, 0, {{SPV_OPERAND_TYPE_ID, {bool_id}}, - {SPV_OPERAND_TYPE_ID, {condition_value ? successor : bb_to->id()}}, - {SPV_OPERAND_TYPE_ID, {condition_value ? bb_to->id() : successor}}}); + {SPV_OPERAND_TYPE_ID, {condition_value ? successor_id : bb_to_id}}, + {SPV_OPERAND_TYPE_ID, {condition_value ? bb_to_id : successor_id}}}); +} + +void AddUnreachableEdgeAndUpdateOpPhis( + opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to, + uint32_t bool_id, + const google::protobuf::RepeatedField<google::protobuf::uint32>& phi_ids) { + assert(PhiIdsOkForNewEdge(context, bb_from, bb_to, phi_ids) && + "Precondition on phi_ids is not satisfied"); + + const bool from_to_edge_already_exists = bb_from->IsSuccessor(bb_to); + *bb_from->terminator() = CreateUnreachableEdgeInstruction( + context, bb_from->id(), bb_to->id(), bool_id); // Update OpPhi instructions in the target block if this branch adds a // previously non-existent edge from source to target. @@ -410,7 +468,7 @@ bool IsValid(const opt::IRContext* context, std::vector<uint32_t> binary; context->module()->ToBinary(&binary, false); SpirvTools tools(context->grammar().target_env()); - tools.SetMessageConsumer(consumer); + tools.SetMessageConsumer(std::move(consumer)); return tools.Validate(binary.data(), binary.size(), validator_options); } @@ -747,14 +805,15 @@ bool IsNullConstantSupported(const opt::analysis::Type& type) { bool GlobalVariablesMustBeDeclaredInEntryPointInterfaces( const 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. + // TODO(afd): We capture the environments for which this requirement holds. + // The check should be refined on demand for other target environments. switch (ir_context->grammar().target_env()) { case SPV_ENV_UNIVERSAL_1_0: case SPV_ENV_UNIVERSAL_1_1: case SPV_ENV_UNIVERSAL_1_2: case SPV_ENV_UNIVERSAL_1_3: + case SPV_ENV_VULKAN_1_0: + case SPV_ENV_VULKAN_1_1: return false; default: return true; @@ -778,9 +837,10 @@ void AddVariableIdToEntryPointInterfaces(opt::IRContext* context, uint32_t id) { } } -void AddGlobalVariable(opt::IRContext* context, uint32_t result_id, - uint32_t type_id, SpvStorageClass storage_class, - uint32_t initializer_id) { +opt::Instruction* AddGlobalVariable(opt::IRContext* context, uint32_t result_id, + uint32_t type_id, + SpvStorageClass storage_class, + uint32_t initializer_id) { // Check various preconditions. assert(result_id != 0 && "Result id can't be 0"); @@ -815,16 +875,20 @@ void AddGlobalVariable(opt::IRContext* context, uint32_t result_id, operands.push_back({SPV_OPERAND_TYPE_ID, {initializer_id}}); } - context->module()->AddGlobalValue(MakeUnique<opt::Instruction>( - context, SpvOpVariable, type_id, result_id, std::move(operands))); + auto new_instruction = MakeUnique<opt::Instruction>( + context, SpvOpVariable, type_id, result_id, std::move(operands)); + auto result = new_instruction.get(); + context->module()->AddGlobalValue(std::move(new_instruction)); AddVariableIdToEntryPointInterfaces(context, result_id); UpdateModuleIdBound(context, result_id); + + return result; } -void AddLocalVariable(opt::IRContext* context, uint32_t result_id, - uint32_t type_id, uint32_t function_id, - uint32_t initializer_id) { +opt::Instruction* AddLocalVariable(opt::IRContext* context, uint32_t result_id, + uint32_t type_id, uint32_t function_id, + uint32_t initializer_id) { // Check various preconditions. assert(result_id != 0 && "Result id can't be 0"); @@ -845,13 +909,17 @@ void AddLocalVariable(opt::IRContext* context, uint32_t result_id, auto* function = FindFunction(context, function_id); assert(function && "Function id is invalid"); - function->begin()->begin()->InsertBefore(MakeUnique<opt::Instruction>( + auto new_instruction = MakeUnique<opt::Instruction>( context, SpvOpVariable, type_id, result_id, opt::Instruction::OperandList{ {SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}}, - {SPV_OPERAND_TYPE_ID, {initializer_id}}})); + {SPV_OPERAND_TYPE_ID, {initializer_id}}}); + auto result = new_instruction.get(); + function->begin()->begin()->InsertBefore(std::move(new_instruction)); UpdateModuleIdBound(context, result_id); + + return result; } bool HasDuplicates(const std::vector<uint32_t>& arr) { @@ -1355,74 +1423,6 @@ uint32_t MaybeGetBoolConstant( return 0; } -void AddIntegerType(opt::IRContext* ir_context, uint32_t result_id, - uint32_t width, bool is_signed) { - ir_context->module()->AddType(MakeUnique<opt::Instruction>( - ir_context, SpvOpTypeInt, 0, result_id, - opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {width}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {is_signed ? 1u : 0u}}})); - - UpdateModuleIdBound(ir_context, result_id); -} - -void AddFloatType(opt::IRContext* ir_context, uint32_t result_id, - uint32_t width) { - ir_context->module()->AddType(MakeUnique<opt::Instruction>( - ir_context, SpvOpTypeFloat, 0, result_id, - opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {width}}})); - - UpdateModuleIdBound(ir_context, result_id); -} - -void AddVectorType(opt::IRContext* ir_context, uint32_t result_id, - uint32_t component_type_id, uint32_t element_count) { - const auto* component_type = - ir_context->get_type_mgr()->GetType(component_type_id); - (void)component_type; // Make compiler happy in release mode. - assert(component_type && - (component_type->AsInteger() || component_type->AsFloat() || - component_type->AsBool()) && - "|component_type_id| is invalid"); - assert(element_count >= 2 && element_count <= 4 && - "Precondition: component count must be in range [2, 4]."); - ir_context->module()->AddType(MakeUnique<opt::Instruction>( - ir_context, SpvOpTypeVector, 0, result_id, - opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_ID, {component_type_id}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {element_count}}})); - - UpdateModuleIdBound(ir_context, result_id); -} - -void AddStructType(opt::IRContext* ir_context, uint32_t result_id, - const std::vector<uint32_t>& component_type_ids) { - opt::Instruction::OperandList operands; - operands.reserve(component_type_ids.size()); - - for (auto type_id : component_type_ids) { - const auto* type = ir_context->get_type_mgr()->GetType(type_id); - (void)type; // Make compiler happy in release mode. - assert(type && !type->AsFunction() && "Component's type id is invalid"); - - if (type->AsStruct()) { - // From the spec for the BuiltIn decoration: - // - When applied to a structure-type member, that structure type cannot - // be contained as a member of another structure type. - assert(!MembersHaveBuiltInDecoration(ir_context, type_id) && - "A member struct has BuiltIn members"); - } - - operands.push_back({SPV_OPERAND_TYPE_ID, {type_id}}); - } - - ir_context->AddType(MakeUnique<opt::Instruction>( - ir_context, SpvOpTypeStruct, 0, result_id, std::move(operands))); - - UpdateModuleIdBound(ir_context, result_id); -} - std::vector<uint32_t> IntToWords(uint64_t value, uint32_t width, bool is_signed) { assert(width <= 64 && "The bit width should not be more than 64 bits"); @@ -1827,6 +1827,104 @@ std::set<uint32_t> GetReachableReturnBlocks(opt::IRContext* ir_context, return result; } +bool NewTerminatorPreservesDominationRules(opt::IRContext* ir_context, + uint32_t block_id, + opt::Instruction new_terminator) { + auto* mutated_block = MaybeFindBlock(ir_context, block_id); + assert(mutated_block && "|block_id| is invalid"); + + ChangeTerminatorRAII change_terminator_raii(mutated_block, + std::move(new_terminator)); + opt::DominatorAnalysis dominator_analysis; + dominator_analysis.InitializeTree(*ir_context->cfg(), + mutated_block->GetParent()); + + // Check that each dominator appears before each dominated block. + std::unordered_map<uint32_t, size_t> positions; + for (const auto& block : *mutated_block->GetParent()) { + positions[block.id()] = positions.size(); + } + + std::queue<uint32_t> q({mutated_block->GetParent()->begin()->id()}); + std::unordered_set<uint32_t> visited; + while (!q.empty()) { + auto block = q.front(); + q.pop(); + visited.insert(block); + + auto success = ir_context->cfg()->block(block)->WhileEachSuccessorLabel( + [&positions, &visited, &dominator_analysis, block, &q](uint32_t id) { + if (id == block) { + // Handle the case when loop header and continue target are the same + // block. + return true; + } + + if (dominator_analysis.Dominates(block, id) && + positions[block] > positions[id]) { + // |block| dominates |id| but appears after |id| - violates + // domination rules. + return false; + } + + if (!visited.count(id)) { + q.push(id); + } + + return true; + }); + + if (!success) { + return false; + } + } + + // For each instruction in the |block->GetParent()| function check whether + // all its dependencies satisfy domination rules (i.e. all id operands + // dominate that instruction). + for (const auto& block : *mutated_block->GetParent()) { + if (!dominator_analysis.IsReachable(&block)) { + // If some block is not reachable then we don't need to worry about the + // preservation of domination rules for its instructions. + continue; + } + + for (const auto& inst : block) { + for (uint32_t i = 0; i < inst.NumInOperands(); + i += inst.opcode() == SpvOpPhi ? 2 : 1) { + const auto& operand = inst.GetInOperand(i); + if (!spvIsInIdType(operand.type)) { + continue; + } + + if (MaybeFindBlock(ir_context, operand.words[0])) { + // Ignore operands that refer to OpLabel instructions. + continue; + } + + const auto* dependency_block = + ir_context->get_instr_block(operand.words[0]); + if (!dependency_block) { + // A global instruction always dominates all instructions in any + // function. + continue; + } + + auto domination_target_id = inst.opcode() == SpvOpPhi + ? inst.GetSingleWordInOperand(i + 1) + : block.id(); + + if (!dominator_analysis.Dominates(dependency_block->id(), + domination_target_id)) { + return false; + } + } + } + } + + return true; +} + } // namespace fuzzerutil } // namespace fuzz } // namespace spvtools diff --git a/source/fuzz/fuzzer_util.h b/source/fuzz/fuzzer_util.h index 4e6ec36e..fcbf1c65 100644 --- a/source/fuzz/fuzzer_util.h +++ b/source/fuzz/fuzzer_util.h @@ -38,6 +38,15 @@ extern const spvtools::MessageConsumer kSilentMessageConsumer; // Function type that produces a SPIR-V module. using ModuleSupplier = std::function<std::unique_ptr<opt::IRContext>()>; +// Builds a new opt::IRContext object. Returns true if successful and changes +// the |ir_context| parameter. Otherwise (if any errors occur), returns false +// and |ir_context| remains unchanged. +bool BuildIRContext(spv_target_env target_env, + const spvtools::MessageConsumer& message_consumer, + const std::vector<uint32_t>& binary_in, + spv_validator_options validator_options, + std::unique_ptr<spvtools::opt::IRContext>* ir_context); + // Returns true if and only if the module does not define the given id. bool IsFreshId(opt::IRContext* context, uint32_t id); @@ -59,6 +68,16 @@ bool PhiIdsOkForNewEdge( opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to, const google::protobuf::RepeatedField<google::protobuf::uint32>& phi_ids); +// Returns an OpBranchConditional instruction that will create an unreachable +// branch from |bb_from_id| to |bb_to_id|. |bool_id| must be a result id of +// either OpConstantTrue or OpConstantFalse. Based on the opcode of |bool_id|, +// operands of the returned instruction will be positioned in a way that the +// branch from |bb_from_id| to |bb_to_id| is always unreachable. +opt::Instruction CreateUnreachableEdgeInstruction(opt::IRContext* ir_context, + uint32_t bb_from_id, + uint32_t bb_to_id, + uint32_t bool_id); + // Requires that |bool_id| is a valid result id of either OpConstantTrue or // OpConstantFalse, that PhiIdsOkForNewEdge(context, bb_from, bb_to, phi_ids) // holds, and that bb_from ends with "OpBranch %some_block". Turns OpBranch @@ -284,9 +303,12 @@ void AddVariableIdToEntryPointInterfaces(opt::IRContext* context, uint32_t id); // - |initializer_id| must be 0 if |storage_class| is Workgroup, and otherwise // may either be 0 or the id of a constant whose type is the pointee type of // |type_id|. -void AddGlobalVariable(opt::IRContext* context, uint32_t result_id, - uint32_t type_id, SpvStorageClass storage_class, - uint32_t initializer_id); +// +// Returns a pointer to the new global variable instruction. +opt::Instruction* AddGlobalVariable(opt::IRContext* context, uint32_t result_id, + uint32_t type_id, + SpvStorageClass storage_class, + uint32_t initializer_id); // Adds an instruction to the start of |function_id|, of the form: // |result_id| = OpVariable |type_id| Function |initializer_id|. @@ -296,9 +318,11 @@ void AddGlobalVariable(opt::IRContext* context, uint32_t result_id, // - |initializer_id| must be the id of a constant with the same type as the // pointer's pointee type. // - |function_id| must be the id of a function. -void AddLocalVariable(opt::IRContext* context, uint32_t result_id, - uint32_t type_id, uint32_t function_id, - uint32_t initializer_id); +// +// Returns a pointer to the new local variable instruction. +opt::Instruction* AddLocalVariable(opt::IRContext* context, uint32_t result_id, + uint32_t type_id, uint32_t function_id, + uint32_t initializer_id); // Returns true if the vector |arr| has duplicates. bool HasDuplicates(const std::vector<uint32_t>& arr); @@ -476,30 +500,6 @@ uint32_t MaybeGetBoolConstant( const TransformationContext& transformation_context, bool value, bool is_irrelevant); -// Creates a new OpTypeInt instruction in the module. Updates module's id bound -// to accommodate for |result_id|. -void AddIntegerType(opt::IRContext* ir_context, uint32_t result_id, - uint32_t width, bool is_signed); - -// Creates a new OpTypeFloat instruction in the module. Updates module's id -// bound to accommodate for |result_id|. -void AddFloatType(opt::IRContext* ir_context, uint32_t result_id, - uint32_t width); - -// Creates a new OpTypeVector instruction in the module. |component_type_id| -// must be a valid result id of an OpTypeInt, OpTypeFloat or OpTypeBool -// instruction in the module. |element_count| must be in the range [2, 4]. -// Updates module's id bound to accommodate for |result_id|. -void AddVectorType(opt::IRContext* ir_context, uint32_t result_id, - uint32_t component_type_id, uint32_t element_count); - -// Creates a new OpTypeStruct instruction in the module. Updates module's id -// bound to accommodate for |result_id|. |component_type_ids| may not contain -// a result id of an OpTypeFunction. if |component_type_ids| contains a result -// of an OpTypeStruct instruction, that struct may not have BuiltIn members. -void AddStructType(opt::IRContext* ir_context, uint32_t result_id, - const std::vector<uint32_t>& component_type_ids); - // Returns a vector of words representing the integer |value|, only considering // the last |width| bits. The last |width| bits are sign-extended if the value // is signed, zero-extended if it is unsigned. @@ -588,6 +588,14 @@ bool InstructionHasNoSideEffects(const opt::Instruction& instruction); std::set<uint32_t> GetReachableReturnBlocks(opt::IRContext* ir_context, uint32_t function_id); +// Returns true if changing terminator instruction to |new_terminator| in the +// basic block with id |block_id| preserves domination rules and valid block +// order (i.e. dominator must always appear before dominated in the CFG). +// Returns false otherwise. +bool NewTerminatorPreservesDominationRules(opt::IRContext* ir_context, + uint32_t block_id, + opt::Instruction new_terminator); + } // namespace fuzzerutil } // namespace fuzz } // namespace spvtools diff --git a/source/fuzz/instruction_descriptor.cpp b/source/fuzz/instruction_descriptor.cpp index c0cc5e52..fb1ff765 100644 --- a/source/fuzz/instruction_descriptor.cpp +++ b/source/fuzz/instruction_descriptor.cpp @@ -20,37 +20,32 @@ namespace fuzz { opt::Instruction* FindInstruction( const protobufs::InstructionDescriptor& instruction_descriptor, spvtools::opt::IRContext* context) { - for (auto& function : *context->module()) { - for (auto& block : function) { - bool found_base = - block.id() == instruction_descriptor.base_instruction_result_id(); - uint32_t num_ignored = 0; - for (auto& instruction : block) { - if (instruction.HasResultId() && - instruction.result_id() == - instruction_descriptor.base_instruction_result_id()) { - assert(!found_base && - "It should not be possible to find the base instruction " - "multiple times."); - found_base = true; - assert(num_ignored == 0 && - "The skipped instruction count should only be incremented " - "after the instruction base has been found."); - } - if (found_base && - instruction.opcode() == - instruction_descriptor.target_instruction_opcode()) { - if (num_ignored == instruction_descriptor.num_opcodes_to_ignore()) { - return &instruction; - } - num_ignored++; - } - } - if (found_base) { - // We found the base instruction, but did not find the target - // instruction in the same block. - return nullptr; + auto block = context->get_instr_block( + instruction_descriptor.base_instruction_result_id()); + if (block == nullptr) { + return nullptr; + } + bool found_base = + block->id() == instruction_descriptor.base_instruction_result_id(); + uint32_t num_ignored = 0; + for (auto& instruction : *block) { + if (instruction.HasResultId() && + instruction.result_id() == + instruction_descriptor.base_instruction_result_id()) { + assert(!found_base && + "It should not be possible to find the base instruction " + "multiple times."); + found_base = true; + assert(num_ignored == 0 && + "The skipped instruction count should only be incremented " + "after the instruction base has been found."); + } + if (found_base && instruction.opcode() == + instruction_descriptor.target_instruction_opcode()) { + if (num_ignored == instruction_descriptor.num_opcodes_to_ignore()) { + return &instruction; } + num_ignored++; } } return nullptr; diff --git a/source/fuzz/pass_management/repeated_pass_manager.cpp b/source/fuzz/pass_management/repeated_pass_manager.cpp index 032f2645..ec443733 100644 --- a/source/fuzz/pass_management/repeated_pass_manager.cpp +++ b/source/fuzz/pass_management/repeated_pass_manager.cpp @@ -14,6 +14,10 @@ #include "source/fuzz/pass_management/repeated_pass_manager.h" +#include "source/fuzz/pass_management/repeated_pass_manager_looped_with_recommendations.h" +#include "source/fuzz/pass_management/repeated_pass_manager_random_with_recommendations.h" +#include "source/fuzz/pass_management/repeated_pass_manager_simple.h" + namespace spvtools { namespace fuzz { @@ -23,5 +27,25 @@ RepeatedPassManager::RepeatedPassManager(FuzzerContext* fuzzer_context, RepeatedPassManager::~RepeatedPassManager() = default; +std::unique_ptr<RepeatedPassManager> RepeatedPassManager::Create( + RepeatedPassStrategy strategy, FuzzerContext* fuzzer_context, + RepeatedPassInstances* pass_instances, + RepeatedPassRecommender* pass_recommender) { + switch (strategy) { + case RepeatedPassStrategy::kSimple: + return MakeUnique<RepeatedPassManagerSimple>(fuzzer_context, + pass_instances); + case RepeatedPassStrategy::kLoopedWithRecommendations: + return MakeUnique<RepeatedPassManagerLoopedWithRecommendations>( + fuzzer_context, pass_instances, pass_recommender); + case RepeatedPassStrategy::kRandomWithRecommendations: + return MakeUnique<RepeatedPassManagerRandomWithRecommendations>( + fuzzer_context, pass_instances, pass_recommender); + } + + assert(false && "Unreachable"); + return nullptr; +} + } // namespace fuzz } // namespace spvtools diff --git a/source/fuzz/pass_management/repeated_pass_manager.h b/source/fuzz/pass_management/repeated_pass_manager.h index 1c231792..1e6ae3e4 100644 --- a/source/fuzz/pass_management/repeated_pass_manager.h +++ b/source/fuzz/pass_management/repeated_pass_manager.h @@ -18,11 +18,21 @@ #include "source/fuzz/fuzzer_context.h" #include "source/fuzz/fuzzer_pass.h" #include "source/fuzz/pass_management/repeated_pass_instances.h" +#include "source/fuzz/pass_management/repeated_pass_recommender.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h" namespace spvtools { namespace fuzz { +// Each field of this enum corresponds to an available repeated pass +// strategy, and is used to decide which kind of RepeatedPassManager object +// to create. +enum class RepeatedPassStrategy { + kSimple, + kRandomWithRecommendations, + kLoopedWithRecommendations +}; + // An interface to encapsulate the manner in which the sequence of repeated // passes that are applied during fuzzing is chosen. An implementation of this // interface could, for example, keep track of the history of passes that have @@ -40,6 +50,12 @@ class RepeatedPassManager { virtual FuzzerPass* ChoosePass( const protobufs::TransformationSequence& applied_transformations) = 0; + // Creates a corresponding RepeatedPassManager based on the |strategy|. + static std::unique_ptr<RepeatedPassManager> Create( + RepeatedPassStrategy strategy, FuzzerContext* fuzzer_context, + RepeatedPassInstances* pass_instances, + RepeatedPassRecommender* pass_recommender); + protected: FuzzerContext* GetFuzzerContext() { return fuzzer_context_; } diff --git a/source/fuzz/transformation_access_chain.cpp b/source/fuzz/transformation_access_chain.cpp index daf73d63..97d4e041 100644 --- a/source/fuzz/transformation_access_chain.cpp +++ b/source/fuzz/transformation_access_chain.cpp @@ -23,8 +23,8 @@ namespace spvtools { namespace fuzz { TransformationAccessChain::TransformationAccessChain( - const spvtools::fuzz::protobufs::TransformationAccessChain& message) - : message_(message) {} + protobufs::TransformationAccessChain message) + : message_(std::move(message)) {} TransformationAccessChain::TransformationAccessChain( uint32_t fresh_id, uint32_t pointer_id, @@ -228,6 +228,11 @@ void TransformationAccessChain::Apply( uint32_t id_pairs_used = 0; + opt::Instruction* instruction_to_insert_before = + FindInstruction(message_.instruction_to_insert_before(), ir_context); + opt::BasicBlock* enclosing_block = + ir_context->get_instr_block(instruction_to_insert_before); + // Go through the index ids in turn. for (auto index_id : message_.index_id()) { uint32_t index_value; @@ -280,29 +285,37 @@ void TransformationAccessChain::Apply( // Clamp the integer and add the corresponding instructions in the module // if |add_clamping_instructions| is set. - auto instruction_to_insert_before = - FindInstruction(message_.instruction_to_insert_before(), ir_context); // Compare the index with the bound via an instruction of the form: // %fresh_ids.first = OpULessThanEqual %bool %int_id %bound_minus_one. fuzzerutil::UpdateModuleIdBound(ir_context, fresh_ids.first()); - instruction_to_insert_before->InsertBefore(MakeUnique<opt::Instruction>( + auto comparison_instruction = MakeUnique<opt::Instruction>( ir_context, SpvOpULessThanEqual, bool_type_id, fresh_ids.first(), opt::Instruction::OperandList( {{SPV_OPERAND_TYPE_ID, {index_instruction->result_id()}}, - {SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}}))); + {SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}})); + auto comparison_instruction_ptr = comparison_instruction.get(); + instruction_to_insert_before->InsertBefore( + std::move(comparison_instruction)); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse( + comparison_instruction_ptr); + ir_context->set_instr_block(comparison_instruction_ptr, enclosing_block); // Select the index if in-bounds, otherwise one less than the bound: // %fresh_ids.second = OpSelect %int_type %fresh_ids.first %int_id // %bound_minus_one fuzzerutil::UpdateModuleIdBound(ir_context, fresh_ids.second()); - instruction_to_insert_before->InsertBefore(MakeUnique<opt::Instruction>( + auto select_instruction = MakeUnique<opt::Instruction>( ir_context, SpvOpSelect, int_type_inst->result_id(), fresh_ids.second(), opt::Instruction::OperandList( {{SPV_OPERAND_TYPE_ID, {fresh_ids.first()}}, {SPV_OPERAND_TYPE_ID, {index_instruction->result_id()}}, - {SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}}))); + {SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}})); + auto select_instruction_ptr = select_instruction.get(); + instruction_to_insert_before->InsertBefore(std::move(select_instruction)); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(select_instruction_ptr); + ir_context->set_instr_block(select_instruction_ptr, enclosing_block); new_index_id = fresh_ids.second(); @@ -326,13 +339,14 @@ void TransformationAccessChain::Apply( // Add the access chain instruction to the module, and update the module's // id bound. 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. - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); + auto access_chain_instruction = MakeUnique<opt::Instruction>( + ir_context, SpvOpAccessChain, result_type, message_.fresh_id(), operands); + auto access_chain_instruction_ptr = access_chain_instruction.get(); + instruction_to_insert_before->InsertBefore( + std::move(access_chain_instruction)); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse( + access_chain_instruction_ptr); + ir_context->set_instr_block(access_chain_instruction_ptr, enclosing_block); // If the base pointer's pointee value was irrelevant, the same is true of // the pointee value of the result of this access chain. diff --git a/source/fuzz/transformation_access_chain.h b/source/fuzz/transformation_access_chain.h index 02cdc329..5582de39 100644 --- a/source/fuzz/transformation_access_chain.h +++ b/source/fuzz/transformation_access_chain.h @@ -28,7 +28,7 @@ namespace fuzz { class TransformationAccessChain : public Transformation { public: explicit TransformationAccessChain( - const protobufs::TransformationAccessChain& message); + protobufs::TransformationAccessChain message); TransformationAccessChain( uint32_t fresh_id, uint32_t pointer_id, diff --git a/source/fuzz/transformation_add_bit_instruction_synonym.cpp b/source/fuzz/transformation_add_bit_instruction_synonym.cpp index 6cdfdfb6..d232e13a 100644 --- a/source/fuzz/transformation_add_bit_instruction_synonym.cpp +++ b/source/fuzz/transformation_add_bit_instruction_synonym.cpp @@ -21,9 +21,8 @@ namespace spvtools { namespace fuzz { TransformationAddBitInstructionSynonym::TransformationAddBitInstructionSynonym( - const spvtools::fuzz::protobufs::TransformationAddBitInstructionSynonym& - message) - : message_(message) {} + protobufs::TransformationAddBitInstructionSynonym message) + : message_(std::move(message)) {} TransformationAddBitInstructionSynonym::TransformationAddBitInstructionSynonym( const uint32_t instruction_result_id, diff --git a/source/fuzz/transformation_add_bit_instruction_synonym.h b/source/fuzz/transformation_add_bit_instruction_synonym.h index ed1a0af5..ad9d32d9 100644 --- a/source/fuzz/transformation_add_bit_instruction_synonym.h +++ b/source/fuzz/transformation_add_bit_instruction_synonym.h @@ -103,7 +103,7 @@ namespace fuzz { class TransformationAddBitInstructionSynonym : public Transformation { public: explicit TransformationAddBitInstructionSynonym( - const protobufs::TransformationAddBitInstructionSynonym& message); + protobufs::TransformationAddBitInstructionSynonym message); TransformationAddBitInstructionSynonym( const uint32_t instruction_result_id, diff --git a/source/fuzz/transformation_add_constant_boolean.cpp b/source/fuzz/transformation_add_constant_boolean.cpp index 937fdbcc..39354325 100644 --- a/source/fuzz/transformation_add_constant_boolean.cpp +++ b/source/fuzz/transformation_add_constant_boolean.cpp @@ -21,8 +21,8 @@ namespace spvtools { namespace fuzz { TransformationAddConstantBoolean::TransformationAddConstantBoolean( - const protobufs::TransformationAddConstantBoolean& message) - : message_(message) {} + protobufs::TransformationAddConstantBoolean message) + : message_(std::move(message)) {} TransformationAddConstantBoolean::TransformationAddConstantBoolean( uint32_t fresh_id, bool is_true, bool is_irrelevant) { @@ -42,14 +42,18 @@ void TransformationAddConstantBoolean::Apply( TransformationContext* transformation_context) const { // Add the boolean constant to the module, ensuring the module's id bound is // high enough. + auto new_instruction = MakeUnique<opt::Instruction>( + ir_context, message_.is_true() ? SpvOpConstantTrue : SpvOpConstantFalse, + fuzzerutil::MaybeGetBoolType(ir_context), message_.fresh_id(), + opt::Instruction::OperandList()); + auto new_instruction_ptr = new_instruction.get(); + ir_context->module()->AddGlobalValue(std::move(new_instruction)); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - ir_context->module()->AddGlobalValue( - message_.is_true() ? SpvOpConstantTrue : SpvOpConstantFalse, - message_.fresh_id(), fuzzerutil::MaybeGetBoolType(ir_context)); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + + // Inform the def-use manager about the new instruction. Invalidate the + // constant manager as we have added a new constant. + ir_context->get_def_use_mgr()->AnalyzeInstDef(new_instruction_ptr); + ir_context->InvalidateAnalyses(opt::IRContext::kAnalysisConstants); if (message_.is_irrelevant()) { transformation_context->GetFactManager()->AddFactIdIsIrrelevant( diff --git a/source/fuzz/transformation_add_constant_boolean.h b/source/fuzz/transformation_add_constant_boolean.h index d1d04efd..7f31471c 100644 --- a/source/fuzz/transformation_add_constant_boolean.h +++ b/source/fuzz/transformation_add_constant_boolean.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddConstantBoolean : public Transformation { public: explicit TransformationAddConstantBoolean( - const protobufs::TransformationAddConstantBoolean& message); + protobufs::TransformationAddConstantBoolean message); TransformationAddConstantBoolean(uint32_t fresh_id, bool is_true, bool is_irrelevant); diff --git a/source/fuzz/transformation_add_constant_composite.cpp b/source/fuzz/transformation_add_constant_composite.cpp index 02603210..e6cd5a96 100644 --- a/source/fuzz/transformation_add_constant_composite.cpp +++ b/source/fuzz/transformation_add_constant_composite.cpp @@ -22,9 +22,8 @@ namespace spvtools { namespace fuzz { TransformationAddConstantComposite::TransformationAddConstantComposite( - const spvtools::fuzz::protobufs::TransformationAddConstantComposite& - message) - : message_(message) {} + spvtools::fuzz::protobufs::TransformationAddConstantComposite message) + : message_(std::move(message)) {} TransformationAddConstantComposite::TransformationAddConstantComposite( uint32_t fresh_id, uint32_t type_id, @@ -120,14 +119,17 @@ void TransformationAddConstantComposite::Apply( for (auto constituent_id : message_.constituent_id()) { in_operands.push_back({SPV_OPERAND_TYPE_ID, {constituent_id}}); } - ir_context->module()->AddGlobalValue(MakeUnique<opt::Instruction>( + auto new_instruction = MakeUnique<opt::Instruction>( ir_context, SpvOpConstantComposite, message_.type_id(), - message_.fresh_id(), in_operands)); + message_.fresh_id(), in_operands); + auto new_instruction_ptr = new_instruction.get(); + ir_context->module()->AddGlobalValue(std::move(new_instruction)); 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. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + + // Inform the def-use manager of the new instruction. Invalidate the constant + // manager as we have added a new constant. + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr); + ir_context->InvalidateAnalyses(opt::IRContext::kAnalysisConstants); if (message_.is_irrelevant()) { transformation_context->GetFactManager()->AddFactIdIsIrrelevant( diff --git a/source/fuzz/transformation_add_constant_composite.h b/source/fuzz/transformation_add_constant_composite.h index 9e9222dc..94e7a927 100644 --- a/source/fuzz/transformation_add_constant_composite.h +++ b/source/fuzz/transformation_add_constant_composite.h @@ -28,7 +28,7 @@ namespace fuzz { class TransformationAddConstantComposite : public Transformation { public: explicit TransformationAddConstantComposite( - const protobufs::TransformationAddConstantComposite& message); + protobufs::TransformationAddConstantComposite message); TransformationAddConstantComposite( uint32_t fresh_id, uint32_t type_id, diff --git a/source/fuzz/transformation_add_constant_null.cpp b/source/fuzz/transformation_add_constant_null.cpp index 3c66ab10..32544e6d 100644 --- a/source/fuzz/transformation_add_constant_null.cpp +++ b/source/fuzz/transformation_add_constant_null.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationAddConstantNull::TransformationAddConstantNull( - const spvtools::fuzz::protobufs::TransformationAddConstantNull& message) - : message_(message) {} + spvtools::fuzz::protobufs::TransformationAddConstantNull message) + : message_(std::move(message)) {} TransformationAddConstantNull::TransformationAddConstantNull(uint32_t fresh_id, uint32_t type_id) { @@ -46,14 +46,18 @@ bool TransformationAddConstantNull::IsApplicable( } void TransformationAddConstantNull::Apply( - opt::IRContext* context, TransformationContext* /*unused*/) const { - context->module()->AddGlobalValue(MakeUnique<opt::Instruction>( - context, SpvOpConstantNull, message_.type_id(), message_.fresh_id(), - opt::Instruction::OperandList())); - fuzzerutil::UpdateModuleIdBound(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); + opt::IRContext* ir_context, TransformationContext* /*unused*/) const { + auto new_instruction = MakeUnique<opt::Instruction>( + ir_context, SpvOpConstantNull, message_.type_id(), message_.fresh_id(), + opt::Instruction::OperandList()); + auto new_instruction_ptr = new_instruction.get(); + ir_context->module()->AddGlobalValue(std::move(new_instruction)); + fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); + + // Inform the def-use manager about the new instruction. Invalidate the + // constant manager as we have added a new constant. + ir_context->get_def_use_mgr()->AnalyzeInstDef(new_instruction_ptr); + ir_context->InvalidateAnalyses(opt::IRContext::kAnalysisConstants); } protobufs::Transformation TransformationAddConstantNull::ToMessage() const { diff --git a/source/fuzz/transformation_add_constant_null.h b/source/fuzz/transformation_add_constant_null.h index bd08b1da..bb1d1b7c 100644 --- a/source/fuzz/transformation_add_constant_null.h +++ b/source/fuzz/transformation_add_constant_null.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddConstantNull : public Transformation { public: explicit TransformationAddConstantNull( - const protobufs::TransformationAddConstantNull& message); + protobufs::TransformationAddConstantNull message); TransformationAddConstantNull(uint32_t fresh_id, uint32_t type_id); @@ -34,12 +34,12 @@ class TransformationAddConstantNull : public Transformation { // - |message_.type_id| must be the id of a type for which it is acceptable // to create a null constant bool IsApplicable( - opt::IRContext* context, + opt::IRContext* ir_context, const TransformationContext& transformation_context) const override; // Adds an OpConstantNull instruction to the module, with |message_.type_id| // as its type. The instruction has result id |message_.fresh_id|. - void Apply(opt::IRContext* context, + void Apply(opt::IRContext* ir_context, TransformationContext* transformation_context) const override; std::unordered_set<uint32_t> GetFreshIds() const override; diff --git a/source/fuzz/transformation_add_constant_scalar.cpp b/source/fuzz/transformation_add_constant_scalar.cpp index 9a6642a9..a2d95fb6 100644 --- a/source/fuzz/transformation_add_constant_scalar.cpp +++ b/source/fuzz/transformation_add_constant_scalar.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationAddConstantScalar::TransformationAddConstantScalar( - const spvtools::fuzz::protobufs::TransformationAddConstantScalar& message) - : message_(message) {} + spvtools::fuzz::protobufs::TransformationAddConstantScalar message) + : message_(std::move(message)) {} TransformationAddConstantScalar::TransformationAddConstantScalar( uint32_t fresh_id, uint32_t type_id, const std::vector<uint32_t>& words, @@ -64,19 +64,21 @@ bool TransformationAddConstantScalar::IsApplicable( void TransformationAddConstantScalar::Apply( opt::IRContext* ir_context, TransformationContext* transformation_context) const { - ir_context->module()->AddGlobalValue(MakeUnique<opt::Instruction>( + auto new_instruction = MakeUnique<opt::Instruction>( ir_context, SpvOpConstant, message_.type_id(), message_.fresh_id(), opt::Instruction::OperandList( {{SPV_OPERAND_TYPE_LITERAL_INTEGER, std::vector<uint32_t>(message_.word().begin(), - message_.word().end())}}))); + message_.word().end())}})); + auto new_instruction_ptr = new_instruction.get(); + ir_context->module()->AddGlobalValue(std::move(new_instruction)); 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. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + // Inform the def-use manager about the new instruction. Invalidate the + // constant manager as we have added a new constant. + ir_context->get_def_use_mgr()->AnalyzeInstDef(new_instruction_ptr); + ir_context->InvalidateAnalyses(opt::IRContext::kAnalysisConstants); if (message_.is_irrelevant()) { transformation_context->GetFactManager()->AddFactIdIsIrrelevant( diff --git a/source/fuzz/transformation_add_constant_scalar.h b/source/fuzz/transformation_add_constant_scalar.h index 3f23907c..adb07355 100644 --- a/source/fuzz/transformation_add_constant_scalar.h +++ b/source/fuzz/transformation_add_constant_scalar.h @@ -28,7 +28,7 @@ namespace fuzz { class TransformationAddConstantScalar : public Transformation { public: explicit TransformationAddConstantScalar( - const protobufs::TransformationAddConstantScalar& message); + protobufs::TransformationAddConstantScalar message); TransformationAddConstantScalar(uint32_t fresh_id, uint32_t type_id, const std::vector<uint32_t>& words, diff --git a/source/fuzz/transformation_add_copy_memory.cpp b/source/fuzz/transformation_add_copy_memory.cpp index 44bb9c57..5eb4bdc0 100644 --- a/source/fuzz/transformation_add_copy_memory.cpp +++ b/source/fuzz/transformation_add_copy_memory.cpp @@ -22,8 +22,8 @@ namespace spvtools { namespace fuzz { TransformationAddCopyMemory::TransformationAddCopyMemory( - const protobufs::TransformationAddCopyMemory& message) - : message_(message) {} + protobufs::TransformationAddCopyMemory message) + : message_(std::move(message)) {} TransformationAddCopyMemory::TransformationAddCopyMemory( const protobufs::InstructionDescriptor& instruction_descriptor, @@ -99,15 +99,8 @@ void TransformationAddCopyMemory::Apply( auto* insert_before_inst = FindInstruction(message_.instruction_descriptor(), ir_context); assert(insert_before_inst); - - auto insert_before_iter = fuzzerutil::GetIteratorForInstruction( - ir_context->get_instr_block(insert_before_inst), insert_before_inst); - - insert_before_iter.InsertBefore(MakeUnique<opt::Instruction>( - ir_context, SpvOpCopyMemory, 0, 0, - opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}, - {SPV_OPERAND_TYPE_ID, {message_.source_id()}}})); + opt::BasicBlock* enclosing_block = + ir_context->get_instr_block(insert_before_inst); // Add global or local variable to copy memory into. auto storage_class = static_cast<SpvStorageClass>(message_.storage_class()); @@ -118,23 +111,35 @@ void TransformationAddCopyMemory::Apply( storage_class); if (storage_class == SpvStorageClassPrivate) { - fuzzerutil::AddGlobalVariable(ir_context, message_.fresh_id(), type_id, - storage_class, message_.initializer_id()); + opt::Instruction* new_global = + fuzzerutil::AddGlobalVariable(ir_context, message_.fresh_id(), type_id, + storage_class, message_.initializer_id()); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_global); } else { assert(storage_class == SpvStorageClassFunction && "Storage class can be either Private or Function"); - fuzzerutil::AddLocalVariable(ir_context, message_.fresh_id(), type_id, - ir_context->get_instr_block(insert_before_inst) - ->GetParent() - ->result_id(), - message_.initializer_id()); + opt::Function* enclosing_function = enclosing_block->GetParent(); + opt::Instruction* new_local = fuzzerutil::AddLocalVariable( + ir_context, message_.fresh_id(), type_id, + enclosing_function->result_id(), message_.initializer_id()); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_local); + ir_context->set_instr_block(new_local, &*enclosing_function->entry()); } - fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); + auto insert_before_iter = fuzzerutil::GetIteratorForInstruction( + enclosing_block, insert_before_inst); + + auto new_instruction = MakeUnique<opt::Instruction>( + ir_context, SpvOpCopyMemory, 0, 0, + opt::Instruction::OperandList{ + {SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}, + {SPV_OPERAND_TYPE_ID, {message_.source_id()}}}); + auto new_instruction_ptr = new_instruction.get(); + insert_before_iter.InsertBefore(std::move(new_instruction)); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr); + ir_context->set_instr_block(new_instruction_ptr, enclosing_block); - // Make sure our changes are analyzed - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); // Even though the copy memory instruction will - at least temporarily - lead // to the destination and source pointers referring to identical values, this diff --git a/source/fuzz/transformation_add_copy_memory.h b/source/fuzz/transformation_add_copy_memory.h index cc42f1e2..b25652fd 100644 --- a/source/fuzz/transformation_add_copy_memory.h +++ b/source/fuzz/transformation_add_copy_memory.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddCopyMemory : public Transformation { public: explicit TransformationAddCopyMemory( - const protobufs::TransformationAddCopyMemory& message); + protobufs::TransformationAddCopyMemory message); TransformationAddCopyMemory( const protobufs::InstructionDescriptor& instruction_descriptor, diff --git a/source/fuzz/transformation_add_dead_block.cpp b/source/fuzz/transformation_add_dead_block.cpp index 5dce3569..82e8cd8f 100644 --- a/source/fuzz/transformation_add_dead_block.cpp +++ b/source/fuzz/transformation_add_dead_block.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationAddDeadBlock::TransformationAddDeadBlock( - const spvtools::fuzz::protobufs::TransformationAddDeadBlock& message) - : message_(message) {} + protobufs::TransformationAddDeadBlock message) + : message_(std::move(message)) {} TransformationAddDeadBlock::TransformationAddDeadBlock(uint32_t fresh_id, uint32_t existing_block, diff --git a/source/fuzz/transformation_add_dead_block.h b/source/fuzz/transformation_add_dead_block.h index 50af6b0b..d8b3c2ae 100644 --- a/source/fuzz/transformation_add_dead_block.h +++ b/source/fuzz/transformation_add_dead_block.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddDeadBlock : public Transformation { public: explicit TransformationAddDeadBlock( - const protobufs::TransformationAddDeadBlock& message); + protobufs::TransformationAddDeadBlock message); TransformationAddDeadBlock(uint32_t fresh_id, uint32_t existing_block, bool condition_value); diff --git a/source/fuzz/transformation_add_dead_break.cpp b/source/fuzz/transformation_add_dead_break.cpp index bc938d40..ad46ce7f 100644 --- a/source/fuzz/transformation_add_dead_break.cpp +++ b/source/fuzz/transformation_add_dead_break.cpp @@ -24,8 +24,8 @@ namespace spvtools { namespace fuzz { TransformationAddDeadBreak::TransformationAddDeadBreak( - const spvtools::fuzz::protobufs::TransformationAddDeadBreak& message) - : message_(message) {} + protobufs::TransformationAddDeadBreak message) + : message_(std::move(message)) {} TransformationAddDeadBreak::TransformationAddDeadBreak( uint32_t from_block, uint32_t to_block, bool break_condition_value, @@ -112,9 +112,10 @@ bool TransformationAddDeadBreak::IsApplicable( const TransformationContext& transformation_context) const { // First, we check that a constant with the same value as // |message_.break_condition_value| is present. - if (!fuzzerutil::MaybeGetBoolConstant(ir_context, transformation_context, - message_.break_condition_value(), - false)) { + const auto bool_id = + fuzzerutil::MaybeGetBoolConstant(ir_context, transformation_context, + message_.break_condition_value(), false); + if (!bool_id) { // The required constant is not present, so the transformation cannot be // applied. return false; @@ -171,25 +172,23 @@ bool TransformationAddDeadBreak::IsApplicable( } // Adding the dead break is only valid if SPIR-V rules related to dominance - // hold. Rather than checking these rules explicitly, we defer to the - // validator. We make a clone of the module, apply the transformation to the - // clone, and check whether the transformed clone is valid. - // - // In principle some of the above checks could be removed, with more reliance - // 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(ir_context); - ApplyImpl(cloned_context.get(), transformation_context); - return fuzzerutil::IsValid(cloned_context.get(), - transformation_context.GetValidatorOptions(), - fuzzerutil::kSilentMessageConsumer); + // hold. + return fuzzerutil::NewTerminatorPreservesDominationRules( + ir_context, message_.from_block(), + fuzzerutil::CreateUnreachableEdgeInstruction( + ir_context, message_.from_block(), message_.to_block(), bool_id)); } void TransformationAddDeadBreak::Apply( opt::IRContext* ir_context, TransformationContext* transformation_context) const { - ApplyImpl(ir_context, *transformation_context); + fuzzerutil::AddUnreachableEdgeAndUpdateOpPhis( + ir_context, ir_context->cfg()->block(message_.from_block()), + ir_context->cfg()->block(message_.to_block()), + fuzzerutil::MaybeGetBoolConstant(ir_context, *transformation_context, + message_.break_condition_value(), false), + message_.phi_id()); + // Invalidate all analyses ir_context->InvalidateAnalysesExceptFor( opt::IRContext::Analysis::kAnalysisNone); @@ -201,17 +200,6 @@ protobufs::Transformation TransformationAddDeadBreak::ToMessage() const { return result; } -void TransformationAddDeadBreak::ApplyImpl( - spvtools::opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { - fuzzerutil::AddUnreachableEdgeAndUpdateOpPhis( - ir_context, ir_context->cfg()->block(message_.from_block()), - ir_context->cfg()->block(message_.to_block()), - fuzzerutil::MaybeGetBoolConstant(ir_context, transformation_context, - message_.break_condition_value(), false), - message_.phi_id()); -} - std::unordered_set<uint32_t> TransformationAddDeadBreak::GetFreshIds() const { return std::unordered_set<uint32_t>(); } diff --git a/source/fuzz/transformation_add_dead_break.h b/source/fuzz/transformation_add_dead_break.h index afb8dc7b..8c1ab4a4 100644 --- a/source/fuzz/transformation_add_dead_break.h +++ b/source/fuzz/transformation_add_dead_break.h @@ -28,7 +28,7 @@ namespace fuzz { class TransformationAddDeadBreak : public Transformation { public: explicit TransformationAddDeadBreak( - const protobufs::TransformationAddDeadBreak& message); + protobufs::TransformationAddDeadBreak message); TransformationAddDeadBreak(uint32_t from_block, uint32_t to_block, bool break_condition_value, @@ -71,15 +71,6 @@ class TransformationAddDeadBreak : public Transformation { bool AddingBreakRespectsStructuredControlFlow(opt::IRContext* ir_context, opt::BasicBlock* bb_from) const; - // Used by 'Apply' to actually apply the transformation to the module of - // interest, and by 'IsApplicable' to do a dry-run of the transformation on a - // cloned module, in order to check that the transformation leads to a valid - // 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* ir_context, - const TransformationContext& transformation_context) const; - protobufs::TransformationAddDeadBreak message_; }; diff --git a/source/fuzz/transformation_add_dead_continue.cpp b/source/fuzz/transformation_add_dead_continue.cpp index 18b3c39f..be6294e8 100644 --- a/source/fuzz/transformation_add_dead_continue.cpp +++ b/source/fuzz/transformation_add_dead_continue.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationAddDeadContinue::TransformationAddDeadContinue( - const spvtools::fuzz::protobufs::TransformationAddDeadContinue& message) - : message_(message) {} + protobufs::TransformationAddDeadContinue message) + : message_(std::move(message)) {} TransformationAddDeadContinue::TransformationAddDeadContinue( uint32_t from_block, bool continue_condition_value, @@ -38,9 +38,10 @@ bool TransformationAddDeadContinue::IsApplicable( const TransformationContext& transformation_context) const { // First, we check that a constant with the same value as // |message_.continue_condition_value| is present. - if (!fuzzerutil::MaybeGetBoolConstant(ir_context, transformation_context, - message_.continue_condition_value(), - false)) { + const auto bool_id = fuzzerutil::MaybeGetBoolConstant( + ir_context, transformation_context, message_.continue_condition_value(), + false); + if (!bool_id) { // The required constant is not present, so the transformation cannot be // applied. return false; @@ -111,39 +112,16 @@ bool TransformationAddDeadContinue::IsApplicable( } // Adding the dead break is only valid if SPIR-V rules related to dominance - // hold. Rather than checking these rules explicitly, we defer to the - // validator. We make a clone of the module, apply the transformation to the - // clone, and check whether the transformed clone is valid. - // - // In principle some of the above checks could be removed, with more reliance - // 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(ir_context); - ApplyImpl(cloned_context.get(), transformation_context); - return fuzzerutil::IsValid(cloned_context.get(), - transformation_context.GetValidatorOptions(), - fuzzerutil::kSilentMessageConsumer); + // hold. + return fuzzerutil::NewTerminatorPreservesDominationRules( + ir_context, message_.from_block(), + fuzzerutil::CreateUnreachableEdgeInstruction( + ir_context, message_.from_block(), continue_block, bool_id)); } void TransformationAddDeadContinue::Apply( opt::IRContext* ir_context, TransformationContext* transformation_context) const { - ApplyImpl(ir_context, *transformation_context); - // Invalidate all analyses - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); -} - -protobufs::Transformation TransformationAddDeadContinue::ToMessage() const { - protobufs::Transformation result; - *result.mutable_add_dead_continue() = message_; - return result; -} - -void TransformationAddDeadContinue::ApplyImpl( - spvtools::opt::IRContext* ir_context, - const TransformationContext& transformation_context) const { auto bb_from = ir_context->cfg()->block(message_.from_block()); auto continue_block = bb_from->IsLoopHeader() @@ -153,10 +131,20 @@ void TransformationAddDeadContinue::ApplyImpl( assert(continue_block && "message_.from_block must be in a loop."); fuzzerutil::AddUnreachableEdgeAndUpdateOpPhis( ir_context, bb_from, ir_context->cfg()->block(continue_block), - fuzzerutil::MaybeGetBoolConstant(ir_context, transformation_context, + fuzzerutil::MaybeGetBoolConstant(ir_context, *transformation_context, message_.continue_condition_value(), false), message_.phi_id()); + + // Invalidate all analyses + ir_context->InvalidateAnalysesExceptFor( + opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationAddDeadContinue::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_dead_continue() = message_; + return result; } std::unordered_set<uint32_t> TransformationAddDeadContinue::GetFreshIds() diff --git a/source/fuzz/transformation_add_dead_continue.h b/source/fuzz/transformation_add_dead_continue.h index 27527e78..9463aebc 100644 --- a/source/fuzz/transformation_add_dead_continue.h +++ b/source/fuzz/transformation_add_dead_continue.h @@ -28,7 +28,7 @@ namespace fuzz { class TransformationAddDeadContinue : public Transformation { public: explicit TransformationAddDeadContinue( - const protobufs::TransformationAddDeadContinue& message); + protobufs::TransformationAddDeadContinue message); TransformationAddDeadContinue(uint32_t from_block, bool continue_condition_value, @@ -68,15 +68,6 @@ class TransformationAddDeadContinue : public Transformation { protobufs::Transformation ToMessage() const override; private: - // Used by 'Apply' to actually apply the transformation to the module of - // interest, and by 'IsApplicable' to do a dry-run of the transformation on a - // cloned module, in order to check that the transformation leads to a valid - // 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* ir_context, - const TransformationContext& transformation_context) const; - protobufs::TransformationAddDeadContinue message_; }; diff --git a/source/fuzz/transformation_add_early_terminator_wrapper.cpp b/source/fuzz/transformation_add_early_terminator_wrapper.cpp index 9f86070f..547398aa 100644 --- a/source/fuzz/transformation_add_early_terminator_wrapper.cpp +++ b/source/fuzz/transformation_add_early_terminator_wrapper.cpp @@ -22,9 +22,8 @@ namespace fuzz { TransformationAddEarlyTerminatorWrapper:: TransformationAddEarlyTerminatorWrapper( - const spvtools::fuzz::protobufs:: - TransformationAddEarlyTerminatorWrapper& message) - : message_(message) {} + protobufs::TransformationAddEarlyTerminatorWrapper message) + : message_(std::move(message)) {} TransformationAddEarlyTerminatorWrapper:: TransformationAddEarlyTerminatorWrapper(uint32_t function_fresh_id, diff --git a/source/fuzz/transformation_add_early_terminator_wrapper.h b/source/fuzz/transformation_add_early_terminator_wrapper.h index 273037e5..97cc527c 100644 --- a/source/fuzz/transformation_add_early_terminator_wrapper.h +++ b/source/fuzz/transformation_add_early_terminator_wrapper.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddEarlyTerminatorWrapper : public Transformation { public: explicit TransformationAddEarlyTerminatorWrapper( - const protobufs::TransformationAddEarlyTerminatorWrapper& message); + protobufs::TransformationAddEarlyTerminatorWrapper message); TransformationAddEarlyTerminatorWrapper(uint32_t function_fresh_id, uint32_t label_fresh_id, diff --git a/source/fuzz/transformation_add_function.cpp b/source/fuzz/transformation_add_function.cpp index 9799373d..06cd6572 100644 --- a/source/fuzz/transformation_add_function.cpp +++ b/source/fuzz/transformation_add_function.cpp @@ -21,8 +21,8 @@ namespace spvtools { namespace fuzz { TransformationAddFunction::TransformationAddFunction( - const spvtools::fuzz::protobufs::TransformationAddFunction& message) - : message_(message) {} + protobufs::TransformationAddFunction message) + : message_(std::move(message)) {} TransformationAddFunction::TransformationAddFunction( const std::vector<protobufs::Instruction>& instructions) { diff --git a/source/fuzz/transformation_add_function.h b/source/fuzz/transformation_add_function.h index e5381d14..c41eee33 100644 --- a/source/fuzz/transformation_add_function.h +++ b/source/fuzz/transformation_add_function.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddFunction : public Transformation { public: explicit TransformationAddFunction( - const protobufs::TransformationAddFunction& message); + protobufs::TransformationAddFunction message); // Creates a transformation to add a non live-safe function. explicit TransformationAddFunction( diff --git a/source/fuzz/transformation_add_global_undef.cpp b/source/fuzz/transformation_add_global_undef.cpp index 7a90b821..eb390ea0 100644 --- a/source/fuzz/transformation_add_global_undef.cpp +++ b/source/fuzz/transformation_add_global_undef.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationAddGlobalUndef::TransformationAddGlobalUndef( - const spvtools::fuzz::protobufs::TransformationAddGlobalUndef& message) - : message_(message) {} + spvtools::fuzz::protobufs::TransformationAddGlobalUndef message) + : message_(std::move(message)) {} TransformationAddGlobalUndef::TransformationAddGlobalUndef(uint32_t fresh_id, uint32_t type_id) { @@ -42,14 +42,14 @@ bool TransformationAddGlobalUndef::IsApplicable( void TransformationAddGlobalUndef::Apply( opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - ir_context->module()->AddGlobalValue(MakeUnique<opt::Instruction>( + auto new_instruction = MakeUnique<opt::Instruction>( ir_context, SpvOpUndef, message_.type_id(), message_.fresh_id(), - opt::Instruction::OperandList())); + opt::Instruction::OperandList()); + auto new_instruction_ptr = new_instruction.get(); + ir_context->module()->AddGlobalValue(std::move(new_instruction)); 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. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + // Inform the def-use manager about the new instruction. + ir_context->get_def_use_mgr()->AnalyzeInstDef(new_instruction_ptr); } protobufs::Transformation TransformationAddGlobalUndef::ToMessage() const { diff --git a/source/fuzz/transformation_add_global_undef.h b/source/fuzz/transformation_add_global_undef.h index 717dc9ad..37542c3f 100644 --- a/source/fuzz/transformation_add_global_undef.h +++ b/source/fuzz/transformation_add_global_undef.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddGlobalUndef : public Transformation { public: explicit TransformationAddGlobalUndef( - const protobufs::TransformationAddGlobalUndef& message); + protobufs::TransformationAddGlobalUndef message); TransformationAddGlobalUndef(uint32_t fresh_id, uint32_t type_id); diff --git a/source/fuzz/transformation_add_global_variable.cpp b/source/fuzz/transformation_add_global_variable.cpp index dd04e48a..814d01b3 100644 --- a/source/fuzz/transformation_add_global_variable.cpp +++ b/source/fuzz/transformation_add_global_variable.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationAddGlobalVariable::TransformationAddGlobalVariable( - const spvtools::fuzz::protobufs::TransformationAddGlobalVariable& message) - : message_(message) {} + spvtools::fuzz::protobufs::TransformationAddGlobalVariable message) + : message_(std::move(message)) {} TransformationAddGlobalVariable::TransformationAddGlobalVariable( uint32_t fresh_id, uint32_t type_id, SpvStorageClass storage_class, @@ -93,15 +93,13 @@ bool TransformationAddGlobalVariable::IsApplicable( void TransformationAddGlobalVariable::Apply( opt::IRContext* ir_context, TransformationContext* transformation_context) const { - fuzzerutil::AddGlobalVariable( + opt::Instruction* new_instruction = fuzzerutil::AddGlobalVariable( ir_context, message_.fresh_id(), message_.type_id(), static_cast<SpvStorageClass>(message_.storage_class()), message_.initializer_id()); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + // Inform the def-use manager about the new instruction. + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction); if (message_.value_is_irrelevant()) { transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant( diff --git a/source/fuzz/transformation_add_global_variable.h b/source/fuzz/transformation_add_global_variable.h index 8d46edb7..d74d48a2 100644 --- a/source/fuzz/transformation_add_global_variable.h +++ b/source/fuzz/transformation_add_global_variable.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddGlobalVariable : public Transformation { public: explicit TransformationAddGlobalVariable( - const protobufs::TransformationAddGlobalVariable& message); + protobufs::TransformationAddGlobalVariable message); TransformationAddGlobalVariable(uint32_t fresh_id, uint32_t type_id, SpvStorageClass storage_class, diff --git a/source/fuzz/transformation_add_image_sample_unused_components.cpp b/source/fuzz/transformation_add_image_sample_unused_components.cpp index ab48f0b6..1ead82bc 100644 --- a/source/fuzz/transformation_add_image_sample_unused_components.cpp +++ b/source/fuzz/transformation_add_image_sample_unused_components.cpp @@ -22,9 +22,8 @@ namespace fuzz { TransformationAddImageSampleUnusedComponents:: TransformationAddImageSampleUnusedComponents( - const spvtools::fuzz::protobufs:: - TransformationAddImageSampleUnusedComponents& message) - : message_(message) {} + protobufs::TransformationAddImageSampleUnusedComponents message) + : message_(std::move(message)) {} TransformationAddImageSampleUnusedComponents:: TransformationAddImageSampleUnusedComponents( diff --git a/source/fuzz/transformation_add_image_sample_unused_components.h b/source/fuzz/transformation_add_image_sample_unused_components.h index 7486c760..7b13f9f6 100644 --- a/source/fuzz/transformation_add_image_sample_unused_components.h +++ b/source/fuzz/transformation_add_image_sample_unused_components.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddImageSampleUnusedComponents : public Transformation { public: explicit TransformationAddImageSampleUnusedComponents( - const protobufs::TransformationAddImageSampleUnusedComponents& message); + protobufs::TransformationAddImageSampleUnusedComponents message); TransformationAddImageSampleUnusedComponents( uint32_t coordinate_with_unused_components_id, diff --git a/source/fuzz/transformation_add_local_variable.cpp b/source/fuzz/transformation_add_local_variable.cpp index 0a7a3dac..21768d22 100644 --- a/source/fuzz/transformation_add_local_variable.cpp +++ b/source/fuzz/transformation_add_local_variable.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationAddLocalVariable::TransformationAddLocalVariable( - const spvtools::fuzz::protobufs::TransformationAddLocalVariable& message) - : message_(message) {} + spvtools::fuzz::protobufs::TransformationAddLocalVariable message) + : message_(std::move(message)) {} TransformationAddLocalVariable::TransformationAddLocalVariable( uint32_t fresh_id, uint32_t type_id, uint32_t function_id, @@ -70,11 +70,17 @@ bool TransformationAddLocalVariable::IsApplicable( void TransformationAddLocalVariable::Apply( opt::IRContext* ir_context, TransformationContext* transformation_context) const { - fuzzerutil::AddLocalVariable(ir_context, message_.fresh_id(), - message_.type_id(), message_.function_id(), - message_.initializer_id()); + opt::Instruction* new_instruction = fuzzerutil::AddLocalVariable( + ir_context, message_.fresh_id(), message_.type_id(), + message_.function_id(), message_.initializer_id()); - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); + // Inform the def-use manager about the new instruction. + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction); + ir_context->set_instr_block( + new_instruction, + fuzzerutil::FindFunction(ir_context, message_.function_id()) + ->entry() + .get()); if (message_.value_is_irrelevant()) { transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant( diff --git a/source/fuzz/transformation_add_local_variable.h b/source/fuzz/transformation_add_local_variable.h index 963079f5..b008a1c0 100644 --- a/source/fuzz/transformation_add_local_variable.h +++ b/source/fuzz/transformation_add_local_variable.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddLocalVariable : public Transformation { public: explicit TransformationAddLocalVariable( - const protobufs::TransformationAddLocalVariable& message); + protobufs::TransformationAddLocalVariable message); TransformationAddLocalVariable(uint32_t fresh_id, uint32_t type_id, uint32_t function_id, uint32_t initializer_id, diff --git a/source/fuzz/transformation_add_loop_preheader.cpp b/source/fuzz/transformation_add_loop_preheader.cpp index 3d50fa92..71ab18da 100644 --- a/source/fuzz/transformation_add_loop_preheader.cpp +++ b/source/fuzz/transformation_add_loop_preheader.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationAddLoopPreheader::TransformationAddLoopPreheader( - const protobufs::TransformationAddLoopPreheader& message) - : message_(message) {} + protobufs::TransformationAddLoopPreheader message) + : message_(std::move(message)) {} TransformationAddLoopPreheader::TransformationAddLoopPreheader( uint32_t loop_header_block, uint32_t fresh_id, diff --git a/source/fuzz/transformation_add_loop_preheader.h b/source/fuzz/transformation_add_loop_preheader.h index 05448f3f..9d2c565f 100644 --- a/source/fuzz/transformation_add_loop_preheader.h +++ b/source/fuzz/transformation_add_loop_preheader.h @@ -23,7 +23,7 @@ namespace fuzz { class TransformationAddLoopPreheader : public Transformation { public: explicit TransformationAddLoopPreheader( - const protobufs::TransformationAddLoopPreheader& message); + protobufs::TransformationAddLoopPreheader message); TransformationAddLoopPreheader(uint32_t loop_header_block, uint32_t fresh_id, std::vector<uint32_t> phi_id); diff --git a/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.cpp b/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.cpp index 45d3fc85..657fafa4 100644 --- a/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.cpp +++ b/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.cpp @@ -23,9 +23,8 @@ uint32_t kMaxNumOfIterations = 32; TransformationAddLoopToCreateIntConstantSynonym:: TransformationAddLoopToCreateIntConstantSynonym( - const protobufs::TransformationAddLoopToCreateIntConstantSynonym& - message) - : message_(message) {} + protobufs::TransformationAddLoopToCreateIntConstantSynonym message) + : message_(std::move(message)) {} TransformationAddLoopToCreateIntConstantSynonym:: TransformationAddLoopToCreateIntConstantSynonym( diff --git a/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.h b/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.h index 67c3bcd2..a6dfe63a 100644 --- a/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.h +++ b/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.h @@ -22,8 +22,7 @@ namespace fuzz { class TransformationAddLoopToCreateIntConstantSynonym : public Transformation { public: explicit TransformationAddLoopToCreateIntConstantSynonym( - const protobufs::TransformationAddLoopToCreateIntConstantSynonym& - message); + protobufs::TransformationAddLoopToCreateIntConstantSynonym message); TransformationAddLoopToCreateIntConstantSynonym( uint32_t constant_id, uint32_t initial_val_id, uint32_t step_val_id, diff --git a/source/fuzz/transformation_add_no_contraction_decoration.cpp b/source/fuzz/transformation_add_no_contraction_decoration.cpp index 29a871df..992a216b 100644 --- a/source/fuzz/transformation_add_no_contraction_decoration.cpp +++ b/source/fuzz/transformation_add_no_contraction_decoration.cpp @@ -21,9 +21,8 @@ namespace fuzz { TransformationAddNoContractionDecoration:: TransformationAddNoContractionDecoration( - const spvtools::fuzz::protobufs:: - TransformationAddNoContractionDecoration& message) - : message_(message) {} + protobufs::TransformationAddNoContractionDecoration message) + : message_(std::move(message)) {} TransformationAddNoContractionDecoration:: TransformationAddNoContractionDecoration(uint32_t result_id) { diff --git a/source/fuzz/transformation_add_no_contraction_decoration.h b/source/fuzz/transformation_add_no_contraction_decoration.h index f5a34e81..2f78d429 100644 --- a/source/fuzz/transformation_add_no_contraction_decoration.h +++ b/source/fuzz/transformation_add_no_contraction_decoration.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddNoContractionDecoration : public Transformation { public: explicit TransformationAddNoContractionDecoration( - const protobufs::TransformationAddNoContractionDecoration& message); + protobufs::TransformationAddNoContractionDecoration message); explicit TransformationAddNoContractionDecoration(uint32_t fresh_id); diff --git a/source/fuzz/transformation_add_opphi_synonym.cpp b/source/fuzz/transformation_add_opphi_synonym.cpp index 227c4338..3c4698a7 100644 --- a/source/fuzz/transformation_add_opphi_synonym.cpp +++ b/source/fuzz/transformation_add_opphi_synonym.cpp @@ -19,8 +19,8 @@ namespace spvtools { namespace fuzz { TransformationAddOpPhiSynonym::TransformationAddOpPhiSynonym( - const protobufs::TransformationAddOpPhiSynonym& message) - : message_(message) {} + protobufs::TransformationAddOpPhiSynonym message) + : message_(std::move(message)) {} TransformationAddOpPhiSynonym::TransformationAddOpPhiSynonym( uint32_t block_id, const std::map<uint32_t, uint32_t>& preds_to_ids, diff --git a/source/fuzz/transformation_add_opphi_synonym.h b/source/fuzz/transformation_add_opphi_synonym.h index 3b68abee..39ebea89 100644 --- a/source/fuzz/transformation_add_opphi_synonym.h +++ b/source/fuzz/transformation_add_opphi_synonym.h @@ -22,7 +22,7 @@ namespace fuzz { class TransformationAddOpPhiSynonym : public Transformation { public: explicit TransformationAddOpPhiSynonym( - const protobufs::TransformationAddOpPhiSynonym& message); + protobufs::TransformationAddOpPhiSynonym message); TransformationAddOpPhiSynonym( uint32_t block_id, const std::map<uint32_t, uint32_t>& preds_to_ids, diff --git a/source/fuzz/transformation_add_parameter.cpp b/source/fuzz/transformation_add_parameter.cpp index 9ed0bfb4..48de3e83 100644 --- a/source/fuzz/transformation_add_parameter.cpp +++ b/source/fuzz/transformation_add_parameter.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationAddParameter::TransformationAddParameter( - const protobufs::TransformationAddParameter& message) - : message_(message) {} + protobufs::TransformationAddParameter message) + : message_(std::move(message)) {} TransformationAddParameter::TransformationAddParameter( uint32_t function_id, uint32_t parameter_fresh_id, diff --git a/source/fuzz/transformation_add_parameter.h b/source/fuzz/transformation_add_parameter.h index a33521da..0bc096e7 100644 --- a/source/fuzz/transformation_add_parameter.h +++ b/source/fuzz/transformation_add_parameter.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddParameter : public Transformation { public: explicit TransformationAddParameter( - const protobufs::TransformationAddParameter& message); + protobufs::TransformationAddParameter message); TransformationAddParameter(uint32_t function_id, uint32_t parameter_fresh_id, uint32_t parameter_type_id, diff --git a/source/fuzz/transformation_add_relaxed_decoration.cpp b/source/fuzz/transformation_add_relaxed_decoration.cpp index 7b513053..b66a1a83 100644 --- a/source/fuzz/transformation_add_relaxed_decoration.cpp +++ b/source/fuzz/transformation_add_relaxed_decoration.cpp @@ -20,9 +20,8 @@ namespace spvtools { namespace fuzz { TransformationAddRelaxedDecoration::TransformationAddRelaxedDecoration( - const spvtools::fuzz::protobufs::TransformationAddRelaxedDecoration& - message) - : message_(message) {} + protobufs::TransformationAddRelaxedDecoration message) + : message_(std::move(message)) {} TransformationAddRelaxedDecoration::TransformationAddRelaxedDecoration( uint32_t result_id) { diff --git a/source/fuzz/transformation_add_relaxed_decoration.h b/source/fuzz/transformation_add_relaxed_decoration.h index 3f8bf3ed..c0163497 100644 --- a/source/fuzz/transformation_add_relaxed_decoration.h +++ b/source/fuzz/transformation_add_relaxed_decoration.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddRelaxedDecoration : public Transformation { public: explicit TransformationAddRelaxedDecoration( - const protobufs::TransformationAddRelaxedDecoration& message); + protobufs::TransformationAddRelaxedDecoration message); explicit TransformationAddRelaxedDecoration(uint32_t fresh_id); diff --git a/source/fuzz/transformation_add_synonym.cpp b/source/fuzz/transformation_add_synonym.cpp index a516916b..40768e2e 100644 --- a/source/fuzz/transformation_add_synonym.cpp +++ b/source/fuzz/transformation_add_synonym.cpp @@ -102,14 +102,19 @@ void TransformationAddSynonym::Apply( opt::IRContext* ir_context, TransformationContext* transformation_context) const { // Add a synonymous instruction. - FindInstruction(message_.insert_before(), ir_context) - ->InsertBefore( - MakeSynonymousInstruction(ir_context, *transformation_context)); + auto new_instruction = + MakeSynonymousInstruction(ir_context, *transformation_context); + auto new_instruction_ptr = new_instruction.get(); + auto insert_before = FindInstruction(message_.insert_before(), ir_context); + insert_before->InsertBefore(std::move(new_instruction)); fuzzerutil::UpdateModuleIdBound(ir_context, message_.synonym_fresh_id()); - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + // Inform the def-use manager about the new instruction and record its basic + // block. + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr); + ir_context->set_instr_block(new_instruction_ptr, + ir_context->get_instr_block(insert_before)); // Propagate PointeeValueIsIrrelevant fact. const auto* new_synonym_type = ir_context->get_type_mgr()->GetType( diff --git a/source/fuzz/transformation_add_type_array.cpp b/source/fuzz/transformation_add_type_array.cpp index c9f6a87a..45bc8dfe 100644 --- a/source/fuzz/transformation_add_type_array.cpp +++ b/source/fuzz/transformation_add_type_array.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationAddTypeArray::TransformationAddTypeArray( - const spvtools::fuzz::protobufs::TransformationAddTypeArray& message) - : message_(message) {} + protobufs::TransformationAddTypeArray message) + : message_(std::move(message)) {} TransformationAddTypeArray::TransformationAddTypeArray(uint32_t fresh_id, uint32_t element_type_id, @@ -39,9 +39,11 @@ bool TransformationAddTypeArray::IsApplicable( } auto element_type = 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. + if (!element_type || element_type->AsFunction() || + fuzzerutil::HasBlockOrBufferBlockDecoration(ir_context, + message_.element_type_id())) { + // The element type id either does not refer to a type, refers to a function + // type, or refers to a block-decorated struct. These cases are all illegal. return false; } auto constant = @@ -69,13 +71,17 @@ void TransformationAddTypeArray::Apply( 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()}}); - ir_context->module()->AddType(MakeUnique<opt::Instruction>( - ir_context, SpvOpTypeArray, 0, message_.fresh_id(), in_operands)); + auto type_instruction = MakeUnique<opt::Instruction>( + ir_context, SpvOpTypeArray, 0, message_.fresh_id(), in_operands); + auto type_instruction_ptr = type_instruction.get(); + ir_context->module()->AddType(std::move(type_instruction)); + 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. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + + // Inform the def use manager that there is a new definition. Invalidate the + // type manager since we have added a new type. + ir_context->get_def_use_mgr()->AnalyzeInstDef(type_instruction_ptr); + ir_context->InvalidateAnalyses(opt::IRContext::kAnalysisTypes); } protobufs::Transformation TransformationAddTypeArray::ToMessage() const { diff --git a/source/fuzz/transformation_add_type_array.h b/source/fuzz/transformation_add_type_array.h index ebefc237..3162497a 100644 --- a/source/fuzz/transformation_add_type_array.h +++ b/source/fuzz/transformation_add_type_array.h @@ -26,15 +26,17 @@ namespace fuzz { class TransformationAddTypeArray : public Transformation { public: explicit TransformationAddTypeArray( - const protobufs::TransformationAddTypeArray& message); + protobufs::TransformationAddTypeArray message); TransformationAddTypeArray(uint32_t fresh_id, uint32_t element_type_id, uint32_t size_id); // - |message_.fresh_id| must be fresh // - |message_.element_type_id| must be the id of a non-function type + // - |message_.member_type_id| must not be the result id of an OpTypeStruct + // instruction that has the Block or BufferBlock decoration // - |message_.size_id| must be the id of a 32-bit integer constant that is - // positive when interpreted as signed. + // positive when interpreted as signed bool IsApplicable( opt::IRContext* ir_context, const TransformationContext& transformation_context) const override; diff --git a/source/fuzz/transformation_add_type_boolean.cpp b/source/fuzz/transformation_add_type_boolean.cpp index ebbfabc8..30ff43e2 100644 --- a/source/fuzz/transformation_add_type_boolean.cpp +++ b/source/fuzz/transformation_add_type_boolean.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationAddTypeBoolean::TransformationAddTypeBoolean( - const spvtools::fuzz::protobufs::TransformationAddTypeBoolean& message) - : message_(message) {} + protobufs::TransformationAddTypeBoolean message) + : message_(std::move(message)) {} TransformationAddTypeBoolean::TransformationAddTypeBoolean(uint32_t fresh_id) { message_.set_fresh_id(fresh_id); @@ -42,13 +42,17 @@ bool TransformationAddTypeBoolean::IsApplicable( void TransformationAddTypeBoolean::Apply( opt::IRContext* ir_context, TransformationContext* /*unused*/) const { opt::Instruction::OperandList empty_operands; - ir_context->module()->AddType(MakeUnique<opt::Instruction>( - ir_context, SpvOpTypeBool, 0, message_.fresh_id(), empty_operands)); + auto type_instruction = MakeUnique<opt::Instruction>( + ir_context, SpvOpTypeBool, 0, message_.fresh_id(), empty_operands); + auto type_instruction_ptr = type_instruction.get(); + ir_context->module()->AddType(std::move(type_instruction)); + 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. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + + // Inform the def use manager that there is a new definition. Invalidate the + // type manager since we have added a new type. + ir_context->get_def_use_mgr()->AnalyzeInstDef(type_instruction_ptr); + ir_context->InvalidateAnalyses(opt::IRContext::kAnalysisTypes); } protobufs::Transformation TransformationAddTypeBoolean::ToMessage() const { diff --git a/source/fuzz/transformation_add_type_boolean.h b/source/fuzz/transformation_add_type_boolean.h index 25c92727..ee640153 100644 --- a/source/fuzz/transformation_add_type_boolean.h +++ b/source/fuzz/transformation_add_type_boolean.h @@ -25,7 +25,7 @@ namespace fuzz { class TransformationAddTypeBoolean : public Transformation { public: explicit TransformationAddTypeBoolean( - const protobufs::TransformationAddTypeBoolean& message); + protobufs::TransformationAddTypeBoolean message); explicit TransformationAddTypeBoolean(uint32_t fresh_id); diff --git a/source/fuzz/transformation_add_type_float.cpp b/source/fuzz/transformation_add_type_float.cpp index da3f3e4e..1b88b25c 100644 --- a/source/fuzz/transformation_add_type_float.cpp +++ b/source/fuzz/transformation_add_type_float.cpp @@ -26,8 +26,8 @@ TransformationAddTypeFloat::TransformationAddTypeFloat(uint32_t fresh_id, } TransformationAddTypeFloat::TransformationAddTypeFloat( - const spvtools::fuzz::protobufs::TransformationAddTypeFloat& message) - : message_(message) {} + protobufs::TransformationAddTypeFloat message) + : message_(std::move(message)) {} bool TransformationAddTypeFloat::IsApplicable( opt::IRContext* ir_context, const TransformationContext& /*unused*/) const { @@ -65,11 +65,18 @@ bool TransformationAddTypeFloat::IsApplicable( void TransformationAddTypeFloat::Apply( opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - fuzzerutil::AddFloatType(ir_context, message_.fresh_id(), message_.width()); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + auto type_instruction = MakeUnique<opt::Instruction>( + ir_context, SpvOpTypeFloat, 0, message_.fresh_id(), + opt::Instruction::OperandList{ + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.width()}}}); + auto type_instruction_ptr = type_instruction.get(); + ir_context->module()->AddType(std::move(type_instruction)); + fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); + + // Inform the def use manager that there is a new definition, and invalidate + // the type manager since we have added a new type. + ir_context->get_def_use_mgr()->AnalyzeInstDef(type_instruction_ptr); + ir_context->InvalidateAnalyses(opt::IRContext::kAnalysisTypes); } protobufs::Transformation TransformationAddTypeFloat::ToMessage() const { diff --git a/source/fuzz/transformation_add_type_float.h b/source/fuzz/transformation_add_type_float.h index 30cd0fc6..e049d9a0 100644 --- a/source/fuzz/transformation_add_type_float.h +++ b/source/fuzz/transformation_add_type_float.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddTypeFloat : public Transformation { public: explicit TransformationAddTypeFloat( - const protobufs::TransformationAddTypeFloat& message); + protobufs::TransformationAddTypeFloat message); TransformationAddTypeFloat(uint32_t fresh_id, uint32_t width); diff --git a/source/fuzz/transformation_add_type_function.cpp b/source/fuzz/transformation_add_type_function.cpp index b6cddfc0..e96067f2 100644 --- a/source/fuzz/transformation_add_type_function.cpp +++ b/source/fuzz/transformation_add_type_function.cpp @@ -22,8 +22,8 @@ namespace spvtools { namespace fuzz { TransformationAddTypeFunction::TransformationAddTypeFunction( - const spvtools::fuzz::protobufs::TransformationAddTypeFunction& message) - : message_(message) {} + protobufs::TransformationAddTypeFunction message) + : message_(std::move(message)) {} TransformationAddTypeFunction::TransformationAddTypeFunction( uint32_t fresh_id, uint32_t return_type_id, diff --git a/source/fuzz/transformation_add_type_function.h b/source/fuzz/transformation_add_type_function.h index 59ded2b3..71044579 100644 --- a/source/fuzz/transformation_add_type_function.h +++ b/source/fuzz/transformation_add_type_function.h @@ -28,7 +28,7 @@ namespace fuzz { class TransformationAddTypeFunction : public Transformation { public: explicit TransformationAddTypeFunction( - const protobufs::TransformationAddTypeFunction& message); + protobufs::TransformationAddTypeFunction message); TransformationAddTypeFunction(uint32_t fresh_id, uint32_t return_type_id, const std::vector<uint32_t>& argument_type_ids); diff --git a/source/fuzz/transformation_add_type_int.cpp b/source/fuzz/transformation_add_type_int.cpp index 253ea15b..d4ef9819 100644 --- a/source/fuzz/transformation_add_type_int.cpp +++ b/source/fuzz/transformation_add_type_int.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationAddTypeInt::TransformationAddTypeInt( - const spvtools::fuzz::protobufs::TransformationAddTypeInt& message) - : message_(message) {} + protobufs::TransformationAddTypeInt message) + : message_(std::move(message)) {} TransformationAddTypeInt::TransformationAddTypeInt(uint32_t fresh_id, uint32_t width, @@ -74,12 +74,21 @@ bool TransformationAddTypeInt::IsApplicable( void TransformationAddTypeInt::Apply(opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - fuzzerutil::AddIntegerType(ir_context, message_.fresh_id(), message_.width(), - message_.is_signed()); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + auto type_instruction = MakeUnique<opt::Instruction>( + ir_context, SpvOpTypeInt, 0, message_.fresh_id(), + opt::Instruction::OperandList{ + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.width()}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, + {message_.is_signed() ? 1u : 0u}}}); + auto type_instruction_ptr = type_instruction.get(); + ir_context->module()->AddType(std::move(type_instruction)); + + fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); + + // Inform the def use manager that there is a new definition. Invalidate the + // type manager since we have added a new type. + ir_context->get_def_use_mgr()->AnalyzeInstDef(type_instruction_ptr); + ir_context->InvalidateAnalyses(opt::IRContext::kAnalysisTypes); } protobufs::Transformation TransformationAddTypeInt::ToMessage() const { diff --git a/source/fuzz/transformation_add_type_int.h b/source/fuzz/transformation_add_type_int.h index 20c90ca4..dc67b7dc 100644 --- a/source/fuzz/transformation_add_type_int.h +++ b/source/fuzz/transformation_add_type_int.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddTypeInt : public Transformation { public: explicit TransformationAddTypeInt( - const protobufs::TransformationAddTypeInt& message); + protobufs::TransformationAddTypeInt message); TransformationAddTypeInt(uint32_t fresh_id, uint32_t width, bool is_signed); diff --git a/source/fuzz/transformation_add_type_matrix.cpp b/source/fuzz/transformation_add_type_matrix.cpp index cecebb41..b574b01b 100644 --- a/source/fuzz/transformation_add_type_matrix.cpp +++ b/source/fuzz/transformation_add_type_matrix.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationAddTypeMatrix::TransformationAddTypeMatrix( - const spvtools::fuzz::protobufs::TransformationAddTypeMatrix& message) - : message_(message) {} + protobufs::TransformationAddTypeMatrix message) + : message_(std::move(message)) {} TransformationAddTypeMatrix::TransformationAddTypeMatrix( uint32_t fresh_id, uint32_t column_type_id, uint32_t column_count) { @@ -52,13 +52,17 @@ void TransformationAddTypeMatrix::Apply( in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.column_type_id()}}); in_operands.push_back( {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.column_count()}}); - ir_context->module()->AddType(MakeUnique<opt::Instruction>( - ir_context, SpvOpTypeMatrix, 0, message_.fresh_id(), in_operands)); + auto type_instruction = MakeUnique<opt::Instruction>( + ir_context, SpvOpTypeMatrix, 0, message_.fresh_id(), in_operands); + auto type_instruction_ptr = type_instruction.get(); + ir_context->module()->AddType(std::move(type_instruction)); + 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. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + + // Inform the def use manager that there is a new definition. Invalidate the + // type manager since we have added a new type. + ir_context->get_def_use_mgr()->AnalyzeInstDef(type_instruction_ptr); + ir_context->InvalidateAnalyses(opt::IRContext::kAnalysisTypes); } protobufs::Transformation TransformationAddTypeMatrix::ToMessage() const { diff --git a/source/fuzz/transformation_add_type_matrix.h b/source/fuzz/transformation_add_type_matrix.h index f1d41656..b4788b1b 100644 --- a/source/fuzz/transformation_add_type_matrix.h +++ b/source/fuzz/transformation_add_type_matrix.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddTypeMatrix : public Transformation { public: explicit TransformationAddTypeMatrix( - const protobufs::TransformationAddTypeMatrix& message); + protobufs::TransformationAddTypeMatrix message); TransformationAddTypeMatrix(uint32_t fresh_id, uint32_t column_type_id, uint32_t column_count); diff --git a/source/fuzz/transformation_add_type_pointer.cpp b/source/fuzz/transformation_add_type_pointer.cpp index f74768d6..c6c3945b 100644 --- a/source/fuzz/transformation_add_type_pointer.cpp +++ b/source/fuzz/transformation_add_type_pointer.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationAddTypePointer::TransformationAddTypePointer( - const spvtools::fuzz::protobufs::TransformationAddTypePointer& message) - : message_(message) {} + protobufs::TransformationAddTypePointer message) + : message_(std::move(message)) {} TransformationAddTypePointer::TransformationAddTypePointer( uint32_t fresh_id, SpvStorageClass storage_class, uint32_t base_type_id) { @@ -47,13 +47,17 @@ void TransformationAddTypePointer::Apply( opt::Instruction::OperandList in_operands = { {SPV_OPERAND_TYPE_STORAGE_CLASS, {message_.storage_class()}}, {SPV_OPERAND_TYPE_ID, {message_.base_type_id()}}}; - ir_context->module()->AddType(MakeUnique<opt::Instruction>( - ir_context, SpvOpTypePointer, 0, message_.fresh_id(), in_operands)); + auto type_instruction = MakeUnique<opt::Instruction>( + ir_context, SpvOpTypePointer, 0, message_.fresh_id(), in_operands); + auto type_instruction_ptr = type_instruction.get(); + ir_context->module()->AddType(std::move(type_instruction)); + 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. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + + // Inform the def use manager that there is a new definition. Invalidate the + // type manager since we have added a new type. + ir_context->get_def_use_mgr()->AnalyzeInstDef(type_instruction_ptr); + ir_context->InvalidateAnalyses(opt::IRContext::kAnalysisTypes); } protobufs::Transformation TransformationAddTypePointer::ToMessage() const { diff --git a/source/fuzz/transformation_add_type_pointer.h b/source/fuzz/transformation_add_type_pointer.h index 3f686e97..8468c14d 100644 --- a/source/fuzz/transformation_add_type_pointer.h +++ b/source/fuzz/transformation_add_type_pointer.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddTypePointer : public Transformation { public: explicit TransformationAddTypePointer( - const protobufs::TransformationAddTypePointer& message); + protobufs::TransformationAddTypePointer message); TransformationAddTypePointer(uint32_t fresh_id, SpvStorageClass storage_class, uint32_t base_type_id); diff --git a/source/fuzz/transformation_add_type_struct.cpp b/source/fuzz/transformation_add_type_struct.cpp index b20ffb00..d7f0711e 100644 --- a/source/fuzz/transformation_add_type_struct.cpp +++ b/source/fuzz/transformation_add_type_struct.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationAddTypeStruct::TransformationAddTypeStruct( - const spvtools::fuzz::protobufs::TransformationAddTypeStruct& message) - : message_(message) {} + protobufs::TransformationAddTypeStruct message) + : message_(std::move(message)) {} TransformationAddTypeStruct::TransformationAddTypeStruct( uint32_t fresh_id, const std::vector<uint32_t>& member_type_ids) { @@ -39,9 +39,11 @@ bool TransformationAddTypeStruct::IsApplicable( } for (auto member_type : message_.member_type_id()) { auto type = ir_context->get_type_mgr()->GetType(member_type); - if (!type || type->AsFunction()) { - // The member type id either does not refer to a type, or refers to a - // function type; both are illegal. + if (!type || type->AsFunction() || + fuzzerutil::HasBlockOrBufferBlockDecoration(ir_context, member_type)) { + // The member type id either does not refer to a type, refers to a + // function type, or refers to a block-decorated struct. These cases are + // all illegal. return false; } @@ -58,14 +60,36 @@ bool TransformationAddTypeStruct::IsApplicable( void TransformationAddTypeStruct::Apply( opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - fuzzerutil::AddStructType( - ir_context, message_.fresh_id(), - std::vector<uint32_t>(message_.member_type_id().begin(), - message_.member_type_id().end())); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + opt::Instruction::OperandList operands; + operands.reserve(message_.member_type_id().size()); + + for (auto type_id : message_.member_type_id()) { + const auto* type = ir_context->get_type_mgr()->GetType(type_id); + (void)type; // Make compiler happy in release mode. + assert(type && !type->AsFunction() && "Component's type id is invalid"); + + if (type->AsStruct()) { + // From the spec for the BuiltIn decoration: + // - When applied to a structure-type member, that structure type cannot + // be contained as a member of another structure type. + assert(!fuzzerutil::MembersHaveBuiltInDecoration(ir_context, type_id) && + "A member struct has BuiltIn members"); + } + + operands.push_back({SPV_OPERAND_TYPE_ID, {type_id}}); + } + + auto type_instruction = MakeUnique<opt::Instruction>( + ir_context, SpvOpTypeStruct, 0, message_.fresh_id(), std::move(operands)); + auto type_instruction_ptr = type_instruction.get(); + ir_context->AddType(std::move(type_instruction)); + + fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); + + // Inform the def use manager that there is a new definition. Invalidate the + // type manager since we have added a new type. + ir_context->get_def_use_mgr()->AnalyzeInstDef(type_instruction_ptr); + ir_context->InvalidateAnalyses(opt::IRContext::kAnalysisTypes); } protobufs::Transformation TransformationAddTypeStruct::ToMessage() const { diff --git a/source/fuzz/transformation_add_type_struct.h b/source/fuzz/transformation_add_type_struct.h index 94be42ad..6a8dce7c 100644 --- a/source/fuzz/transformation_add_type_struct.h +++ b/source/fuzz/transformation_add_type_struct.h @@ -28,7 +28,7 @@ namespace fuzz { class TransformationAddTypeStruct : public Transformation { public: explicit TransformationAddTypeStruct( - const protobufs::TransformationAddTypeStruct& message); + protobufs::TransformationAddTypeStruct message); TransformationAddTypeStruct(uint32_t fresh_id, const std::vector<uint32_t>& component_type_ids); @@ -37,7 +37,9 @@ class TransformationAddTypeStruct : public Transformation { // - |message_.member_type_id| must be a sequence of non-function type ids // - |message_.member_type_id| may not contain a result id of an OpTypeStruct // instruction with BuiltIn members (i.e. members of the struct are - // decorated via OpMemberDecorate with BuiltIn decoration). + // decorated via OpMemberDecorate with BuiltIn decoration) + // - |message_.member_type_id| may not contain a result id of an OpTypeStruct + // instruction that has the Block or BufferBlock decoration bool IsApplicable( opt::IRContext* ir_context, const TransformationContext& transformation_context) const override; diff --git a/source/fuzz/transformation_add_type_vector.cpp b/source/fuzz/transformation_add_type_vector.cpp index a3b0010e..4da0ff01 100644 --- a/source/fuzz/transformation_add_type_vector.cpp +++ b/source/fuzz/transformation_add_type_vector.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationAddTypeVector::TransformationAddTypeVector( - const spvtools::fuzz::protobufs::TransformationAddTypeVector& message) - : message_(message) {} + protobufs::TransformationAddTypeVector message) + : message_(std::move(message)) {} TransformationAddTypeVector::TransformationAddTypeVector( uint32_t fresh_id, uint32_t component_type_id, uint32_t component_count) { @@ -46,13 +46,30 @@ bool TransformationAddTypeVector::IsApplicable( void TransformationAddTypeVector::Apply( opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - fuzzerutil::AddVectorType(ir_context, message_.fresh_id(), - message_.component_type_id(), - message_.component_count()); - // We have added an instruction to the module, so need to be careful about the - // validity of existing analyses. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + const auto* component_type = + ir_context->get_type_mgr()->GetType(message_.component_type_id()); + (void)component_type; // Make compiler happy in release mode. + assert(component_type && + (component_type->AsInteger() || component_type->AsFloat() || + component_type->AsBool()) && + "|component_type_id| is invalid"); + assert(message_.component_count() >= 2 && message_.component_count() <= 4 && + "Precondition: component count must be in range [2, 4]."); + + auto type_instruction = MakeUnique<opt::Instruction>( + ir_context, SpvOpTypeVector, 0, message_.fresh_id(), + opt::Instruction::OperandList{ + {SPV_OPERAND_TYPE_ID, {message_.component_type_id()}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.component_count()}}}); + auto type_instruction_ptr = type_instruction.get(); + ir_context->module()->AddType(std::move(type_instruction)); + + fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); + + // Inform the def use manager that there is a new definition. Invalidate the + // type manager since we have added a new type. + ir_context->get_def_use_mgr()->AnalyzeInstDef(type_instruction_ptr); + ir_context->InvalidateAnalyses(opt::IRContext::kAnalysisTypes); } protobufs::Transformation TransformationAddTypeVector::ToMessage() const { diff --git a/source/fuzz/transformation_add_type_vector.h b/source/fuzz/transformation_add_type_vector.h index c25d565d..43460ce4 100644 --- a/source/fuzz/transformation_add_type_vector.h +++ b/source/fuzz/transformation_add_type_vector.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAddTypeVector : public Transformation { public: explicit TransformationAddTypeVector( - const protobufs::TransformationAddTypeVector& message); + protobufs::TransformationAddTypeVector message); TransformationAddTypeVector(uint32_t fresh_id, uint32_t component_type_id, uint32_t component_count); diff --git a/source/fuzz/transformation_adjust_branch_weights.cpp b/source/fuzz/transformation_adjust_branch_weights.cpp index 8b74ed37..21fef258 100644 --- a/source/fuzz/transformation_adjust_branch_weights.cpp +++ b/source/fuzz/transformation_adjust_branch_weights.cpp @@ -28,8 +28,8 @@ const uint32_t kBranchWeightForFalseLabelIndex = 4; } // namespace TransformationAdjustBranchWeights::TransformationAdjustBranchWeights( - const spvtools::fuzz::protobufs::TransformationAdjustBranchWeights& message) - : message_(message) {} + protobufs::TransformationAdjustBranchWeights message) + : message_(std::move(message)) {} TransformationAdjustBranchWeights::TransformationAdjustBranchWeights( const protobufs::InstructionDescriptor& instruction_descriptor, diff --git a/source/fuzz/transformation_adjust_branch_weights.h b/source/fuzz/transformation_adjust_branch_weights.h index 4d451a5a..41eceeb5 100644 --- a/source/fuzz/transformation_adjust_branch_weights.h +++ b/source/fuzz/transformation_adjust_branch_weights.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationAdjustBranchWeights : public Transformation { public: explicit TransformationAdjustBranchWeights( - const protobufs::TransformationAdjustBranchWeights& message); + protobufs::TransformationAdjustBranchWeights message); TransformationAdjustBranchWeights( const protobufs::InstructionDescriptor& instruction_descriptor, diff --git a/source/fuzz/transformation_composite_construct.cpp b/source/fuzz/transformation_composite_construct.cpp index f0de1aeb..0cd2308b 100644 --- a/source/fuzz/transformation_composite_construct.cpp +++ b/source/fuzz/transformation_composite_construct.cpp @@ -23,8 +23,8 @@ namespace spvtools { namespace fuzz { TransformationCompositeConstruct::TransformationCompositeConstruct( - const protobufs::TransformationCompositeConstruct& message) - : message_(message) {} + protobufs::TransformationCompositeConstruct message) + : message_(std::move(message)) {} TransformationCompositeConstruct::TransformationCompositeConstruct( uint32_t composite_type_id, std::vector<uint32_t> component, @@ -120,12 +120,18 @@ void TransformationCompositeConstruct::Apply( } // Insert an OpCompositeConstruct instruction. - insert_before.InsertBefore(MakeUnique<opt::Instruction>( + auto new_instruction = MakeUnique<opt::Instruction>( ir_context, SpvOpCompositeConstruct, message_.composite_type_id(), - message_.fresh_id(), in_operands)); + message_.fresh_id(), in_operands); + auto new_instruction_ptr = new_instruction.get(); + insert_before.InsertBefore(std::move(new_instruction)); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr); + ir_context->set_instr_block(new_instruction_ptr, destination_block); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); + + // No analyses need to be invalidated since the transformation is local to a + // block and the def-use and instruction-to-block mappings have been updated. AddDataSynonymFacts(ir_context, transformation_context); } diff --git a/source/fuzz/transformation_composite_construct.h b/source/fuzz/transformation_composite_construct.h index 3a3e43c4..cc44a612 100644 --- a/source/fuzz/transformation_composite_construct.h +++ b/source/fuzz/transformation_composite_construct.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationCompositeConstruct : public Transformation { public: explicit TransformationCompositeConstruct( - const protobufs::TransformationCompositeConstruct& message); + protobufs::TransformationCompositeConstruct message); TransformationCompositeConstruct( uint32_t composite_type_id, std::vector<uint32_t> component, diff --git a/source/fuzz/transformation_composite_extract.cpp b/source/fuzz/transformation_composite_extract.cpp index 2aff02fb..647cd74e 100644 --- a/source/fuzz/transformation_composite_extract.cpp +++ b/source/fuzz/transformation_composite_extract.cpp @@ -24,8 +24,8 @@ namespace spvtools { namespace fuzz { TransformationCompositeExtract::TransformationCompositeExtract( - const spvtools::fuzz::protobufs::TransformationCompositeExtract& message) - : message_(message) {} + protobufs::TransformationCompositeExtract message) + : message_(std::move(message)) {} TransformationCompositeExtract::TransformationCompositeExtract( const protobufs::InstructionDescriptor& instruction_to_insert_before, @@ -89,15 +89,20 @@ void TransformationCompositeExtract::Apply( auto extracted_type = fuzzerutil::WalkCompositeTypeIndices( ir_context, composite_instruction->type_id(), message_.index()); - FindInstruction(message_.instruction_to_insert_before(), ir_context) - ->InsertBefore(MakeUnique<opt::Instruction>( + auto insert_before = + FindInstruction(message_.instruction_to_insert_before(), ir_context); + opt::Instruction* new_instruction = + insert_before->InsertBefore(MakeUnique<opt::Instruction>( ir_context, SpvOpCompositeExtract, extracted_type, message_.fresh_id(), extract_operands)); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction); + ir_context->set_instr_block(new_instruction, + ir_context->get_instr_block(insert_before)); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + // No analyses need to be invalidated since the transformation is local to a + // block and the def-use and instruction-to-block mappings have been updated. AddDataSynonymFacts(ir_context, transformation_context); } diff --git a/source/fuzz/transformation_composite_extract.h b/source/fuzz/transformation_composite_extract.h index 0f5348a8..0682a61c 100644 --- a/source/fuzz/transformation_composite_extract.h +++ b/source/fuzz/transformation_composite_extract.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationCompositeExtract : public Transformation { public: explicit TransformationCompositeExtract( - const protobufs::TransformationCompositeExtract& message); + protobufs::TransformationCompositeExtract message); TransformationCompositeExtract( const protobufs::InstructionDescriptor& instruction_to_insert_before, diff --git a/source/fuzz/transformation_composite_insert.cpp b/source/fuzz/transformation_composite_insert.cpp index cc681415..14c3a1b0 100644 --- a/source/fuzz/transformation_composite_insert.cpp +++ b/source/fuzz/transformation_composite_insert.cpp @@ -22,8 +22,8 @@ namespace spvtools { namespace fuzz { TransformationCompositeInsert::TransformationCompositeInsert( - const spvtools::fuzz::protobufs::TransformationCompositeInsert& message) - : message_(message) {} + protobufs::TransformationCompositeInsert message) + : message_(std::move(message)) {} TransformationCompositeInsert::TransformationCompositeInsert( const protobufs::InstructionDescriptor& instruction_to_insert_before, @@ -124,15 +124,21 @@ void TransformationCompositeInsert::Apply( auto composite_type_id = fuzzerutil::GetTypeId(ir_context, message_.composite_id()); - FindInstruction(message_.instruction_to_insert_before(), ir_context) - ->InsertBefore(MakeUnique<opt::Instruction>( - ir_context, SpvOpCompositeInsert, composite_type_id, - message_.fresh_id(), std::move(in_operands))); + auto insert_before = + FindInstruction(message_.instruction_to_insert_before(), ir_context); + auto new_instruction = MakeUnique<opt::Instruction>( + ir_context, SpvOpCompositeInsert, composite_type_id, message_.fresh_id(), + std::move(in_operands)); + auto new_instruction_ptr = new_instruction.get(); + insert_before->InsertBefore(std::move(new_instruction)); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - // We have modified the module so most analyzes are now invalid. - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); + // Inform the def-use manager about the new instruction and record its basic + // block. + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr); + ir_context->set_instr_block(new_instruction_ptr, + ir_context->get_instr_block(insert_before)); // Add data synonym facts that arise from the insertion. AddDataSynonymFacts(ir_context, transformation_context); diff --git a/source/fuzz/transformation_composite_insert.h b/source/fuzz/transformation_composite_insert.h index f2290142..413d41f1 100644 --- a/source/fuzz/transformation_composite_insert.h +++ b/source/fuzz/transformation_composite_insert.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationCompositeInsert : public Transformation { public: explicit TransformationCompositeInsert( - const protobufs::TransformationCompositeInsert& message); + protobufs::TransformationCompositeInsert message); TransformationCompositeInsert( const protobufs::InstructionDescriptor& instruction_to_insert_before, diff --git a/source/fuzz/transformation_compute_data_synonym_fact_closure.cpp b/source/fuzz/transformation_compute_data_synonym_fact_closure.cpp index f7270526..7ae9df82 100644 --- a/source/fuzz/transformation_compute_data_synonym_fact_closure.cpp +++ b/source/fuzz/transformation_compute_data_synonym_fact_closure.cpp @@ -19,9 +19,8 @@ namespace fuzz { TransformationComputeDataSynonymFactClosure:: TransformationComputeDataSynonymFactClosure( - const spvtools::fuzz::protobufs:: - TransformationComputeDataSynonymFactClosure& message) - : message_(message) {} + protobufs::TransformationComputeDataSynonymFactClosure message) + : message_(std::move(message)) {} TransformationComputeDataSynonymFactClosure:: TransformationComputeDataSynonymFactClosure( diff --git a/source/fuzz/transformation_compute_data_synonym_fact_closure.h b/source/fuzz/transformation_compute_data_synonym_fact_closure.h index dedabe23..c61b26ec 100644 --- a/source/fuzz/transformation_compute_data_synonym_fact_closure.h +++ b/source/fuzz/transformation_compute_data_synonym_fact_closure.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationComputeDataSynonymFactClosure : public Transformation { public: explicit TransformationComputeDataSynonymFactClosure( - const protobufs::TransformationComputeDataSynonymFactClosure& message); + protobufs::TransformationComputeDataSynonymFactClosure message); explicit TransformationComputeDataSynonymFactClosure( uint32_t maximum_equivalence_class_size); diff --git a/source/fuzz/transformation_duplicate_region_with_selection.cpp b/source/fuzz/transformation_duplicate_region_with_selection.cpp index 2ac6259d..dee1207f 100644 --- a/source/fuzz/transformation_duplicate_region_with_selection.cpp +++ b/source/fuzz/transformation_duplicate_region_with_selection.cpp @@ -21,9 +21,8 @@ namespace fuzz { TransformationDuplicateRegionWithSelection:: TransformationDuplicateRegionWithSelection( - const spvtools::fuzz::protobufs:: - TransformationDuplicateRegionWithSelection& message) - : message_(message) {} + protobufs::TransformationDuplicateRegionWithSelection message) + : message_(std::move(message)) {} TransformationDuplicateRegionWithSelection:: TransformationDuplicateRegionWithSelection( diff --git a/source/fuzz/transformation_duplicate_region_with_selection.h b/source/fuzz/transformation_duplicate_region_with_selection.h index a2b9a433..30e3c373 100644 --- a/source/fuzz/transformation_duplicate_region_with_selection.h +++ b/source/fuzz/transformation_duplicate_region_with_selection.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationDuplicateRegionWithSelection : public Transformation { public: explicit TransformationDuplicateRegionWithSelection( - const protobufs::TransformationDuplicateRegionWithSelection& message); + protobufs::TransformationDuplicateRegionWithSelection message); explicit TransformationDuplicateRegionWithSelection( uint32_t new_entry_fresh_id, uint32_t condition_id, diff --git a/source/fuzz/transformation_equation_instruction.cpp b/source/fuzz/transformation_equation_instruction.cpp index 32e83518..1e5dae97 100644 --- a/source/fuzz/transformation_equation_instruction.cpp +++ b/source/fuzz/transformation_equation_instruction.cpp @@ -21,8 +21,8 @@ namespace spvtools { namespace fuzz { TransformationEquationInstruction::TransformationEquationInstruction( - const spvtools::fuzz::protobufs::TransformationEquationInstruction& message) - : message_(message) {} + protobufs::TransformationEquationInstruction message) + : message_(std::move(message)) {} TransformationEquationInstruction::TransformationEquationInstruction( uint32_t fresh_id, SpvOp opcode, const std::vector<uint32_t>& in_operand_id, @@ -84,13 +84,17 @@ void TransformationEquationInstruction::Apply( rhs_id.push_back(id); } - FindInstruction(message_.instruction_to_insert_before(), ir_context) - ->InsertBefore(MakeUnique<opt::Instruction>( + auto insert_before = + FindInstruction(message_.instruction_to_insert_before(), ir_context); + opt::Instruction* new_instruction = + insert_before->InsertBefore(MakeUnique<opt::Instruction>( ir_context, static_cast<SpvOp>(message_.opcode()), MaybeGetResultTypeId(ir_context), message_.fresh_id(), std::move(in_operands))); - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction); + ir_context->set_instr_block(new_instruction, + ir_context->get_instr_block(insert_before)); // Add an equation fact as long as the result id is not irrelevant (it could // be if we are inserting into a dead block). diff --git a/source/fuzz/transformation_equation_instruction.h b/source/fuzz/transformation_equation_instruction.h index 4afc85fb..ae32a1a2 100644 --- a/source/fuzz/transformation_equation_instruction.h +++ b/source/fuzz/transformation_equation_instruction.h @@ -28,7 +28,7 @@ namespace fuzz { class TransformationEquationInstruction : public Transformation { public: explicit TransformationEquationInstruction( - const protobufs::TransformationEquationInstruction& message); + protobufs::TransformationEquationInstruction message); TransformationEquationInstruction( uint32_t fresh_id, SpvOp opcode, diff --git a/source/fuzz/transformation_expand_vector_reduction.cpp b/source/fuzz/transformation_expand_vector_reduction.cpp index 640aea25..99387066 100644 --- a/source/fuzz/transformation_expand_vector_reduction.cpp +++ b/source/fuzz/transformation_expand_vector_reduction.cpp @@ -21,9 +21,8 @@ namespace spvtools { namespace fuzz { TransformationExpandVectorReduction::TransformationExpandVectorReduction( - const spvtools::fuzz::protobufs::TransformationExpandVectorReduction& - message) - : message_(message) {} + protobufs::TransformationExpandVectorReduction message) + : message_(std::move(message)) {} TransformationExpandVectorReduction::TransformationExpandVectorReduction( const uint32_t instruction_result_id, diff --git a/source/fuzz/transformation_expand_vector_reduction.h b/source/fuzz/transformation_expand_vector_reduction.h index e4cc9539..6ee2cefa 100644 --- a/source/fuzz/transformation_expand_vector_reduction.h +++ b/source/fuzz/transformation_expand_vector_reduction.h @@ -70,7 +70,7 @@ namespace fuzz { class TransformationExpandVectorReduction : public Transformation { public: explicit TransformationExpandVectorReduction( - const protobufs::TransformationExpandVectorReduction& message); + protobufs::TransformationExpandVectorReduction message); TransformationExpandVectorReduction(const uint32_t instruction_result_id, const std::vector<uint32_t>& fresh_ids); diff --git a/source/fuzz/transformation_flatten_conditional_branch.cpp b/source/fuzz/transformation_flatten_conditional_branch.cpp index fdee5130..b8c6de0c 100644 --- a/source/fuzz/transformation_flatten_conditional_branch.cpp +++ b/source/fuzz/transformation_flatten_conditional_branch.cpp @@ -21,8 +21,8 @@ namespace spvtools { namespace fuzz { TransformationFlattenConditionalBranch::TransformationFlattenConditionalBranch( - const protobufs::TransformationFlattenConditionalBranch& message) - : message_(message) {} + protobufs::TransformationFlattenConditionalBranch message) + : message_(std::move(message)) {} TransformationFlattenConditionalBranch::TransformationFlattenConditionalBranch( uint32_t header_block_id, bool true_branch_first, @@ -844,7 +844,9 @@ bool TransformationFlattenConditionalBranch::OpSelectArgumentsAreRestricted( case SPV_ENV_UNIVERSAL_1_0: case SPV_ENV_UNIVERSAL_1_1: case SPV_ENV_UNIVERSAL_1_2: - case SPV_ENV_UNIVERSAL_1_3: { + case SPV_ENV_UNIVERSAL_1_3: + case SPV_ENV_VULKAN_1_0: + case SPV_ENV_VULKAN_1_1: { return true; } default: diff --git a/source/fuzz/transformation_flatten_conditional_branch.h b/source/fuzz/transformation_flatten_conditional_branch.h index 9bdae937..4efff670 100644 --- a/source/fuzz/transformation_flatten_conditional_branch.h +++ b/source/fuzz/transformation_flatten_conditional_branch.h @@ -23,7 +23,7 @@ namespace fuzz { class TransformationFlattenConditionalBranch : public Transformation { public: explicit TransformationFlattenConditionalBranch( - const protobufs::TransformationFlattenConditionalBranch& message); + protobufs::TransformationFlattenConditionalBranch message); TransformationFlattenConditionalBranch( uint32_t header_block_id, bool true_branch_first, diff --git a/source/fuzz/transformation_function_call.cpp b/source/fuzz/transformation_function_call.cpp index ec95c320..0f88ce51 100644 --- a/source/fuzz/transformation_function_call.cpp +++ b/source/fuzz/transformation_function_call.cpp @@ -22,8 +22,8 @@ namespace spvtools { namespace fuzz { TransformationFunctionCall::TransformationFunctionCall( - const spvtools::fuzz::protobufs::TransformationFunctionCall& message) - : message_(message) {} + protobufs::TransformationFunctionCall message) + : message_(std::move(message)) {} TransformationFunctionCall::TransformationFunctionCall( uint32_t fresh_id, uint32_t callee_id, diff --git a/source/fuzz/transformation_function_call.h b/source/fuzz/transformation_function_call.h index e220d83d..a2aaf365 100644 --- a/source/fuzz/transformation_function_call.h +++ b/source/fuzz/transformation_function_call.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationFunctionCall : public Transformation { public: explicit TransformationFunctionCall( - const protobufs::TransformationFunctionCall& message); + protobufs::TransformationFunctionCall message); TransformationFunctionCall( uint32_t fresh_id, uint32_t callee_id, diff --git a/source/fuzz/transformation_inline_function.cpp b/source/fuzz/transformation_inline_function.cpp index f997491d..a48b8179 100644 --- a/source/fuzz/transformation_inline_function.cpp +++ b/source/fuzz/transformation_inline_function.cpp @@ -21,8 +21,8 @@ namespace spvtools { namespace fuzz { TransformationInlineFunction::TransformationInlineFunction( - const spvtools::fuzz::protobufs::TransformationInlineFunction& message) - : message_(message) {} + protobufs::TransformationInlineFunction message) + : message_(std::move(message)) {} TransformationInlineFunction::TransformationInlineFunction( uint32_t function_call_id, diff --git a/source/fuzz/transformation_inline_function.h b/source/fuzz/transformation_inline_function.h index 8105d92b..f4dc410a 100644 --- a/source/fuzz/transformation_inline_function.h +++ b/source/fuzz/transformation_inline_function.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationInlineFunction : public Transformation { public: explicit TransformationInlineFunction( - const protobufs::TransformationInlineFunction& message); + protobufs::TransformationInlineFunction message); TransformationInlineFunction( uint32_t function_call_id, diff --git a/source/fuzz/transformation_load.cpp b/source/fuzz/transformation_load.cpp index f8b35134..e22f8dd2 100644 --- a/source/fuzz/transformation_load.cpp +++ b/source/fuzz/transformation_load.cpp @@ -20,9 +20,8 @@ namespace spvtools { namespace fuzz { -TransformationLoad::TransformationLoad( - const spvtools::fuzz::protobufs::TransformationLoad& message) - : message_(message) {} +TransformationLoad::TransformationLoad(protobufs::TransformationLoad message) + : message_(std::move(message)) {} TransformationLoad::TransformationLoad( uint32_t fresh_id, uint32_t pointer_id, @@ -84,12 +83,19 @@ void TransformationLoad::Apply(opt::IRContext* ir_context, uint32_t result_type = fuzzerutil::GetPointeeTypeIdFromPointerType( ir_context, fuzzerutil::GetTypeId(ir_context, message_.pointer_id())); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - FindInstruction(message_.instruction_to_insert_before(), ir_context) - ->InsertBefore(MakeUnique<opt::Instruction>( - ir_context, SpvOpLoad, result_type, message_.fresh_id(), - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}}))); - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); + auto insert_before = + FindInstruction(message_.instruction_to_insert_before(), ir_context); + auto new_instruction = MakeUnique<opt::Instruction>( + ir_context, SpvOpLoad, result_type, message_.fresh_id(), + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}})); + auto new_instruction_ptr = new_instruction.get(); + insert_before->InsertBefore(std::move(new_instruction)); + // Inform the def-use manager about the new instruction and record its basic + // block. + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr); + ir_context->set_instr_block(new_instruction_ptr, + ir_context->get_instr_block(insert_before)); } protobufs::Transformation TransformationLoad::ToMessage() const { diff --git a/source/fuzz/transformation_load.h b/source/fuzz/transformation_load.h index 683bba52..d10b0073 100644 --- a/source/fuzz/transformation_load.h +++ b/source/fuzz/transformation_load.h @@ -25,7 +25,7 @@ namespace fuzz { class TransformationLoad : public Transformation { public: - explicit TransformationLoad(const protobufs::TransformationLoad& message); + explicit TransformationLoad(protobufs::TransformationLoad message); TransformationLoad( uint32_t fresh_id, uint32_t pointer_id, diff --git a/source/fuzz/transformation_make_vector_operation_dynamic.cpp b/source/fuzz/transformation_make_vector_operation_dynamic.cpp index d6d51404..bd0664c0 100644 --- a/source/fuzz/transformation_make_vector_operation_dynamic.cpp +++ b/source/fuzz/transformation_make_vector_operation_dynamic.cpp @@ -22,9 +22,8 @@ namespace fuzz { TransformationMakeVectorOperationDynamic:: TransformationMakeVectorOperationDynamic( - const spvtools::fuzz::protobufs:: - TransformationMakeVectorOperationDynamic& message) - : message_(message) {} + protobufs::TransformationMakeVectorOperationDynamic message) + : message_(std::move(message)) {} TransformationMakeVectorOperationDynamic:: TransformationMakeVectorOperationDynamic(uint32_t instruction_result_id, diff --git a/source/fuzz/transformation_make_vector_operation_dynamic.h b/source/fuzz/transformation_make_vector_operation_dynamic.h index d1765c52..e444f40c 100644 --- a/source/fuzz/transformation_make_vector_operation_dynamic.h +++ b/source/fuzz/transformation_make_vector_operation_dynamic.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationMakeVectorOperationDynamic : public Transformation { public: explicit TransformationMakeVectorOperationDynamic( - const protobufs::TransformationMakeVectorOperationDynamic& message); + protobufs::TransformationMakeVectorOperationDynamic message); TransformationMakeVectorOperationDynamic(uint32_t instruction_result_id, uint32_t constant_index_id); diff --git a/source/fuzz/transformation_merge_blocks.cpp b/source/fuzz/transformation_merge_blocks.cpp index 2a9e90cc..22236795 100644 --- a/source/fuzz/transformation_merge_blocks.cpp +++ b/source/fuzz/transformation_merge_blocks.cpp @@ -21,8 +21,8 @@ namespace spvtools { namespace fuzz { TransformationMergeBlocks::TransformationMergeBlocks( - const spvtools::fuzz::protobufs::TransformationMergeBlocks& message) - : message_(message) {} + protobufs::TransformationMergeBlocks message) + : message_(std::move(message)) {} TransformationMergeBlocks::TransformationMergeBlocks(uint32_t block_id) { message_.set_block_id(block_id); diff --git a/source/fuzz/transformation_merge_blocks.h b/source/fuzz/transformation_merge_blocks.h index d9a0ca05..f6306c5a 100644 --- a/source/fuzz/transformation_merge_blocks.h +++ b/source/fuzz/transformation_merge_blocks.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationMergeBlocks : public Transformation { public: explicit TransformationMergeBlocks( - const protobufs::TransformationMergeBlocks& message); + protobufs::TransformationMergeBlocks message); TransformationMergeBlocks(uint32_t block_id); diff --git a/source/fuzz/transformation_merge_function_returns.cpp b/source/fuzz/transformation_merge_function_returns.cpp index c7cb5572..1aefedc0 100644 --- a/source/fuzz/transformation_merge_function_returns.cpp +++ b/source/fuzz/transformation_merge_function_returns.cpp @@ -21,8 +21,8 @@ namespace spvtools { namespace fuzz { TransformationMergeFunctionReturns::TransformationMergeFunctionReturns( - const protobufs::TransformationMergeFunctionReturns& message) - : message_(message) {} + protobufs::TransformationMergeFunctionReturns message) + : message_(std::move(message)) {} TransformationMergeFunctionReturns::TransformationMergeFunctionReturns( uint32_t function_id, uint32_t outer_header_id, uint32_t outer_return_id, diff --git a/source/fuzz/transformation_merge_function_returns.h b/source/fuzz/transformation_merge_function_returns.h index 4b299367..8f0937c2 100644 --- a/source/fuzz/transformation_merge_function_returns.h +++ b/source/fuzz/transformation_merge_function_returns.h @@ -22,7 +22,7 @@ namespace fuzz { class TransformationMergeFunctionReturns : public Transformation { public: explicit TransformationMergeFunctionReturns( - const protobufs::TransformationMergeFunctionReturns& message); + protobufs::TransformationMergeFunctionReturns message); TransformationMergeFunctionReturns( uint32_t function_id, uint32_t outer_header_id, uint32_t outer_return_id, diff --git a/source/fuzz/transformation_move_block_down.cpp b/source/fuzz/transformation_move_block_down.cpp index c5ed4333..dc1b2430 100644 --- a/source/fuzz/transformation_move_block_down.cpp +++ b/source/fuzz/transformation_move_block_down.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationMoveBlockDown::TransformationMoveBlockDown( - const spvtools::fuzz::protobufs::TransformationMoveBlockDown& message) - : message_(message) {} + protobufs::TransformationMoveBlockDown message) + : message_(std::move(message)) {} TransformationMoveBlockDown::TransformationMoveBlockDown(uint32_t id) { message_.set_block_id(id); diff --git a/source/fuzz/transformation_move_block_down.h b/source/fuzz/transformation_move_block_down.h index 82f2599a..cbad9451 100644 --- a/source/fuzz/transformation_move_block_down.h +++ b/source/fuzz/transformation_move_block_down.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationMoveBlockDown : public Transformation { public: explicit TransformationMoveBlockDown( - const protobufs::TransformationMoveBlockDown& message); + protobufs::TransformationMoveBlockDown message); explicit TransformationMoveBlockDown(uint32_t id); diff --git a/source/fuzz/transformation_move_instruction_down.cpp b/source/fuzz/transformation_move_instruction_down.cpp index dec05789..c8139e72 100644 --- a/source/fuzz/transformation_move_instruction_down.cpp +++ b/source/fuzz/transformation_move_instruction_down.cpp @@ -38,8 +38,8 @@ std::string GetExtensionSet(opt::IRContext* ir_context, } // namespace TransformationMoveInstructionDown::TransformationMoveInstructionDown( - const protobufs::TransformationMoveInstructionDown& message) - : message_(message) {} + protobufs::TransformationMoveInstructionDown message) + : message_(std::move(message)) {} TransformationMoveInstructionDown::TransformationMoveInstructionDown( const protobufs::InstructionDescriptor& instruction) { diff --git a/source/fuzz/transformation_move_instruction_down.h b/source/fuzz/transformation_move_instruction_down.h index 85852253..2a5a8f1f 100644 --- a/source/fuzz/transformation_move_instruction_down.h +++ b/source/fuzz/transformation_move_instruction_down.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationMoveInstructionDown : public Transformation { public: explicit TransformationMoveInstructionDown( - const protobufs::TransformationMoveInstructionDown& message); + protobufs::TransformationMoveInstructionDown message); explicit TransformationMoveInstructionDown( const protobufs::InstructionDescriptor& instruction); diff --git a/source/fuzz/transformation_mutate_pointer.cpp b/source/fuzz/transformation_mutate_pointer.cpp index fefedbd1..516a0d61 100644 --- a/source/fuzz/transformation_mutate_pointer.cpp +++ b/source/fuzz/transformation_mutate_pointer.cpp @@ -21,8 +21,8 @@ namespace spvtools { namespace fuzz { TransformationMutatePointer::TransformationMutatePointer( - const protobufs::TransformationMutatePointer& message) - : message_(message) {} + protobufs::TransformationMutatePointer message) + : message_(std::move(message)) {} TransformationMutatePointer::TransformationMutatePointer( uint32_t pointer_id, uint32_t fresh_id, @@ -92,36 +92,47 @@ void TransformationMutatePointer::Apply( auto* insert_before_inst = FindInstruction(message_.insert_before(), ir_context); assert(insert_before_inst && "|insert_before| descriptor is invalid"); + opt::BasicBlock* enclosing_block = + ir_context->get_instr_block(insert_before_inst); auto pointee_type_id = fuzzerutil::GetPointeeTypeIdFromPointerType( ir_context, fuzzerutil::GetTypeId(ir_context, message_.pointer_id())); // Back up the original value. - insert_before_inst->InsertBefore(MakeUnique<opt::Instruction>( + auto backup_instruction = MakeUnique<opt::Instruction>( ir_context, SpvOpLoad, pointee_type_id, message_.fresh_id(), opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}})); + {SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}}); + auto backup_instruction_ptr = backup_instruction.get(); + insert_before_inst->InsertBefore(std::move(backup_instruction)); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(backup_instruction_ptr); + ir_context->set_instr_block(backup_instruction_ptr, enclosing_block); // Insert a new value. - insert_before_inst->InsertBefore(MakeUnique<opt::Instruction>( + auto new_value_instruction = MakeUnique<opt::Instruction>( ir_context, SpvOpStore, 0, 0, opt::Instruction::OperandList{ {SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}, {SPV_OPERAND_TYPE_ID, {fuzzerutil::MaybeGetZeroConstant( - ir_context, *transformation_context, pointee_type_id, true)}}})); + ir_context, *transformation_context, pointee_type_id, true)}}}); + auto new_value_instruction_ptr = new_value_instruction.get(); + insert_before_inst->InsertBefore(std::move(new_value_instruction)); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_value_instruction_ptr); + ir_context->set_instr_block(new_value_instruction_ptr, enclosing_block); // Restore the original value. - insert_before_inst->InsertBefore(MakeUnique<opt::Instruction>( + auto restore_instruction = MakeUnique<opt::Instruction>( ir_context, SpvOpStore, 0, 0, opt::Instruction::OperandList{ {SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}, - {SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}})); + {SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}}); + auto restore_instruction_ptr = restore_instruction.get(); + insert_before_inst->InsertBefore(std::move(restore_instruction)); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(restore_instruction_ptr); + ir_context->set_instr_block(restore_instruction_ptr, enclosing_block); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - - // Make sure analyses represent the correct state of the module. - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); } protobufs::Transformation TransformationMutatePointer::ToMessage() const { diff --git a/source/fuzz/transformation_mutate_pointer.h b/source/fuzz/transformation_mutate_pointer.h index b9f09656..2c712909 100644 --- a/source/fuzz/transformation_mutate_pointer.h +++ b/source/fuzz/transformation_mutate_pointer.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationMutatePointer : public Transformation { public: explicit TransformationMutatePointer( - const protobufs::TransformationMutatePointer& message); + protobufs::TransformationMutatePointer message); explicit TransformationMutatePointer( uint32_t pointer_id, uint32_t fresh_id, diff --git a/source/fuzz/transformation_outline_function.cpp b/source/fuzz/transformation_outline_function.cpp index 643fd699..6ee91225 100644 --- a/source/fuzz/transformation_outline_function.cpp +++ b/source/fuzz/transformation_outline_function.cpp @@ -22,8 +22,8 @@ namespace spvtools { namespace fuzz { TransformationOutlineFunction::TransformationOutlineFunction( - const spvtools::fuzz::protobufs::TransformationOutlineFunction& message) - : message_(message) {} + protobufs::TransformationOutlineFunction message) + : message_(std::move(message)) {} TransformationOutlineFunction::TransformationOutlineFunction( uint32_t entry_block, uint32_t exit_block, diff --git a/source/fuzz/transformation_outline_function.h b/source/fuzz/transformation_outline_function.h index 36c0daf5..94ce556d 100644 --- a/source/fuzz/transformation_outline_function.h +++ b/source/fuzz/transformation_outline_function.h @@ -30,7 +30,7 @@ namespace fuzz { class TransformationOutlineFunction : public Transformation { public: explicit TransformationOutlineFunction( - const protobufs::TransformationOutlineFunction& message); + protobufs::TransformationOutlineFunction message); TransformationOutlineFunction( uint32_t entry_block, uint32_t exit_block, diff --git a/source/fuzz/transformation_permute_function_parameters.cpp b/source/fuzz/transformation_permute_function_parameters.cpp index a954cc18..5663d72f 100644 --- a/source/fuzz/transformation_permute_function_parameters.cpp +++ b/source/fuzz/transformation_permute_function_parameters.cpp @@ -23,9 +23,8 @@ namespace fuzz { TransformationPermuteFunctionParameters:: TransformationPermuteFunctionParameters( - const spvtools::fuzz::protobufs:: - TransformationPermuteFunctionParameters& message) - : message_(message) {} + protobufs::TransformationPermuteFunctionParameters message) + : message_(std::move(message)) {} TransformationPermuteFunctionParameters:: TransformationPermuteFunctionParameters( diff --git a/source/fuzz/transformation_permute_function_parameters.h b/source/fuzz/transformation_permute_function_parameters.h index 38de8b18..abb5675c 100644 --- a/source/fuzz/transformation_permute_function_parameters.h +++ b/source/fuzz/transformation_permute_function_parameters.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationPermuteFunctionParameters : public Transformation { public: explicit TransformationPermuteFunctionParameters( - const protobufs::TransformationPermuteFunctionParameters& message); + protobufs::TransformationPermuteFunctionParameters message); TransformationPermuteFunctionParameters( uint32_t function_id, uint32_t function_type_fresh_id, diff --git a/source/fuzz/transformation_permute_phi_operands.cpp b/source/fuzz/transformation_permute_phi_operands.cpp index ebd3c862..60563312 100644 --- a/source/fuzz/transformation_permute_phi_operands.cpp +++ b/source/fuzz/transformation_permute_phi_operands.cpp @@ -22,8 +22,8 @@ namespace spvtools { namespace fuzz { TransformationPermutePhiOperands::TransformationPermutePhiOperands( - const spvtools::fuzz::protobufs::TransformationPermutePhiOperands& message) - : message_(message) {} + protobufs::TransformationPermutePhiOperands message) + : message_(std::move(message)) {} TransformationPermutePhiOperands::TransformationPermutePhiOperands( uint32_t result_id, const std::vector<uint32_t>& permutation) { @@ -80,9 +80,9 @@ void TransformationPermutePhiOperands::Apply( inst->SetInOperands(std::move(permuted_operands)); - // Make sure our changes are analyzed - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + // Update the def-use manager. + ir_context->get_def_use_mgr()->ClearInst(inst); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(inst); } protobufs::Transformation TransformationPermutePhiOperands::ToMessage() const { diff --git a/source/fuzz/transformation_permute_phi_operands.h b/source/fuzz/transformation_permute_phi_operands.h index 8198b706..16427113 100644 --- a/source/fuzz/transformation_permute_phi_operands.h +++ b/source/fuzz/transformation_permute_phi_operands.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationPermutePhiOperands : public Transformation { public: explicit TransformationPermutePhiOperands( - const protobufs::TransformationPermutePhiOperands& message); + protobufs::TransformationPermutePhiOperands message); TransformationPermutePhiOperands(uint32_t result_id, const std::vector<uint32_t>& permutation); diff --git a/source/fuzz/transformation_propagate_instruction_down.cpp b/source/fuzz/transformation_propagate_instruction_down.cpp index ba22e398..7713562e 100644 --- a/source/fuzz/transformation_propagate_instruction_down.cpp +++ b/source/fuzz/transformation_propagate_instruction_down.cpp @@ -21,8 +21,8 @@ namespace spvtools { namespace fuzz { TransformationPropagateInstructionDown::TransformationPropagateInstructionDown( - const protobufs::TransformationPropagateInstructionDown& message) - : message_(message) {} + protobufs::TransformationPropagateInstructionDown message) + : message_(std::move(message)) {} TransformationPropagateInstructionDown::TransformationPropagateInstructionDown( uint32_t block_id, uint32_t phi_fresh_id, diff --git a/source/fuzz/transformation_propagate_instruction_down.h b/source/fuzz/transformation_propagate_instruction_down.h index 7eca1ad1..560d7dc5 100644 --- a/source/fuzz/transformation_propagate_instruction_down.h +++ b/source/fuzz/transformation_propagate_instruction_down.h @@ -28,7 +28,7 @@ namespace fuzz { class TransformationPropagateInstructionDown : public Transformation { public: explicit TransformationPropagateInstructionDown( - const protobufs::TransformationPropagateInstructionDown& message); + protobufs::TransformationPropagateInstructionDown message); TransformationPropagateInstructionDown( uint32_t block_id, uint32_t phi_fresh_id, diff --git a/source/fuzz/transformation_propagate_instruction_up.cpp b/source/fuzz/transformation_propagate_instruction_up.cpp index a2cacf40..bf0e6630 100644 --- a/source/fuzz/transformation_propagate_instruction_up.cpp +++ b/source/fuzz/transformation_propagate_instruction_up.cpp @@ -79,8 +79,8 @@ bool HasValidDependencies(opt::IRContext* ir_context, opt::Instruction* inst) { } // namespace TransformationPropagateInstructionUp::TransformationPropagateInstructionUp( - const protobufs::TransformationPropagateInstructionUp& message) - : message_(message) {} + protobufs::TransformationPropagateInstructionUp message) + : message_(std::move(message)) {} TransformationPropagateInstructionUp::TransformationPropagateInstructionUp( uint32_t block_id, diff --git a/source/fuzz/transformation_propagate_instruction_up.h b/source/fuzz/transformation_propagate_instruction_up.h index 63540947..0ca051bf 100644 --- a/source/fuzz/transformation_propagate_instruction_up.h +++ b/source/fuzz/transformation_propagate_instruction_up.h @@ -28,7 +28,7 @@ namespace fuzz { class TransformationPropagateInstructionUp : public Transformation { public: explicit TransformationPropagateInstructionUp( - const protobufs::TransformationPropagateInstructionUp& message); + protobufs::TransformationPropagateInstructionUp message); TransformationPropagateInstructionUp( uint32_t block_id, diff --git a/source/fuzz/transformation_push_id_through_variable.cpp b/source/fuzz/transformation_push_id_through_variable.cpp index cdc40aab..0df1da6b 100644 --- a/source/fuzz/transformation_push_id_through_variable.cpp +++ b/source/fuzz/transformation_push_id_through_variable.cpp @@ -21,9 +21,8 @@ namespace spvtools { namespace fuzz { TransformationPushIdThroughVariable::TransformationPushIdThroughVariable( - const spvtools::fuzz::protobufs::TransformationPushIdThroughVariable& - message) - : message_(message) {} + protobufs::TransformationPushIdThroughVariable message) + : message_(std::move(message)) {} TransformationPushIdThroughVariable::TransformationPushIdThroughVariable( uint32_t value_id, uint32_t value_synonym_id, uint32_t variable_id, @@ -105,6 +104,10 @@ void TransformationPushIdThroughVariable::Apply( auto value_instruction = ir_context->get_def_use_mgr()->GetDef(message_.value_id()); + opt::Instruction* insert_before = + FindInstruction(message_.instruction_descriptor(), ir_context); + opt::BasicBlock* enclosing_block = ir_context->get_instr_block(insert_before); + // A pointer type instruction pointing to the value type must be defined. auto pointer_type_id = fuzzerutil::MaybeGetPointerType( ir_context, value_instruction->type_id(), @@ -113,36 +116,42 @@ void TransformationPushIdThroughVariable::Apply( // Adds whether a global or local variable. if (message_.variable_storage_class() == SpvStorageClassPrivate) { - fuzzerutil::AddGlobalVariable(ir_context, message_.variable_id(), - pointer_type_id, SpvStorageClassPrivate, - message_.initializer_id()); + opt::Instruction* global_variable = fuzzerutil::AddGlobalVariable( + ir_context, message_.variable_id(), pointer_type_id, + SpvStorageClassPrivate, message_.initializer_id()); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(global_variable); } else { - auto function_id = ir_context - ->get_instr_block(FindInstruction( - message_.instruction_descriptor(), ir_context)) - ->GetParent() - ->result_id(); - fuzzerutil::AddLocalVariable(ir_context, message_.variable_id(), - pointer_type_id, function_id, - message_.initializer_id()); + opt::Function* function = + ir_context + ->get_instr_block( + FindInstruction(message_.instruction_descriptor(), ir_context)) + ->GetParent(); + opt::Instruction* local_variable = fuzzerutil::AddLocalVariable( + ir_context, message_.variable_id(), pointer_type_id, + function->result_id(), message_.initializer_id()); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(local_variable); + ir_context->set_instr_block(local_variable, &*function->entry()); } // First, insert the OpLoad instruction before |instruction_descriptor| and // then insert the OpStore instruction before the OpLoad instruction. fuzzerutil::UpdateModuleIdBound(ir_context, message_.value_synonym_id()); - FindInstruction(message_.instruction_descriptor(), ir_context) - ->InsertBefore(MakeUnique<opt::Instruction>( + opt::Instruction* load_instruction = + insert_before->InsertBefore(MakeUnique<opt::Instruction>( ir_context, SpvOpLoad, value_instruction->type_id(), message_.value_synonym_id(), opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {message_.variable_id()}}}))) - ->InsertBefore(MakeUnique<opt::Instruction>( + {{SPV_OPERAND_TYPE_ID, {message_.variable_id()}}}))); + opt::Instruction* store_instruction = + load_instruction->InsertBefore(MakeUnique<opt::Instruction>( ir_context, SpvOpStore, 0, 0, opt::Instruction::OperandList( {{SPV_OPERAND_TYPE_ID, {message_.variable_id()}}, {SPV_OPERAND_TYPE_ID, {message_.value_id()}}}))); - - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(store_instruction); + ir_context->set_instr_block(store_instruction, enclosing_block); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(load_instruction); + ir_context->set_instr_block(load_instruction, enclosing_block); // We should be able to create a synonym of |value_id| if it's not irrelevant. if (fuzzerutil::CanMakeSynonymOf(ir_context, *transformation_context, diff --git a/source/fuzz/transformation_push_id_through_variable.h b/source/fuzz/transformation_push_id_through_variable.h index d0558259..ec6943ca 100644 --- a/source/fuzz/transformation_push_id_through_variable.h +++ b/source/fuzz/transformation_push_id_through_variable.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationPushIdThroughVariable : public Transformation { public: explicit TransformationPushIdThroughVariable( - const protobufs::TransformationPushIdThroughVariable& message); + protobufs::TransformationPushIdThroughVariable message); TransformationPushIdThroughVariable( uint32_t value_id, uint32_t value_synonym_fresh_id, diff --git a/source/fuzz/transformation_record_synonymous_constants.cpp b/source/fuzz/transformation_record_synonymous_constants.cpp index 30ea94bb..3278d7d8 100644 --- a/source/fuzz/transformation_record_synonymous_constants.cpp +++ b/source/fuzz/transformation_record_synonymous_constants.cpp @@ -22,8 +22,8 @@ namespace fuzz { TransformationRecordSynonymousConstants:: TransformationRecordSynonymousConstants( - const protobufs::TransformationRecordSynonymousConstants& message) - : message_(message) {} + protobufs::TransformationRecordSynonymousConstants message) + : message_(std::move(message)) {} TransformationRecordSynonymousConstants:: TransformationRecordSynonymousConstants(uint32_t constant1_id, diff --git a/source/fuzz/transformation_record_synonymous_constants.h b/source/fuzz/transformation_record_synonymous_constants.h index 4376c878..d99b0e2a 100644 --- a/source/fuzz/transformation_record_synonymous_constants.h +++ b/source/fuzz/transformation_record_synonymous_constants.h @@ -24,7 +24,7 @@ namespace fuzz { class TransformationRecordSynonymousConstants : public Transformation { public: explicit TransformationRecordSynonymousConstants( - const protobufs::TransformationRecordSynonymousConstants& message); + protobufs::TransformationRecordSynonymousConstants message); TransformationRecordSynonymousConstants(uint32_t constant1_id, uint32_t constant2_id); diff --git a/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.cpp b/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.cpp index a2575153..e1977a64 100644 --- a/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.cpp +++ b/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.cpp @@ -27,9 +27,8 @@ const uint32_t kArithmeticInstructionIndexRightInOperand = 1; TransformationReplaceAddSubMulWithCarryingExtended:: TransformationReplaceAddSubMulWithCarryingExtended( - const spvtools::fuzz::protobufs:: - TransformationReplaceAddSubMulWithCarryingExtended& message) - : message_(message) {} + protobufs::TransformationReplaceAddSubMulWithCarryingExtended message) + : message_(std::move(message)) {} TransformationReplaceAddSubMulWithCarryingExtended:: TransformationReplaceAddSubMulWithCarryingExtended(uint32_t struct_fresh_id, diff --git a/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.h b/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.h index 243542c2..9deb2803 100644 --- a/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.h +++ b/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.h @@ -27,8 +27,7 @@ class TransformationReplaceAddSubMulWithCarryingExtended : public Transformation { public: explicit TransformationReplaceAddSubMulWithCarryingExtended( - const protobufs::TransformationReplaceAddSubMulWithCarryingExtended& - message); + protobufs::TransformationReplaceAddSubMulWithCarryingExtended message); explicit TransformationReplaceAddSubMulWithCarryingExtended( uint32_t struct_fresh_id, uint32_t result_id); diff --git a/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp b/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp index b458b569..24293516 100644 --- a/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp +++ b/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp @@ -111,9 +111,9 @@ bool unsigned_int_binop_evaluates_to(T lhs, T rhs, SpvOp binop, TransformationReplaceBooleanConstantWithConstantBinary:: TransformationReplaceBooleanConstantWithConstantBinary( - const spvtools::fuzz::protobufs:: - TransformationReplaceBooleanConstantWithConstantBinary& message) - : message_(message) {} + protobufs::TransformationReplaceBooleanConstantWithConstantBinary + message) + : message_(std::move(message)) {} TransformationReplaceBooleanConstantWithConstantBinary:: TransformationReplaceBooleanConstantWithConstantBinary( diff --git a/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h b/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h index a0ece7f3..97c66bf9 100644 --- a/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h +++ b/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h @@ -27,7 +27,7 @@ class TransformationReplaceBooleanConstantWithConstantBinary : public Transformation { public: explicit TransformationReplaceBooleanConstantWithConstantBinary( - const protobufs::TransformationReplaceBooleanConstantWithConstantBinary& + protobufs::TransformationReplaceBooleanConstantWithConstantBinary message); TransformationReplaceBooleanConstantWithConstantBinary( diff --git a/source/fuzz/transformation_replace_branch_from_dead_block_with_exit.cpp b/source/fuzz/transformation_replace_branch_from_dead_block_with_exit.cpp index e8090121..9ea7cb6a 100644 --- a/source/fuzz/transformation_replace_branch_from_dead_block_with_exit.cpp +++ b/source/fuzz/transformation_replace_branch_from_dead_block_with_exit.cpp @@ -21,9 +21,8 @@ namespace fuzz { TransformationReplaceBranchFromDeadBlockWithExit:: TransformationReplaceBranchFromDeadBlockWithExit( - const spvtools::fuzz::protobufs:: - TransformationReplaceBranchFromDeadBlockWithExit& message) - : message_(message) {} + protobufs::TransformationReplaceBranchFromDeadBlockWithExit message) + : message_(std::move(message)) {} TransformationReplaceBranchFromDeadBlockWithExit:: TransformationReplaceBranchFromDeadBlockWithExit(uint32_t block_id, @@ -162,7 +161,10 @@ bool TransformationReplaceBranchFromDeadBlockWithExit::BlockIsSuitable( if (ir_context->cfg()->preds(successor->id()).size() < 2) { return false; } - return true; + // Make sure that domination rules are satisfied when we remove the branch + // from the |block| to its |successor|. + return fuzzerutil::NewTerminatorPreservesDominationRules( + ir_context, block.id(), {ir_context, SpvOpUnreachable}); } } // namespace fuzz diff --git a/source/fuzz/transformation_replace_branch_from_dead_block_with_exit.h b/source/fuzz/transformation_replace_branch_from_dead_block_with_exit.h index e1418c9d..89667fcd 100644 --- a/source/fuzz/transformation_replace_branch_from_dead_block_with_exit.h +++ b/source/fuzz/transformation_replace_branch_from_dead_block_with_exit.h @@ -27,8 +27,7 @@ namespace fuzz { class TransformationReplaceBranchFromDeadBlockWithExit : public Transformation { public: explicit TransformationReplaceBranchFromDeadBlockWithExit( - const protobufs::TransformationReplaceBranchFromDeadBlockWithExit& - message); + protobufs::TransformationReplaceBranchFromDeadBlockWithExit message); TransformationReplaceBranchFromDeadBlockWithExit(uint32_t block_id, SpvOp opcode, @@ -41,13 +40,17 @@ class TransformationReplaceBranchFromDeadBlockWithExit : public Transformation { // predecessor // - |message_.opcode()| must be one of OpKill, OpReturn, OpReturnValue and // OpUnreachable - // - |message_.opcode()| can only be OpKill the module's entry points all + // - |message_.opcode()| can only be OpKill if the module's entry points all // have Fragment execution mode // - |message_.opcode()| can only be OpReturn if the return type of the // function containing the block is void // - If |message_.opcode()| is OpReturnValue then |message_.return_value_id| // must be an id that is available at the block terminator and that matches // the return type of the enclosing function + // - Domination rules should be preserved when we apply this transformation. + // In particular, if some block appears after the |block_id|'s successor in + // the CFG, then that block cannot dominate |block_id|'s successor when this + // transformation is applied. bool IsApplicable( opt::IRContext* ir_context, const TransformationContext& transformation_context) const override; diff --git a/source/fuzz/transformation_replace_constant_with_uniform.cpp b/source/fuzz/transformation_replace_constant_with_uniform.cpp index 95932bf6..c6698c03 100644 --- a/source/fuzz/transformation_replace_constant_with_uniform.cpp +++ b/source/fuzz/transformation_replace_constant_with_uniform.cpp @@ -22,9 +22,8 @@ namespace fuzz { TransformationReplaceConstantWithUniform:: TransformationReplaceConstantWithUniform( - const spvtools::fuzz::protobufs:: - TransformationReplaceConstantWithUniform& message) - : message_(message) {} + protobufs::TransformationReplaceConstantWithUniform message) + : message_(std::move(message)) {} TransformationReplaceConstantWithUniform:: TransformationReplaceConstantWithUniform( @@ -254,28 +253,39 @@ void TransformationReplaceConstantWithUniform::Apply( auto* insert_before_inst = GetInsertBeforeInstruction(ir_context); assert(insert_before_inst && "There must exist an insertion point for OpAccessChain and OpLoad"); + opt::BasicBlock* enclosing_block = + ir_context->get_instr_block(insert_before_inst); // Add an access chain instruction to target the uniform element. - insert_before_inst->InsertBefore( - MakeAccessChainInstruction(ir_context, constant_type_id)); + auto access_chain_instruction = + MakeAccessChainInstruction(ir_context, constant_type_id); + auto access_chain_instruction_ptr = access_chain_instruction.get(); + insert_before_inst->InsertBefore(std::move(access_chain_instruction)); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse( + access_chain_instruction_ptr); + ir_context->set_instr_block(access_chain_instruction_ptr, enclosing_block); // Add a load from this access chain. - insert_before_inst->InsertBefore( - MakeLoadInstruction(ir_context, constant_type_id)); + auto load_instruction = MakeLoadInstruction(ir_context, constant_type_id); + auto load_instruction_ptr = load_instruction.get(); + insert_before_inst->InsertBefore(std::move(load_instruction)); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(load_instruction_ptr); + ir_context->set_instr_block(load_instruction_ptr, enclosing_block); // Adjust the instruction containing the usage of the constant so that this // usage refers instead to the result of the load. instruction_containing_constant_use->SetInOperand( message_.id_use_descriptor().in_operand_index(), {message_.fresh_id_for_load()}); + ir_context->get_def_use_mgr()->EraseUseRecordsOfOperandIds( + instruction_containing_constant_use); + ir_context->get_def_use_mgr()->AnalyzeInstUse( + instruction_containing_constant_use); // Update the module id bound to reflect the new instructions. fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id_for_load()); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id_for_access_chain()); - - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); } protobufs::Transformation TransformationReplaceConstantWithUniform::ToMessage() diff --git a/source/fuzz/transformation_replace_constant_with_uniform.h b/source/fuzz/transformation_replace_constant_with_uniform.h index 9e097484..21210927 100644 --- a/source/fuzz/transformation_replace_constant_with_uniform.h +++ b/source/fuzz/transformation_replace_constant_with_uniform.h @@ -28,7 +28,7 @@ namespace fuzz { class TransformationReplaceConstantWithUniform : public Transformation { public: explicit TransformationReplaceConstantWithUniform( - const protobufs::TransformationReplaceConstantWithUniform& message); + protobufs::TransformationReplaceConstantWithUniform message); TransformationReplaceConstantWithUniform( protobufs::IdUseDescriptor id_use, diff --git a/source/fuzz/transformation_replace_copy_memory_with_load_store.cpp b/source/fuzz/transformation_replace_copy_memory_with_load_store.cpp index 936b0542..de9d1fd3 100644 --- a/source/fuzz/transformation_replace_copy_memory_with_load_store.cpp +++ b/source/fuzz/transformation_replace_copy_memory_with_load_store.cpp @@ -22,9 +22,8 @@ namespace fuzz { TransformationReplaceCopyMemoryWithLoadStore:: TransformationReplaceCopyMemoryWithLoadStore( - const spvtools::fuzz::protobufs:: - TransformationReplaceCopyMemoryWithLoadStore& message) - : message_(message) {} + protobufs::TransformationReplaceCopyMemoryWithLoadStore message) + : message_(std::move(message)) {} TransformationReplaceCopyMemoryWithLoadStore:: TransformationReplaceCopyMemoryWithLoadStore( diff --git a/source/fuzz/transformation_replace_copy_memory_with_load_store.h b/source/fuzz/transformation_replace_copy_memory_with_load_store.h index 67d349ff..55d1e064 100644 --- a/source/fuzz/transformation_replace_copy_memory_with_load_store.h +++ b/source/fuzz/transformation_replace_copy_memory_with_load_store.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationReplaceCopyMemoryWithLoadStore : public Transformation { public: explicit TransformationReplaceCopyMemoryWithLoadStore( - const protobufs::TransformationReplaceCopyMemoryWithLoadStore& message); + protobufs::TransformationReplaceCopyMemoryWithLoadStore message); TransformationReplaceCopyMemoryWithLoadStore( uint32_t fresh_id, const protobufs::InstructionDescriptor& diff --git a/source/fuzz/transformation_replace_copy_object_with_store_load.cpp b/source/fuzz/transformation_replace_copy_object_with_store_load.cpp index 54c99d51..e0643bf3 100644 --- a/source/fuzz/transformation_replace_copy_object_with_store_load.cpp +++ b/source/fuzz/transformation_replace_copy_object_with_store_load.cpp @@ -22,9 +22,8 @@ namespace fuzz { TransformationReplaceCopyObjectWithStoreLoad:: TransformationReplaceCopyObjectWithStoreLoad( - const spvtools::fuzz::protobufs:: - TransformationReplaceCopyObjectWithStoreLoad& message) - : message_(message) {} + protobufs::TransformationReplaceCopyObjectWithStoreLoad message) + : message_(std::move(message)) {} TransformationReplaceCopyObjectWithStoreLoad:: TransformationReplaceCopyObjectWithStoreLoad( @@ -88,6 +87,10 @@ void TransformationReplaceCopyObjectWithStoreLoad::Apply( assert(copy_object_instruction && copy_object_instruction->opcode() == SpvOpCopyObject && "The required OpCopyObject instruction must be defined."); + + opt::BasicBlock* enclosing_block = + ir_context->get_instr_block(copy_object_instruction); + // Get id used as a source by the OpCopyObject instruction. uint32_t src_operand = copy_object_instruction->GetSingleWordInOperand(0); // A pointer type instruction pointing to the value type must be defined. @@ -98,37 +101,46 @@ void TransformationReplaceCopyObjectWithStoreLoad::Apply( // Adds a global or local variable (according to the storage class). if (message_.variable_storage_class() == SpvStorageClassPrivate) { - fuzzerutil::AddGlobalVariable(ir_context, message_.fresh_variable_id(), - pointer_type_id, SpvStorageClassPrivate, - message_.variable_initializer_id()); + opt::Instruction* new_global = fuzzerutil::AddGlobalVariable( + ir_context, message_.fresh_variable_id(), pointer_type_id, + SpvStorageClassPrivate, message_.variable_initializer_id()); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_global); } else { - auto function_id = ir_context->get_instr_block(copy_object_instruction) - ->GetParent() - ->result_id(); - fuzzerutil::AddLocalVariable(ir_context, message_.fresh_variable_id(), - pointer_type_id, function_id, - message_.variable_initializer_id()); + opt::Function* function = + ir_context->get_instr_block(copy_object_instruction)->GetParent(); + opt::Instruction* new_local = fuzzerutil::AddLocalVariable( + ir_context, message_.fresh_variable_id(), pointer_type_id, + function->result_id(), message_.variable_initializer_id()); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_local); + ir_context->set_instr_block(new_local, &*function->begin()); } // First, insert the OpLoad instruction before the OpCopyObject instruction // and then insert the OpStore instruction before the OpLoad instruction. fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_variable_id()); - copy_object_instruction - ->InsertBefore(MakeUnique<opt::Instruction>( + opt::Instruction* load_instruction = + copy_object_instruction->InsertBefore(MakeUnique<opt::Instruction>( ir_context, SpvOpLoad, copy_object_instruction->type_id(), message_.copy_object_result_id(), opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {message_.fresh_variable_id()}}}))) - ->InsertBefore(MakeUnique<opt::Instruction>( + {{SPV_OPERAND_TYPE_ID, {message_.fresh_variable_id()}}}))); + opt::Instruction* store_instruction = + load_instruction->InsertBefore(MakeUnique<opt::Instruction>( ir_context, SpvOpStore, 0, 0, opt::Instruction::OperandList( {{SPV_OPERAND_TYPE_ID, {message_.fresh_variable_id()}}, {SPV_OPERAND_TYPE_ID, {src_operand}}}))); + + // Register the new instructions with the def-use manager, and record their + // enclosing block. + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(store_instruction); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(load_instruction); + ir_context->set_instr_block(store_instruction, enclosing_block); + ir_context->set_instr_block(load_instruction, enclosing_block); + // Remove the CopyObject instruction. ir_context->KillInst(copy_object_instruction); - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); - if (!transformation_context->GetFactManager()->IdIsIrrelevant( message_.copy_object_result_id()) && !transformation_context->GetFactManager()->IdIsIrrelevant(src_operand)) { diff --git a/source/fuzz/transformation_replace_copy_object_with_store_load.h b/source/fuzz/transformation_replace_copy_object_with_store_load.h index a90905c5..8c5ce9e2 100644 --- a/source/fuzz/transformation_replace_copy_object_with_store_load.h +++ b/source/fuzz/transformation_replace_copy_object_with_store_load.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationReplaceCopyObjectWithStoreLoad : public Transformation { public: explicit TransformationReplaceCopyObjectWithStoreLoad( - const protobufs::TransformationReplaceCopyObjectWithStoreLoad& message); + protobufs::TransformationReplaceCopyObjectWithStoreLoad message); TransformationReplaceCopyObjectWithStoreLoad( uint32_t copy_object_result_id, uint32_t fresh_variable_id, diff --git a/source/fuzz/transformation_replace_id_with_synonym.cpp b/source/fuzz/transformation_replace_id_with_synonym.cpp index 24e079ff..92ce751d 100644 --- a/source/fuzz/transformation_replace_id_with_synonym.cpp +++ b/source/fuzz/transformation_replace_id_with_synonym.cpp @@ -26,9 +26,8 @@ namespace spvtools { namespace fuzz { TransformationReplaceIdWithSynonym::TransformationReplaceIdWithSynonym( - const spvtools::fuzz::protobufs::TransformationReplaceIdWithSynonym& - message) - : message_(message) {} + protobufs::TransformationReplaceIdWithSynonym message) + : message_(std::move(message)) {} TransformationReplaceIdWithSynonym::TransformationReplaceIdWithSynonym( protobufs::IdUseDescriptor id_use_descriptor, uint32_t synonymous_id) { @@ -95,8 +94,12 @@ void TransformationReplaceIdWithSynonym::Apply( instruction_to_change->SetInOperand( message_.id_use_descriptor().in_operand_index(), {message_.synonymous_id()}); - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + ir_context->get_def_use_mgr()->EraseUseRecordsOfOperandIds( + instruction_to_change); + ir_context->get_def_use_mgr()->AnalyzeInstUse(instruction_to_change); + + // No analyses need to be invalidated, since the transformation is local to a + // block, and the def-use analysis has been updated. } protobufs::Transformation TransformationReplaceIdWithSynonym::ToMessage() diff --git a/source/fuzz/transformation_replace_id_with_synonym.h b/source/fuzz/transformation_replace_id_with_synonym.h index 3101710a..1ac636b4 100644 --- a/source/fuzz/transformation_replace_id_with_synonym.h +++ b/source/fuzz/transformation_replace_id_with_synonym.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationReplaceIdWithSynonym : public Transformation { public: explicit TransformationReplaceIdWithSynonym( - const protobufs::TransformationReplaceIdWithSynonym& message); + protobufs::TransformationReplaceIdWithSynonym message); TransformationReplaceIdWithSynonym( protobufs::IdUseDescriptor id_use_descriptor, uint32_t synonymous_id); diff --git a/source/fuzz/transformation_replace_irrelevant_id.cpp b/source/fuzz/transformation_replace_irrelevant_id.cpp index 27f56eba..a71f96a8 100644 --- a/source/fuzz/transformation_replace_irrelevant_id.cpp +++ b/source/fuzz/transformation_replace_irrelevant_id.cpp @@ -21,8 +21,8 @@ namespace spvtools { namespace fuzz { TransformationReplaceIrrelevantId::TransformationReplaceIrrelevantId( - const protobufs::TransformationReplaceIrrelevantId& message) - : message_(message) {} + protobufs::TransformationReplaceIrrelevantId message) + : message_(std::move(message)) {} TransformationReplaceIrrelevantId::TransformationReplaceIrrelevantId( const protobufs::IdUseDescriptor& id_use_descriptor, @@ -107,9 +107,12 @@ void TransformationReplaceIrrelevantId::Apply( message_.id_use_descriptor().in_operand_index(), {message_.replacement_id()}); - // Invalidate the analyses, since the usage of ids has been changed. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + ir_context->get_def_use_mgr()->EraseUseRecordsOfOperandIds( + instruction_to_change); + ir_context->get_def_use_mgr()->AnalyzeInstUse(instruction_to_change); + + // No analyses need to be invalidated, since the transformation is local to a + // block, and the def-use analysis has been updated. } protobufs::Transformation TransformationReplaceIrrelevantId::ToMessage() const { diff --git a/source/fuzz/transformation_replace_irrelevant_id.h b/source/fuzz/transformation_replace_irrelevant_id.h index 35b1987d..e6210b4d 100644 --- a/source/fuzz/transformation_replace_irrelevant_id.h +++ b/source/fuzz/transformation_replace_irrelevant_id.h @@ -23,7 +23,7 @@ namespace fuzz { class TransformationReplaceIrrelevantId : public Transformation { public: explicit TransformationReplaceIrrelevantId( - const protobufs::TransformationReplaceIrrelevantId& message); + protobufs::TransformationReplaceIrrelevantId message); TransformationReplaceIrrelevantId( const protobufs::IdUseDescriptor& id_use_descriptor, diff --git a/source/fuzz/transformation_replace_linear_algebra_instruction.cpp b/source/fuzz/transformation_replace_linear_algebra_instruction.cpp index fc73a262..2430ccab 100644 --- a/source/fuzz/transformation_replace_linear_algebra_instruction.cpp +++ b/source/fuzz/transformation_replace_linear_algebra_instruction.cpp @@ -22,9 +22,8 @@ namespace fuzz { TransformationReplaceLinearAlgebraInstruction:: TransformationReplaceLinearAlgebraInstruction( - const spvtools::fuzz::protobufs:: - TransformationReplaceLinearAlgebraInstruction& message) - : message_(message) {} + protobufs::TransformationReplaceLinearAlgebraInstruction message) + : message_(std::move(message)) {} TransformationReplaceLinearAlgebraInstruction:: TransformationReplaceLinearAlgebraInstruction( diff --git a/source/fuzz/transformation_replace_linear_algebra_instruction.h b/source/fuzz/transformation_replace_linear_algebra_instruction.h index 45f4aa64..0f0c18bf 100644 --- a/source/fuzz/transformation_replace_linear_algebra_instruction.h +++ b/source/fuzz/transformation_replace_linear_algebra_instruction.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationReplaceLinearAlgebraInstruction : public Transformation { public: explicit TransformationReplaceLinearAlgebraInstruction( - const protobufs::TransformationReplaceLinearAlgebraInstruction& message); + protobufs::TransformationReplaceLinearAlgebraInstruction message); TransformationReplaceLinearAlgebraInstruction( const std::vector<uint32_t>& fresh_ids, diff --git a/source/fuzz/transformation_replace_load_store_with_copy_memory.cpp b/source/fuzz/transformation_replace_load_store_with_copy_memory.cpp index 6067fca8..e75337f6 100644 --- a/source/fuzz/transformation_replace_load_store_with_copy_memory.cpp +++ b/source/fuzz/transformation_replace_load_store_with_copy_memory.cpp @@ -29,9 +29,8 @@ const uint32_t kOpLoadOperandIndexSourceVariable = 2; TransformationReplaceLoadStoreWithCopyMemory:: TransformationReplaceLoadStoreWithCopyMemory( - const spvtools::fuzz::protobufs:: - TransformationReplaceLoadStoreWithCopyMemory& message) - : message_(message) {} + protobufs::TransformationReplaceLoadStoreWithCopyMemory message) + : message_(std::move(message)) {} TransformationReplaceLoadStoreWithCopyMemory:: TransformationReplaceLoadStoreWithCopyMemory( diff --git a/source/fuzz/transformation_replace_load_store_with_copy_memory.h b/source/fuzz/transformation_replace_load_store_with_copy_memory.h index 4dd728e7..bb4d27ef 100644 --- a/source/fuzz/transformation_replace_load_store_with_copy_memory.h +++ b/source/fuzz/transformation_replace_load_store_with_copy_memory.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationReplaceLoadStoreWithCopyMemory : public Transformation { public: explicit TransformationReplaceLoadStoreWithCopyMemory( - const protobufs::TransformationReplaceLoadStoreWithCopyMemory& message); + protobufs::TransformationReplaceLoadStoreWithCopyMemory message); TransformationReplaceLoadStoreWithCopyMemory( const protobufs::InstructionDescriptor& load_instruction_descriptor, diff --git a/source/fuzz/transformation_replace_opphi_id_from_dead_predecessor.cpp b/source/fuzz/transformation_replace_opphi_id_from_dead_predecessor.cpp index f13af7e7..84ca1aba 100644 --- a/source/fuzz/transformation_replace_opphi_id_from_dead_predecessor.cpp +++ b/source/fuzz/transformation_replace_opphi_id_from_dead_predecessor.cpp @@ -21,9 +21,8 @@ namespace fuzz { TransformationReplaceOpPhiIdFromDeadPredecessor:: TransformationReplaceOpPhiIdFromDeadPredecessor( - const protobufs::TransformationReplaceOpPhiIdFromDeadPredecessor& - message) - : message_(message) {} + protobufs::TransformationReplaceOpPhiIdFromDeadPredecessor message) + : message_(std::move(message)) {} TransformationReplaceOpPhiIdFromDeadPredecessor:: TransformationReplaceOpPhiIdFromDeadPredecessor(uint32_t opphi_id, diff --git a/source/fuzz/transformation_replace_opphi_id_from_dead_predecessor.h b/source/fuzz/transformation_replace_opphi_id_from_dead_predecessor.h index d26b6b0a..87ce8ad1 100644 --- a/source/fuzz/transformation_replace_opphi_id_from_dead_predecessor.h +++ b/source/fuzz/transformation_replace_opphi_id_from_dead_predecessor.h @@ -23,8 +23,7 @@ namespace fuzz { class TransformationReplaceOpPhiIdFromDeadPredecessor : public Transformation { public: explicit TransformationReplaceOpPhiIdFromDeadPredecessor( - const protobufs::TransformationReplaceOpPhiIdFromDeadPredecessor& - message); + protobufs::TransformationReplaceOpPhiIdFromDeadPredecessor message); TransformationReplaceOpPhiIdFromDeadPredecessor(uint32_t opphi_id, uint32_t pred_label_id, diff --git a/source/fuzz/transformation_replace_opselect_with_conditional_branch.cpp b/source/fuzz/transformation_replace_opselect_with_conditional_branch.cpp index 7160d4d5..c0e6e449 100644 --- a/source/fuzz/transformation_replace_opselect_with_conditional_branch.cpp +++ b/source/fuzz/transformation_replace_opselect_with_conditional_branch.cpp @@ -20,9 +20,8 @@ namespace spvtools { namespace fuzz { TransformationReplaceOpSelectWithConditionalBranch:: TransformationReplaceOpSelectWithConditionalBranch( - const spvtools::fuzz::protobufs:: - TransformationReplaceOpSelectWithConditionalBranch& message) - : message_(message) {} + protobufs::TransformationReplaceOpSelectWithConditionalBranch message) + : message_(std::move(message)) {} TransformationReplaceOpSelectWithConditionalBranch:: TransformationReplaceOpSelectWithConditionalBranch( diff --git a/source/fuzz/transformation_replace_opselect_with_conditional_branch.h b/source/fuzz/transformation_replace_opselect_with_conditional_branch.h index 8ee5c7f1..ec926c65 100644 --- a/source/fuzz/transformation_replace_opselect_with_conditional_branch.h +++ b/source/fuzz/transformation_replace_opselect_with_conditional_branch.h @@ -24,8 +24,7 @@ class TransformationReplaceOpSelectWithConditionalBranch : public Transformation { public: explicit TransformationReplaceOpSelectWithConditionalBranch( - const protobufs::TransformationReplaceOpSelectWithConditionalBranch& - message); + protobufs::TransformationReplaceOpSelectWithConditionalBranch message); TransformationReplaceOpSelectWithConditionalBranch(uint32_t select_id, uint32_t true_block_id, diff --git a/source/fuzz/transformation_replace_parameter_with_global.cpp b/source/fuzz/transformation_replace_parameter_with_global.cpp index cdf7645f..caf67168 100644 --- a/source/fuzz/transformation_replace_parameter_with_global.cpp +++ b/source/fuzz/transformation_replace_parameter_with_global.cpp @@ -23,8 +23,8 @@ namespace fuzz { TransformationReplaceParameterWithGlobal:: TransformationReplaceParameterWithGlobal( - const protobufs::TransformationReplaceParameterWithGlobal& message) - : message_(message) {} + protobufs::TransformationReplaceParameterWithGlobal message) + : message_(std::move(message)) {} TransformationReplaceParameterWithGlobal:: TransformationReplaceParameterWithGlobal( diff --git a/source/fuzz/transformation_replace_parameter_with_global.h b/source/fuzz/transformation_replace_parameter_with_global.h index c2d5f8ff..38a9c17f 100644 --- a/source/fuzz/transformation_replace_parameter_with_global.h +++ b/source/fuzz/transformation_replace_parameter_with_global.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationReplaceParameterWithGlobal : public Transformation { public: explicit TransformationReplaceParameterWithGlobal( - const protobufs::TransformationReplaceParameterWithGlobal& message); + protobufs::TransformationReplaceParameterWithGlobal message); TransformationReplaceParameterWithGlobal(uint32_t function_type_fresh_id, uint32_t parameter_id, diff --git a/source/fuzz/transformation_replace_params_with_struct.cpp b/source/fuzz/transformation_replace_params_with_struct.cpp index 0a135e56..13eeccb4 100644 --- a/source/fuzz/transformation_replace_params_with_struct.cpp +++ b/source/fuzz/transformation_replace_params_with_struct.cpp @@ -22,8 +22,8 @@ namespace spvtools { namespace fuzz { TransformationReplaceParamsWithStruct::TransformationReplaceParamsWithStruct( - const protobufs::TransformationReplaceParamsWithStruct& message) - : message_(message) {} + protobufs::TransformationReplaceParamsWithStruct message) + : message_(std::move(message)) {} TransformationReplaceParamsWithStruct::TransformationReplaceParamsWithStruct( const std::vector<uint32_t>& parameter_id, uint32_t fresh_function_type_id, diff --git a/source/fuzz/transformation_replace_params_with_struct.h b/source/fuzz/transformation_replace_params_with_struct.h index afa6b14f..705f3405 100644 --- a/source/fuzz/transformation_replace_params_with_struct.h +++ b/source/fuzz/transformation_replace_params_with_struct.h @@ -28,7 +28,7 @@ namespace fuzz { class TransformationReplaceParamsWithStruct : public Transformation { public: explicit TransformationReplaceParamsWithStruct( - const protobufs::TransformationReplaceParamsWithStruct& message); + protobufs::TransformationReplaceParamsWithStruct message); TransformationReplaceParamsWithStruct( const std::vector<uint32_t>& parameter_id, diff --git a/source/fuzz/transformation_set_function_control.cpp b/source/fuzz/transformation_set_function_control.cpp index 8ab9b8cb..02a8c9fe 100644 --- a/source/fuzz/transformation_set_function_control.cpp +++ b/source/fuzz/transformation_set_function_control.cpp @@ -18,8 +18,8 @@ namespace spvtools { namespace fuzz { TransformationSetFunctionControl::TransformationSetFunctionControl( - const spvtools::fuzz::protobufs::TransformationSetFunctionControl& message) - : message_(message) {} + protobufs::TransformationSetFunctionControl message) + : message_(std::move(message)) {} TransformationSetFunctionControl::TransformationSetFunctionControl( uint32_t function_id, uint32_t function_control) { diff --git a/source/fuzz/transformation_set_function_control.h b/source/fuzz/transformation_set_function_control.h index 2952cc6d..2e16e1ca 100644 --- a/source/fuzz/transformation_set_function_control.h +++ b/source/fuzz/transformation_set_function_control.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationSetFunctionControl : public Transformation { public: explicit TransformationSetFunctionControl( - const protobufs::TransformationSetFunctionControl& message); + protobufs::TransformationSetFunctionControl message); TransformationSetFunctionControl(uint32_t function_id, uint32_t function_control); diff --git a/source/fuzz/transformation_set_loop_control.cpp b/source/fuzz/transformation_set_loop_control.cpp index b2180d8a..14499606 100644 --- a/source/fuzz/transformation_set_loop_control.cpp +++ b/source/fuzz/transformation_set_loop_control.cpp @@ -18,8 +18,8 @@ namespace spvtools { namespace fuzz { TransformationSetLoopControl::TransformationSetLoopControl( - const spvtools::fuzz::protobufs::TransformationSetLoopControl& message) - : message_(message) {} + protobufs::TransformationSetLoopControl message) + : message_(std::move(message)) {} TransformationSetLoopControl::TransformationSetLoopControl( uint32_t block_id, uint32_t loop_control, uint32_t peel_count, @@ -77,12 +77,14 @@ bool TransformationSetLoopControl::IsApplicable( } } - if ((message_.loop_control() & - (SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask)) && - !(PeelCountIsSupported(ir_context) && - PartialCountIsSupported(ir_context))) { - // At least one of PeelCount or PartialCount is used, but the SPIR-V version - // in question does not support these loop controls. + // Check that PeelCount and PartialCount are supported if used. + if ((message_.loop_control() & SpvLoopControlPeelCountMask) && + !PeelCountIsSupported(ir_context)) { + return false; + } + + if ((message_.loop_control() & SpvLoopControlPartialCountMask) && + !PartialCountIsSupported(ir_context)) { return false; } @@ -183,14 +185,16 @@ bool TransformationSetLoopControl::LoopControlBitIsAddedByTransformation( bool TransformationSetLoopControl::PartialCountIsSupported( opt::IRContext* ir_context) { - // TODO(afd): We capture the universal environments for which this loop - // control is definitely not supported. The check should be refined on - // demand for other target environments. + // TODO(afd): We capture the environments for which this loop control is + // definitely not supported. The check should be refined on demand for other + // target environments. switch (ir_context->grammar().target_env()) { case SPV_ENV_UNIVERSAL_1_0: case SPV_ENV_UNIVERSAL_1_1: case SPV_ENV_UNIVERSAL_1_2: case SPV_ENV_UNIVERSAL_1_3: + case SPV_ENV_VULKAN_1_0: + case SPV_ENV_VULKAN_1_1: return false; default: return true; @@ -199,14 +203,16 @@ bool TransformationSetLoopControl::PartialCountIsSupported( bool TransformationSetLoopControl::PeelCountIsSupported( opt::IRContext* ir_context) { - // TODO(afd): We capture the universal environments for which this loop - // control is definitely not supported. The check should be refined on - // demand for other target environments. + // TODO(afd): We capture the environments for which this loop control is + // definitely not supported. The check should be refined on demand for other + // target environments. switch (ir_context->grammar().target_env()) { case SPV_ENV_UNIVERSAL_1_0: case SPV_ENV_UNIVERSAL_1_1: case SPV_ENV_UNIVERSAL_1_2: case SPV_ENV_UNIVERSAL_1_3: + case SPV_ENV_VULKAN_1_0: + case SPV_ENV_VULKAN_1_1: return false; default: return true; diff --git a/source/fuzz/transformation_set_loop_control.h b/source/fuzz/transformation_set_loop_control.h index c3480b19..bc17c8a4 100644 --- a/source/fuzz/transformation_set_loop_control.h +++ b/source/fuzz/transformation_set_loop_control.h @@ -29,7 +29,7 @@ class TransformationSetLoopControl : public Transformation { const static uint32_t kLoopControlFirstLiteralInOperandIndex = 3; explicit TransformationSetLoopControl( - const protobufs::TransformationSetLoopControl& message); + protobufs::TransformationSetLoopControl message); TransformationSetLoopControl(uint32_t block_id, uint32_t loop_control, uint32_t peel_count, uint32_t partial_count); diff --git a/source/fuzz/transformation_set_memory_operands_mask.cpp b/source/fuzz/transformation_set_memory_operands_mask.cpp index deb207ae..5a986ad2 100644 --- a/source/fuzz/transformation_set_memory_operands_mask.cpp +++ b/source/fuzz/transformation_set_memory_operands_mask.cpp @@ -29,9 +29,8 @@ const uint32_t kOpCopyMemorySizedFirstMemoryOperandsMaskIndex = 3; } // namespace TransformationSetMemoryOperandsMask::TransformationSetMemoryOperandsMask( - const spvtools::fuzz::protobufs::TransformationSetMemoryOperandsMask& - message) - : message_(message) {} + protobufs::TransformationSetMemoryOperandsMask message) + : message_(std::move(message)) {} TransformationSetMemoryOperandsMask::TransformationSetMemoryOperandsMask( const protobufs::InstructionDescriptor& memory_access_instruction, @@ -53,7 +52,9 @@ bool TransformationSetMemoryOperandsMask::IsApplicable( SpvOpCopyMemory || message_.memory_access_instruction().target_instruction_opcode() == SpvOpCopyMemorySized); - assert(MultipleMemoryOperandMasksAreSupported(ir_context)); + assert(MultipleMemoryOperandMasksAreSupported(ir_context) && + "Multiple memory operand masks are not supported for this SPIR-V " + "version."); } auto instruction = @@ -205,14 +206,16 @@ uint32_t TransformationSetMemoryOperandsMask::GetInOperandIndexForMask( bool TransformationSetMemoryOperandsMask:: MultipleMemoryOperandMasksAreSupported(opt::IRContext* ir_context) { - // TODO(afd): We capture the universal environments for which this loop - // control is definitely not supported. The check should be refined on - // demand for other target environments. + // TODO(afd): We capture the environments for which this loop control is + // definitely not supported. The check should be refined on demand for other + // target environments. switch (ir_context->grammar().target_env()) { case SPV_ENV_UNIVERSAL_1_0: case SPV_ENV_UNIVERSAL_1_1: case SPV_ENV_UNIVERSAL_1_2: case SPV_ENV_UNIVERSAL_1_3: + case SPV_ENV_VULKAN_1_0: + case SPV_ENV_VULKAN_1_1: return false; default: return true; diff --git a/source/fuzz/transformation_set_memory_operands_mask.h b/source/fuzz/transformation_set_memory_operands_mask.h index 7357b1ad..c52fbdba 100644 --- a/source/fuzz/transformation_set_memory_operands_mask.h +++ b/source/fuzz/transformation_set_memory_operands_mask.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationSetMemoryOperandsMask : public Transformation { public: explicit TransformationSetMemoryOperandsMask( - const protobufs::TransformationSetMemoryOperandsMask& message); + protobufs::TransformationSetMemoryOperandsMask message); TransformationSetMemoryOperandsMask( const protobufs::InstructionDescriptor& memory_access_instruction, diff --git a/source/fuzz/transformation_set_selection_control.cpp b/source/fuzz/transformation_set_selection_control.cpp index 625187ea..6dddbdf8 100644 --- a/source/fuzz/transformation_set_selection_control.cpp +++ b/source/fuzz/transformation_set_selection_control.cpp @@ -18,8 +18,8 @@ namespace spvtools { namespace fuzz { TransformationSetSelectionControl::TransformationSetSelectionControl( - const spvtools::fuzz::protobufs::TransformationSetSelectionControl& message) - : message_(message) {} + protobufs::TransformationSetSelectionControl message) + : message_(std::move(message)) {} TransformationSetSelectionControl::TransformationSetSelectionControl( uint32_t block_id, uint32_t selection_control) { diff --git a/source/fuzz/transformation_set_selection_control.h b/source/fuzz/transformation_set_selection_control.h index 56b58852..93b19049 100644 --- a/source/fuzz/transformation_set_selection_control.h +++ b/source/fuzz/transformation_set_selection_control.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationSetSelectionControl : public Transformation { public: explicit TransformationSetSelectionControl( - const protobufs::TransformationSetSelectionControl& message); + protobufs::TransformationSetSelectionControl message); TransformationSetSelectionControl(uint32_t block_id, uint32_t selection_control); diff --git a/source/fuzz/transformation_split_block.cpp b/source/fuzz/transformation_split_block.cpp index b383c405..e15dffa3 100644 --- a/source/fuzz/transformation_split_block.cpp +++ b/source/fuzz/transformation_split_block.cpp @@ -24,8 +24,8 @@ namespace spvtools { namespace fuzz { TransformationSplitBlock::TransformationSplitBlock( - const spvtools::fuzz::protobufs::TransformationSplitBlock& message) - : message_(message) {} + protobufs::TransformationSplitBlock message) + : message_(std::move(message)) {} TransformationSplitBlock::TransformationSplitBlock( const protobufs::InstructionDescriptor& instruction_to_split_before, @@ -109,24 +109,37 @@ void TransformationSplitBlock::Apply( split_before); // The split does not automatically add a branch between the two parts of // the original block, so we add one. - block_to_split->AddInstruction(MakeUnique<opt::Instruction>( + auto branch_instruction = MakeUnique<opt::Instruction>( ir_context, SpvOpBranch, 0, 0, std::initializer_list<opt::Operand>{opt::Operand( - spv_operand_type_t::SPV_OPERAND_TYPE_ID, {message_.fresh_id()})})); + spv_operand_type_t::SPV_OPERAND_TYPE_ID, {message_.fresh_id()})}); + auto branch_instruction_ptr = branch_instruction.get(); + block_to_split->AddInstruction(std::move(branch_instruction)); + + // Inform the def-use manager about the branch instruction, and record its + // block. + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(branch_instruction_ptr); + ir_context->set_instr_block(branch_instruction_ptr, block_to_split); + // If we split before OpPhi instructions, we need to update their // predecessor operand so that the block they used to be inside is now the // predecessor. - new_bb->ForEachPhiInst([block_to_split](opt::Instruction* phi_inst) { + new_bb->ForEachPhiInst([block_to_split, + ir_context](opt::Instruction* phi_inst) { assert( phi_inst->NumInOperands() == 2 && "Precondition: a block can only be split before an OpPhi if the block" "has exactly one predecessor."); phi_inst->SetInOperand(1, {block_to_split->id()}); + ir_context->UpdateDefUse(phi_inst); }); - // Invalidate all analyses + // We have updated the def-use manager and the instruction to block mapping, + // but other analyses (especially control flow-related ones) need to be + // recomputed. ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + opt::IRContext::Analysis::kAnalysisDefUse | + opt::IRContext::Analysis::kAnalysisInstrToBlockMapping); // If the block being split was dead, the new block arising from the split is // also dead. diff --git a/source/fuzz/transformation_split_block.h b/source/fuzz/transformation_split_block.h index 27bf6f8c..ace77b5b 100644 --- a/source/fuzz/transformation_split_block.h +++ b/source/fuzz/transformation_split_block.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationSplitBlock : public Transformation { public: explicit TransformationSplitBlock( - const protobufs::TransformationSplitBlock& message); + protobufs::TransformationSplitBlock message); TransformationSplitBlock( const protobufs::InstructionDescriptor& instruction_to_split_before, diff --git a/source/fuzz/transformation_store.cpp b/source/fuzz/transformation_store.cpp index 460ca016..f8c6d013 100644 --- a/source/fuzz/transformation_store.cpp +++ b/source/fuzz/transformation_store.cpp @@ -20,9 +20,8 @@ namespace spvtools { namespace fuzz { -TransformationStore::TransformationStore( - const spvtools::fuzz::protobufs::TransformationStore& message) - : message_(message) {} +TransformationStore::TransformationStore(protobufs::TransformationStore message) + : message_(std::move(message)) {} TransformationStore::TransformationStore( uint32_t pointer_id, uint32_t value_id, @@ -110,13 +109,20 @@ bool TransformationStore::IsApplicable( void TransformationStore::Apply(opt::IRContext* ir_context, TransformationContext* /*unused*/) const { - FindInstruction(message_.instruction_to_insert_before(), ir_context) - ->InsertBefore(MakeUnique<opt::Instruction>( - ir_context, SpvOpStore, 0, 0, - opt::Instruction::OperandList( - {{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}, - {SPV_OPERAND_TYPE_ID, {message_.value_id()}}}))); - ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); + auto insert_before = + FindInstruction(message_.instruction_to_insert_before(), ir_context); + auto new_instruction = MakeUnique<opt::Instruction>( + ir_context, SpvOpStore, 0, 0, + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}, + {SPV_OPERAND_TYPE_ID, {message_.value_id()}}})); + auto new_instruction_ptr = new_instruction.get(); + insert_before->InsertBefore(std::move(new_instruction)); + // Inform the def-use manager about the new instruction and record its basic + // block. + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr); + ir_context->set_instr_block(new_instruction_ptr, + ir_context->get_instr_block(insert_before)); } protobufs::Transformation TransformationStore::ToMessage() const { diff --git a/source/fuzz/transformation_store.h b/source/fuzz/transformation_store.h index 70520489..18ba1d7d 100644 --- a/source/fuzz/transformation_store.h +++ b/source/fuzz/transformation_store.h @@ -25,7 +25,7 @@ namespace fuzz { class TransformationStore : public Transformation { public: - explicit TransformationStore(const protobufs::TransformationStore& message); + explicit TransformationStore(protobufs::TransformationStore message); TransformationStore( uint32_t pointer_id, uint32_t value_id, diff --git a/source/fuzz/transformation_swap_commutable_operands.cpp b/source/fuzz/transformation_swap_commutable_operands.cpp index b8bdb790..a02e95a0 100644 --- a/source/fuzz/transformation_swap_commutable_operands.cpp +++ b/source/fuzz/transformation_swap_commutable_operands.cpp @@ -21,9 +21,8 @@ namespace spvtools { namespace fuzz { TransformationSwapCommutableOperands::TransformationSwapCommutableOperands( - const spvtools::fuzz::protobufs::TransformationSwapCommutableOperands& - message) - : message_(message) {} + protobufs::TransformationSwapCommutableOperands message) + : message_(std::move(message)) {} TransformationSwapCommutableOperands::TransformationSwapCommutableOperands( const protobufs::InstructionDescriptor& instruction_descriptor) { diff --git a/source/fuzz/transformation_swap_commutable_operands.h b/source/fuzz/transformation_swap_commutable_operands.h index c291c3ea..5e211f19 100644 --- a/source/fuzz/transformation_swap_commutable_operands.h +++ b/source/fuzz/transformation_swap_commutable_operands.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationSwapCommutableOperands : public Transformation { public: explicit TransformationSwapCommutableOperands( - const protobufs::TransformationSwapCommutableOperands& message); + protobufs::TransformationSwapCommutableOperands message); TransformationSwapCommutableOperands( const protobufs::InstructionDescriptor& instruction_descriptor); diff --git a/source/fuzz/transformation_swap_conditional_branch_operands.cpp b/source/fuzz/transformation_swap_conditional_branch_operands.cpp index 866fee66..340836d1 100644 --- a/source/fuzz/transformation_swap_conditional_branch_operands.cpp +++ b/source/fuzz/transformation_swap_conditional_branch_operands.cpp @@ -22,9 +22,8 @@ namespace fuzz { TransformationSwapConditionalBranchOperands:: TransformationSwapConditionalBranchOperands( - const spvtools::fuzz::protobufs:: - TransformationSwapConditionalBranchOperands& message) - : message_(message) {} + protobufs::TransformationSwapConditionalBranchOperands message) + : message_(std::move(message)) {} TransformationSwapConditionalBranchOperands:: TransformationSwapConditionalBranchOperands( @@ -70,11 +69,13 @@ void TransformationSwapConditionalBranchOperands::Apply( // We are swapping the labels in OpBranchConditional. This means that we must // invert the guard as well. We are using OpLogicalNot for that purpose here. - iter.InsertBefore(MakeUnique<opt::Instruction>( + auto new_instruction = MakeUnique<opt::Instruction>( ir_context, SpvOpLogicalNot, condition_inst->type_id(), message_.fresh_id(), opt::Instruction::OperandList{ - {SPV_OPERAND_TYPE_ID, {condition_inst->result_id()}}})); + {SPV_OPERAND_TYPE_ID, {condition_inst->result_id()}}}); + auto new_instruction_ptr = new_instruction.get(); + iter.InsertBefore(std::move(new_instruction)); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); @@ -89,9 +90,13 @@ void TransformationSwapConditionalBranchOperands::Apply( std::swap(branch_inst->GetInOperand(3), branch_inst->GetInOperand(4)); } - // Make sure the changes are analyzed. - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr); + ir_context->set_instr_block(new_instruction_ptr, block); + ir_context->get_def_use_mgr()->EraseUseRecordsOfOperandIds(branch_inst); + ir_context->get_def_use_mgr()->AnalyzeInstUse(branch_inst); + + // No analyses need to be invalidated since the transformation is local to a + // block and the def-use and instruction-to-block mappings have been updated. } protobufs::Transformation diff --git a/source/fuzz/transformation_swap_conditional_branch_operands.h b/source/fuzz/transformation_swap_conditional_branch_operands.h index 022c54a7..165ab806 100644 --- a/source/fuzz/transformation_swap_conditional_branch_operands.h +++ b/source/fuzz/transformation_swap_conditional_branch_operands.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationSwapConditionalBranchOperands : public Transformation { public: explicit TransformationSwapConditionalBranchOperands( - const protobufs::TransformationSwapConditionalBranchOperands& message); + protobufs::TransformationSwapConditionalBranchOperands message); TransformationSwapConditionalBranchOperands( const protobufs::InstructionDescriptor& instruction_descriptor, diff --git a/source/fuzz/transformation_toggle_access_chain_instruction.cpp b/source/fuzz/transformation_toggle_access_chain_instruction.cpp index 1952a343..34523fe8 100644 --- a/source/fuzz/transformation_toggle_access_chain_instruction.cpp +++ b/source/fuzz/transformation_toggle_access_chain_instruction.cpp @@ -22,9 +22,8 @@ namespace fuzz { TransformationToggleAccessChainInstruction:: TransformationToggleAccessChainInstruction( - const spvtools::fuzz::protobufs:: - TransformationToggleAccessChainInstruction& message) - : message_(message) {} + protobufs::TransformationToggleAccessChainInstruction message) + : message_(std::move(message)) {} TransformationToggleAccessChainInstruction:: TransformationToggleAccessChainInstruction( diff --git a/source/fuzz/transformation_toggle_access_chain_instruction.h b/source/fuzz/transformation_toggle_access_chain_instruction.h index 977b0d7a..be2718b0 100644 --- a/source/fuzz/transformation_toggle_access_chain_instruction.h +++ b/source/fuzz/transformation_toggle_access_chain_instruction.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationToggleAccessChainInstruction : public Transformation { public: explicit TransformationToggleAccessChainInstruction( - const protobufs::TransformationToggleAccessChainInstruction& message); + protobufs::TransformationToggleAccessChainInstruction message); TransformationToggleAccessChainInstruction( const protobufs::InstructionDescriptor& instruction_descriptor); diff --git a/source/fuzz/transformation_vector_shuffle.cpp b/source/fuzz/transformation_vector_shuffle.cpp index 05af18e6..ac0e3ccb 100644 --- a/source/fuzz/transformation_vector_shuffle.cpp +++ b/source/fuzz/transformation_vector_shuffle.cpp @@ -21,8 +21,8 @@ namespace spvtools { namespace fuzz { TransformationVectorShuffle::TransformationVectorShuffle( - const spvtools::fuzz::protobufs::TransformationVectorShuffle& message) - : message_(message) {} + protobufs::TransformationVectorShuffle message) + : message_(std::move(message)) {} TransformationVectorShuffle::TransformationVectorShuffle( const protobufs::InstructionDescriptor& instruction_to_insert_before, @@ -130,13 +130,18 @@ void TransformationVectorShuffle::Apply( // Add a shuffle instruction right before the instruction identified by // |message_.instruction_to_insert_before|. - FindInstruction(message_.instruction_to_insert_before(), ir_context) - ->InsertBefore(MakeUnique<opt::Instruction>( + auto insert_before = + FindInstruction(message_.instruction_to_insert_before(), ir_context); + opt::Instruction* new_instruction = + insert_before->InsertBefore(MakeUnique<opt::Instruction>( ir_context, SpvOpVectorShuffle, result_type_id, message_.fresh_id(), shuffle_operands)); fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id()); - ir_context->InvalidateAnalysesExceptFor( - opt::IRContext::Analysis::kAnalysisNone); + // Inform the def-use manager about the new instruction and record its basic + // block. + ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction); + ir_context->set_instr_block(new_instruction, + ir_context->get_instr_block(insert_before)); AddDataSynonymFacts(ir_context, transformation_context); } diff --git a/source/fuzz/transformation_vector_shuffle.h b/source/fuzz/transformation_vector_shuffle.h index cf08a62c..7360906f 100644 --- a/source/fuzz/transformation_vector_shuffle.h +++ b/source/fuzz/transformation_vector_shuffle.h @@ -27,7 +27,7 @@ namespace fuzz { class TransformationVectorShuffle : public Transformation { public: explicit TransformationVectorShuffle( - const protobufs::TransformationVectorShuffle& message); + protobufs::TransformationVectorShuffle message); TransformationVectorShuffle( const protobufs::InstructionDescriptor& instruction_to_insert_before, diff --git a/source/fuzz/transformation_wrap_early_terminator_in_function.cpp b/source/fuzz/transformation_wrap_early_terminator_in_function.cpp index 4c436f5e..468d809f 100644 --- a/source/fuzz/transformation_wrap_early_terminator_in_function.cpp +++ b/source/fuzz/transformation_wrap_early_terminator_in_function.cpp @@ -23,9 +23,8 @@ namespace fuzz { TransformationWrapEarlyTerminatorInFunction:: TransformationWrapEarlyTerminatorInFunction( - const spvtools::fuzz::protobufs:: - TransformationWrapEarlyTerminatorInFunction& message) - : message_(message) {} + protobufs::TransformationWrapEarlyTerminatorInFunction message) + : message_(std::move(message)) {} TransformationWrapEarlyTerminatorInFunction:: TransformationWrapEarlyTerminatorInFunction( diff --git a/source/fuzz/transformation_wrap_early_terminator_in_function.h b/source/fuzz/transformation_wrap_early_terminator_in_function.h index 00151d40..d6e55517 100644 --- a/source/fuzz/transformation_wrap_early_terminator_in_function.h +++ b/source/fuzz/transformation_wrap_early_terminator_in_function.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationWrapEarlyTerminatorInFunction : public Transformation { public: explicit TransformationWrapEarlyTerminatorInFunction( - const protobufs::TransformationWrapEarlyTerminatorInFunction& message); + protobufs::TransformationWrapEarlyTerminatorInFunction message); TransformationWrapEarlyTerminatorInFunction( uint32_t fresh_id, diff --git a/source/fuzz/transformation_wrap_region_in_selection.cpp b/source/fuzz/transformation_wrap_region_in_selection.cpp index 9924e368..01c98cca 100644 --- a/source/fuzz/transformation_wrap_region_in_selection.cpp +++ b/source/fuzz/transformation_wrap_region_in_selection.cpp @@ -20,8 +20,8 @@ namespace spvtools { namespace fuzz { TransformationWrapRegionInSelection::TransformationWrapRegionInSelection( - const protobufs::TransformationWrapRegionInSelection& message) - : message_(message) {} + protobufs::TransformationWrapRegionInSelection message) + : message_(std::move(message)) {} TransformationWrapRegionInSelection::TransformationWrapRegionInSelection( uint32_t region_entry_block_id, uint32_t region_exit_block_id, diff --git a/source/fuzz/transformation_wrap_region_in_selection.h b/source/fuzz/transformation_wrap_region_in_selection.h index 57f4f64f..66d16dad 100644 --- a/source/fuzz/transformation_wrap_region_in_selection.h +++ b/source/fuzz/transformation_wrap_region_in_selection.h @@ -26,7 +26,7 @@ namespace fuzz { class TransformationWrapRegionInSelection : public Transformation { public: explicit TransformationWrapRegionInSelection( - const protobufs::TransformationWrapRegionInSelection& message); + protobufs::TransformationWrapRegionInSelection message); TransformationWrapRegionInSelection(uint32_t region_entry_block_id, uint32_t region_exit_block_id, diff --git a/source/opcode.cpp b/source/opcode.cpp index d87e8287..c96cde8d 100644 --- a/source/opcode.cpp +++ b/source/opcode.cpp @@ -417,8 +417,10 @@ bool spvOpcodeIsAtomicWithLoad(const SpvOp opcode) { case SpvOpAtomicISub: case SpvOpAtomicSMin: case SpvOpAtomicUMin: + case SpvOpAtomicFMinEXT: case SpvOpAtomicSMax: case SpvOpAtomicUMax: + case SpvOpAtomicFMaxEXT: case SpvOpAtomicAnd: case SpvOpAtomicOr: case SpvOpAtomicXor: diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt index 14a6bee7..88d56589 100644 --- a/source/opt/CMakeLists.txt +++ b/source/opt/CMakeLists.txt @@ -62,6 +62,7 @@ set(SPIRV_TOOLS_OPT_SOURCES instruction.h instruction_list.h instrument_pass.h + interp_fixup_pass.h ir_builder.h ir_context.h ir_loader.h @@ -165,6 +166,7 @@ set(SPIRV_TOOLS_OPT_SOURCES instruction.cpp instruction_list.cpp instrument_pass.cpp + interp_fixup_pass.cpp ir_context.cpp ir_loader.cpp licm_pass.cpp diff --git a/source/opt/code_sink.cpp b/source/opt/code_sink.cpp index e49029fe..cd777974 100644 --- a/source/opt/code_sink.cpp +++ b/source/opt/code_sink.cpp @@ -218,8 +218,10 @@ bool CodeSinkingPass::HasUniformMemorySync() { case SpvOpAtomicISub: case SpvOpAtomicSMin: case SpvOpAtomicUMin: + case SpvOpAtomicFMinEXT: case SpvOpAtomicSMax: case SpvOpAtomicUMax: + case SpvOpAtomicFMaxEXT: case SpvOpAtomicAnd: case SpvOpAtomicOr: case SpvOpAtomicXor: diff --git a/source/opt/constants.h b/source/opt/constants.h index e17ae6b6..5bd0ae32 100644 --- a/source/opt/constants.h +++ b/source/opt/constants.h @@ -58,7 +58,7 @@ class ConstantManager; class Constant { public: Constant() = delete; - virtual ~Constant() {} + virtual ~Constant() = default; // Make a deep copy of this constant. virtual std::unique_ptr<Constant> Copy() const = 0; diff --git a/source/opt/folding_rules.cpp b/source/opt/folding_rules.cpp index 010eec9c..1e7c424b 100644 --- a/source/opt/folding_rules.cpp +++ b/source/opt/folding_rules.cpp @@ -470,7 +470,7 @@ uint32_t PerformFloatingPointOperation(analysis::ConstantManager* const_mgr, float fval = val.getAsFloat(); \ if (!IsValidResult(fval)) return 0; \ words = val.GetWords(); \ - } + } static_assert(true, "require extra semicolon") switch (opcode) { case SpvOpFMul: FOLD_OP(*); @@ -522,7 +522,7 @@ uint32_t PerformIntegerOperation(analysis::ConstantManager* const_mgr, uint32_t val = input1->GetU32() op input2->GetU32(); \ words.push_back(val); \ } \ - } + } static_assert(true, "require extra semicalon") switch (opcode) { case SpvOpIMul: FOLD_OP(*); diff --git a/source/opt/inline_pass.h b/source/opt/inline_pass.h index abe773af..9a5429ba 100644 --- a/source/opt/inline_pass.h +++ b/source/opt/inline_pass.h @@ -37,7 +37,7 @@ class InlinePass : public Pass { using cbb_ptr = const BasicBlock*; public: - virtual ~InlinePass() = default; + virtual ~InlinePass() override = default; protected: InlinePass(); diff --git a/source/opt/interp_fixup_pass.cpp b/source/opt/interp_fixup_pass.cpp new file mode 100644 index 00000000..ad29e6a7 --- /dev/null +++ b/source/opt/interp_fixup_pass.cpp @@ -0,0 +1,131 @@ +// Copyright (c) 2021 The Khronos Group Inc. +// Copyright (c) 2021 Valve Corporation +// Copyright (c) 2021 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/interp_fixup_pass.h" + +#include <set> +#include <string> + +#include "ir_builder.h" +#include "source/opt/ir_context.h" +#include "type_manager.h" + +namespace spvtools { +namespace opt { + +namespace { + +// Input Operand Indices +static const int kSpvVariableStorageClassInIdx = 0; + +// Avoid unused variable warning/error on Linux +#ifndef NDEBUG +#define USE_ASSERT(x) assert(x) +#else +#define USE_ASSERT(x) ((void)(x)) +#endif + +// Folding rule function which attempts to replace |op(OpLoad(a),...)| +// by |op(a,...)|, where |op| is one of the GLSLstd450 InterpolateAt* +// instructions. Returns true if replaced, false otherwise. +bool ReplaceInternalInterpolate(IRContext* ctx, Instruction* inst, + const std::vector<const analysis::Constant*>&) { + uint32_t glsl450_ext_inst_id = + ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); + assert(glsl450_ext_inst_id != 0); + + uint32_t ext_opcode = inst->GetSingleWordInOperand(1); + + uint32_t op1_id = inst->GetSingleWordInOperand(2); + + Instruction* load_inst = ctx->get_def_use_mgr()->GetDef(op1_id); + if (load_inst->opcode() != SpvOpLoad) return false; + + Instruction* base_inst = load_inst->GetBaseAddress(); + USE_ASSERT(base_inst->opcode() == SpvOpVariable && + base_inst->GetSingleWordInOperand(kSpvVariableStorageClassInIdx) == + SpvStorageClassInput && + "unexpected interpolant in InterpolateAt*"); + + uint32_t ptr_id = load_inst->GetSingleWordInOperand(0); + uint32_t op2_id = (ext_opcode != GLSLstd450InterpolateAtCentroid) + ? inst->GetSingleWordInOperand(3) + : 0; + + Instruction::OperandList new_operands; + new_operands.push_back({SPV_OPERAND_TYPE_ID, {glsl450_ext_inst_id}}); + new_operands.push_back( + {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, {ext_opcode}}); + new_operands.push_back({SPV_OPERAND_TYPE_ID, {ptr_id}}); + if (op2_id != 0) new_operands.push_back({SPV_OPERAND_TYPE_ID, {op2_id}}); + + inst->SetInOperands(std::move(new_operands)); + ctx->UpdateDefUse(inst); + return true; +} + +class InterpFoldingRules : public FoldingRules { + public: + explicit InterpFoldingRules(IRContext* ctx) : FoldingRules(ctx) {} + + protected: + virtual void AddFoldingRules() override { + uint32_t extension_id = + context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); + + if (extension_id != 0) { + ext_rules_[{extension_id, GLSLstd450InterpolateAtCentroid}].push_back( + ReplaceInternalInterpolate); + ext_rules_[{extension_id, GLSLstd450InterpolateAtSample}].push_back( + ReplaceInternalInterpolate); + ext_rules_[{extension_id, GLSLstd450InterpolateAtOffset}].push_back( + ReplaceInternalInterpolate); + } + } +}; + +class InterpConstFoldingRules : public ConstantFoldingRules { + public: + InterpConstFoldingRules(IRContext* ctx) : ConstantFoldingRules(ctx) {} + + protected: + virtual void AddFoldingRules() override {} +}; + +} // namespace + +Pass::Status InterpFixupPass::Process() { + bool changed = false; + + // Traverse the body of the functions to replace instructions that require + // the extensions. + InstructionFolder folder( + context(), + std::unique_ptr<InterpFoldingRules>(new InterpFoldingRules(context())), + MakeUnique<InterpConstFoldingRules>(context())); + for (Function& func : *get_module()) { + func.ForEachInst([&changed, &folder](Instruction* inst) { + if (folder.FoldInstruction(inst)) { + changed = true; + } + }); + } + + return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange; +} + +} // namespace opt +} // namespace spvtools diff --git a/source/opt/interp_fixup_pass.h b/source/opt/interp_fixup_pass.h new file mode 100644 index 00000000..e112b651 --- /dev/null +++ b/source/opt/interp_fixup_pass.h @@ -0,0 +1,54 @@ +// Copyright (c) 2021 The Khronos Group Inc. +// Copyright (c) 2021 Valve Corporation +// Copyright (c) 2021 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_INTERP_FIXUP_H +#define SOURCE_OPT_INTERP_FIXUP_H + +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +// Replaces overloaded internal form for GLSLstd450Interpolate* instructions +// with external form. Specifically, removes OpLoad from the first argument +// and replaces it with the pointer for the OpLoad. glslang generates the +// internal form. This pass is called as part of glslang HLSL legalization. +class InterpFixupPass : public Pass { + public: + const char* name() const override { return "interp-fixup"; } + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | + IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | + IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisScalarEvolution | + IRContext::kAnalysisRegisterPressure | + IRContext::kAnalysisValueNumberTable | + IRContext::kAnalysisStructuredCFG | + IRContext::kAnalysisBuiltinVarId | + IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes | + IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants; + } +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_INTERP_FIXUP_H diff --git a/source/opt/iterator.h b/source/opt/iterator.h index 444d457c..2280582d 100644 --- a/source/opt/iterator.h +++ b/source/opt/iterator.h @@ -30,18 +30,14 @@ namespace opt { // std::unique_ptr managed elements in the vector, behaving like we are using // std::vector<|ValueType|>. template <typename ValueType, bool IsConst = false> -class UptrVectorIterator - : public std::iterator<std::random_access_iterator_tag, - typename std::conditional<IsConst, const ValueType, - ValueType>::type> { +class UptrVectorIterator { public: - using super = std::iterator< - std::random_access_iterator_tag, - typename std::conditional<IsConst, const ValueType, ValueType>::type>; + using iterator_category = std::random_access_iterator_tag; + using value_type = ValueType; - using pointer = typename super::pointer; - using reference = typename super::reference; - using difference_type = typename super::difference_type; + using pointer = value_type*; + using reference = value_type&; + using difference_type = std::ptrdiff_t; // Type aliases. We need to apply constness properly if |IsConst| is true. using Uptr = std::unique_ptr<ValueType>; @@ -174,11 +170,7 @@ inline IteratorRange<IteratorType> make_const_range( // // Currently this iterator is always an input iterator. template <typename SubIterator, typename Predicate> -class FilterIterator - : public std::iterator< - std::input_iterator_tag, typename SubIterator::value_type, - typename SubIterator::difference_type, typename SubIterator::pointer, - typename SubIterator::reference> { +class FilterIterator { public: // Iterator interface. using iterator_category = typename SubIterator::iterator_category; diff --git a/source/opt/mem_pass.h b/source/opt/mem_pass.h index dcc16b65..5a77670d 100644 --- a/source/opt/mem_pass.h +++ b/source/opt/mem_pass.h @@ -38,7 +38,7 @@ namespace opt { // utility functions and supporting state. class MemPass : public Pass { public: - virtual ~MemPass() = default; + virtual ~MemPass() override = default; // Returns an undef value for the given |var_id|'s type. uint32_t GetUndefVal(uint32_t var_id) { diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index 909442cc..a5d10c3d 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -155,7 +155,8 @@ Optimizer& Optimizer::RegisterLegalizationPasses() { .RegisterPass(CreateVectorDCEPass()) .RegisterPass(CreateDeadInsertElimPass()) .RegisterPass(CreateReduceLoadSizePass()) - .RegisterPass(CreateAggressiveDCEPass()); + .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateInterpolateFixupPass()); } Optimizer& Optimizer::RegisterPerformancePasses() { @@ -494,6 +495,8 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { RegisterPass(CreateWrapOpKillPass()); } else if (pass_name == "amd-ext-to-khr") { RegisterPass(CreateAmdExtToKhrPass()); + } else if (pass_name == "interpolate-fixup") { + RegisterPass(CreateInterpolateFixupPass()); } else { Errorf(consumer(), nullptr, {}, "Unknown flag '--%s'. Use --help for a list of valid flags", @@ -925,4 +928,9 @@ Optimizer::PassToken CreateAmdExtToKhrPass() { MakeUnique<opt::AmdExtensionToKhrPass>()); } +Optimizer::PassToken CreateInterpolateFixupPass() { + return MakeUnique<Optimizer::PassToken::Impl>( + MakeUnique<opt::InterpFixupPass>()); +} + } // namespace spvtools diff --git a/source/opt/passes.h b/source/opt/passes.h index 1bc94c7e..bfb34af7 100644 --- a/source/opt/passes.h +++ b/source/opt/passes.h @@ -46,6 +46,7 @@ #include "source/opt/inst_bindless_check_pass.h" #include "source/opt/inst_buff_addr_check_pass.h" #include "source/opt/inst_debug_printf_pass.h" +#include "source/opt/interp_fixup_pass.h" #include "source/opt/licm_pass.h" #include "source/opt/local_access_chain_convert_pass.h" #include "source/opt/local_redundancy_elimination.h" diff --git a/source/opt/scalar_replacement_pass.cpp b/source/opt/scalar_replacement_pass.cpp index ba2d0675..4d47bdd8 100644 --- a/source/opt/scalar_replacement_pass.cpp +++ b/source/opt/scalar_replacement_pass.cpp @@ -861,6 +861,9 @@ bool ScalarReplacementPass::CheckUsesRelaxed(const Instruction* inst) const { case SpvOpStore: if (!CheckStore(user, index)) ok = false; break; + case SpvOpImageTexelPointer: + if (!CheckImageTexelPointer(index)) ok = false; + break; default: ok = false; break; @@ -870,6 +873,10 @@ bool ScalarReplacementPass::CheckUsesRelaxed(const Instruction* inst) const { return ok; } +bool ScalarReplacementPass::CheckImageTexelPointer(uint32_t index) const { + return index == 2u; +} + bool ScalarReplacementPass::CheckLoad(const Instruction* inst, uint32_t index) const { if (index != 2u) return false; diff --git a/source/opt/scalar_replacement_pass.h b/source/opt/scalar_replacement_pass.h index 1f6c9281..9e9f0739 100644 --- a/source/opt/scalar_replacement_pass.h +++ b/source/opt/scalar_replacement_pass.h @@ -142,6 +142,10 @@ class ScalarReplacementPass : public Pass { // of |inst| and the store is not to volatile memory. bool CheckStore(const Instruction* inst, uint32_t index) const; + // Returns true if |index| is the pointer operand of an OpImageTexelPointer + // instruction. + bool CheckImageTexelPointer(uint32_t index) const; + // Creates a variable of type |typeId| from the |index|'th element of // |varInst|. The new variable is added to |replacements|. If the variable // could not be created, then |nullptr| is appended to |replacements|. diff --git a/source/opt/type_manager.cpp b/source/opt/type_manager.cpp index ce9c2c14..7935ad33 100644 --- a/source/opt/type_manager.cpp +++ b/source/opt/type_manager.cpp @@ -223,7 +223,7 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) { case Type::k##kind: \ typeInst = MakeUnique<Instruction>(context(), SpvOpType##kind, 0, id, \ std::initializer_list<Operand>{}); \ - break; + break DefineParameterlessCase(Void); DefineParameterlessCase(Bool); DefineParameterlessCase(Sampler); @@ -513,7 +513,7 @@ Type* TypeManager::RebuildType(const Type& type) { #define DefineNoSubtypeCase(kind) \ case Type::k##kind: \ rebuilt_ty.reset(type.Clone().release()); \ - return type_pool_.insert(std::move(rebuilt_ty)).first->get(); + return type_pool_.insert(std::move(rebuilt_ty)).first->get() DefineNoSubtypeCase(Void); DefineNoSubtypeCase(Bool); diff --git a/source/opt/types.h b/source/opt/types.h index d5be9be4..9ecd41a6 100644 --- a/source/opt/types.h +++ b/source/opt/types.h @@ -101,7 +101,7 @@ class Type { Type(Kind k) : kind_(k) {} - virtual ~Type() {} + virtual ~Type() = default; // Attaches a decoration directly on this type. void AddDecoration(std::vector<uint32_t>&& d) { diff --git a/source/reduce/reducer.cpp b/source/reduce/reducer.cpp index 18eeaeb6..16bb94fe 100644 --- a/source/reduce/reducer.cpp +++ b/source/reduce/reducer.cpp @@ -54,10 +54,10 @@ void Reducer::SetInterestingnessFunction( } Reducer::ReductionResultStatus Reducer::Run( - std::vector<uint32_t>&& binary_in, std::vector<uint32_t>* binary_out, + const std::vector<uint32_t>& binary_in, std::vector<uint32_t>* binary_out, spv_const_reducer_options options, spv_validator_options validator_options) { - std::vector<uint32_t> current_binary(std::move(binary_in)); + std::vector<uint32_t> current_binary(binary_in); spvtools::SpirvTools tools(target_env_); assert(tools.IsValid() && "Failed to create SPIRV-Tools interface"); @@ -138,13 +138,13 @@ void Reducer::AddDefaultReductionPasses() { } void Reducer::AddReductionPass( - std::unique_ptr<ReductionOpportunityFinder>&& finder) { + std::unique_ptr<ReductionOpportunityFinder> finder) { passes_.push_back( spvtools::MakeUnique<ReductionPass>(target_env_, std::move(finder))); -} +} void Reducer::AddCleanupReductionPass( - std::unique_ptr<ReductionOpportunityFinder>&& finder) { + std::unique_ptr<ReductionOpportunityFinder> finder) { cleanup_passes_.push_back( spvtools::MakeUnique<ReductionPass>(target_env_, std::move(finder))); } diff --git a/source/reduce/reducer.h b/source/reduce/reducer.h index 864ce757..f3ba1806 100644 --- a/source/reduce/reducer.h +++ b/source/reduce/reducer.h @@ -84,17 +84,17 @@ class Reducer { // Adds a reduction pass based on the given finder to the sequence of passes // that will be iterated over. - void AddReductionPass(std::unique_ptr<ReductionOpportunityFinder>&& finder); + void AddReductionPass(std::unique_ptr<ReductionOpportunityFinder> finder); // Adds a cleanup reduction pass based on the given finder to the sequence of // passes that will run after other passes. void AddCleanupReductionPass( - std::unique_ptr<ReductionOpportunityFinder>&& finder); + std::unique_ptr<ReductionOpportunityFinder> finder); // Reduces the given SPIR-V module |binary_out|. // The reduced binary ends up in |binary_out|. // A status is returned. - ReductionResultStatus Run(std::vector<uint32_t>&& binary_in, + ReductionResultStatus Run(const std::vector<uint32_t>& binary_in, std::vector<uint32_t>* binary_out, spv_const_reducer_options options, spv_validator_options validator_options); diff --git a/source/val/basic_block.h b/source/val/basic_block.h index 5eea4f92..5af4b9e4 100644 --- a/source/val/basic_block.h +++ b/source/val/basic_block.h @@ -139,9 +139,14 @@ class BasicBlock { /// @brief A BasicBlock dominator iterator class /// /// This iterator will iterate over the (post)dominators of the block - class DominatorIterator - : public std::iterator<std::forward_iterator_tag, BasicBlock*> { + class DominatorIterator { public: + using iterator_category = std::forward_iterator_tag; + using value_type = BasicBlock*; + using pointer = value_type*; + using reference = value_type&; + using difference_type = std::ptrdiff_t; + /// @brief Constructs the end of dominator iterator /// /// This will create an iterator which will represent the element diff --git a/source/val/validate.cpp b/source/val/validate.cpp index a2e116b1..45b6a463 100644 --- a/source/val/validate.cpp +++ b/source/val/validate.cpp @@ -143,6 +143,7 @@ spv_result_t ValidateEntryPoints(ValidationState_t& _) { if (_.recursive_entry_points().find(entry_point) != _.recursive_entry_points().end()) { return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(entry_point)) + << _.VkErrorID(4634) << "Entry points may not have a call graph with cycles."; } } diff --git a/source/val/validate_atomics.cpp b/source/val/validate_atomics.cpp index dd263a79..fa53ca1f 100644 --- a/source/val/validate_atomics.cpp +++ b/source/val/validate_atomics.cpp @@ -47,6 +47,72 @@ bool IsStorageClassAllowedByUniversalRules(uint32_t storage_class) { } } +bool HasReturnType(uint32_t opcode) { + switch (opcode) { + case SpvOpAtomicStore: + case SpvOpAtomicFlagClear: + return false; + break; + default: + return true; + } +} + +bool HasOnlyFloatReturnType(uint32_t opcode) { + switch (opcode) { + case SpvOpAtomicFAddEXT: + case SpvOpAtomicFMinEXT: + case SpvOpAtomicFMaxEXT: + return true; + break; + default: + return false; + } +} + +bool HasOnlyIntReturnType(uint32_t opcode) { + switch (opcode) { + case SpvOpAtomicCompareExchange: + case SpvOpAtomicCompareExchangeWeak: + case SpvOpAtomicIIncrement: + case SpvOpAtomicIDecrement: + case SpvOpAtomicIAdd: + case SpvOpAtomicISub: + case SpvOpAtomicSMin: + case SpvOpAtomicUMin: + case SpvOpAtomicSMax: + case SpvOpAtomicUMax: + case SpvOpAtomicAnd: + case SpvOpAtomicOr: + case SpvOpAtomicXor: + return true; + break; + default: + return false; + } +} + +bool HasIntOrFloatReturnType(uint32_t opcode) { + switch (opcode) { + case SpvOpAtomicLoad: + case SpvOpAtomicExchange: + return true; + break; + default: + return false; + } +} + +bool HasOnlyBoolReturnType(uint32_t opcode) { + switch (opcode) { + case SpvOpAtomicFlagTestAndSet: + return true; + break; + default: + return false; + } +} + } // namespace namespace spvtools { @@ -55,12 +121,6 @@ namespace val { // Validates correctness of atomic instructions. spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { const SpvOp opcode = inst->opcode(); - const uint32_t result_type = inst->type_id(); - bool is_atomic_float_opcode = false; - if (opcode == SpvOpAtomicLoad || opcode == SpvOpAtomicStore || - opcode == SpvOpAtomicFAddEXT || opcode == SpvOpAtomicExchange) { - is_atomic_float_opcode = true; - } switch (opcode) { case SpvOpAtomicLoad: case SpvOpAtomicStore: @@ -74,128 +134,47 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { case SpvOpAtomicISub: case SpvOpAtomicSMin: case SpvOpAtomicUMin: + case SpvOpAtomicFMinEXT: case SpvOpAtomicSMax: case SpvOpAtomicUMax: + case SpvOpAtomicFMaxEXT: case SpvOpAtomicAnd: case SpvOpAtomicOr: case SpvOpAtomicXor: case SpvOpAtomicFlagTestAndSet: case SpvOpAtomicFlagClear: { - if (_.HasCapability(SpvCapabilityKernel) && - (opcode == SpvOpAtomicLoad || opcode == SpvOpAtomicExchange || - opcode == SpvOpAtomicCompareExchange)) { - if (!_.IsFloatScalarType(result_type) && - !_.IsIntScalarType(result_type)) { + const uint32_t result_type = inst->type_id(); + + // All current atomics only are scalar result + // Validate return type first so can just check if pointer type is same + // (if applicable) + if (HasReturnType(opcode)) { + if (HasOnlyFloatReturnType(opcode) && + !_.IsFloatScalarType(result_type)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << spvOpcodeString(opcode) - << ": expected Result Type to be int or float scalar type"; - } - } else if (opcode == SpvOpAtomicFlagTestAndSet) { - if (!_.IsBoolScalarType(result_type)) { + << ": expected Result Type to be float scalar type"; + } else if (HasOnlyIntReturnType(opcode) && + !_.IsIntScalarType(result_type)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << spvOpcodeString(opcode) - << ": expected Result Type to be bool scalar type"; - } - } else if (opcode == SpvOpAtomicFlagClear || opcode == SpvOpAtomicStore) { - assert(result_type == 0); - } else { - if (_.IsFloatScalarType(result_type)) { - if (is_atomic_float_opcode) { - if (opcode == SpvOpAtomicFAddEXT) { - if ((_.GetBitWidth(result_type) == 32) && - (!_.HasCapability(SpvCapabilityAtomicFloat32AddEXT))) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": float add atomics require the AtomicFloat32AddEXT " - "capability"; - } - if ((_.GetBitWidth(result_type) == 64) && - (!_.HasCapability(SpvCapabilityAtomicFloat64AddEXT))) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": float add atomics require the AtomicFloat64AddEXT " - "capability"; - } - } - } else { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": expected Result Type to be int scalar type"; - } - } else if (_.IsIntScalarType(result_type) && - opcode == SpvOpAtomicFAddEXT) { + << ": expected Result Type to be integer scalar type"; + } else if (HasIntOrFloatReturnType(opcode) && + !_.IsFloatScalarType(result_type) && + !_.IsIntScalarType(result_type)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << spvOpcodeString(opcode) - << ": expected Result Type to be float scalar type"; - } else if (!_.IsFloatScalarType(result_type) && - !_.IsIntScalarType(result_type)) { - switch (opcode) { - case SpvOpAtomicFAddEXT: - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": expected Result Type to be float scalar type"; - case SpvOpAtomicIIncrement: - case SpvOpAtomicIDecrement: - case SpvOpAtomicIAdd: - case SpvOpAtomicISub: - case SpvOpAtomicSMin: - case SpvOpAtomicSMax: - case SpvOpAtomicUMin: - case SpvOpAtomicUMax: - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": expected Result Type to be integer scalar type"; - default: - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": expected Result Type to be int or float scalar type"; - } - } - - if (spvIsVulkanEnv(_.context()->target_env) && - (_.GetBitWidth(result_type) != 32 && - (_.GetBitWidth(result_type) != 64 || - !_.HasCapability(SpvCapabilityInt64ImageEXT)))) { - switch (opcode) { - case SpvOpAtomicSMin: - case SpvOpAtomicUMin: - case SpvOpAtomicSMax: - case SpvOpAtomicUMax: - case SpvOpAtomicAnd: - case SpvOpAtomicOr: - case SpvOpAtomicXor: - case SpvOpAtomicIAdd: - case SpvOpAtomicISub: - case SpvOpAtomicFAddEXT: - case SpvOpAtomicLoad: - case SpvOpAtomicStore: - case SpvOpAtomicExchange: - case SpvOpAtomicIIncrement: - case SpvOpAtomicIDecrement: - case SpvOpAtomicCompareExchangeWeak: - case SpvOpAtomicCompareExchange: { - if (_.GetBitWidth(result_type) == 64 && - _.IsIntScalarType(result_type) && - !_.HasCapability(SpvCapabilityInt64Atomics)) - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": 64-bit atomics require the Int64Atomics " - "capability"; - } break; - default: - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": according to the Vulkan spec atomic Result Type " - "needs " - "to be a 32-bit int scalar type"; - } + << ": expected Result Type to be integer or float scalar type"; + } else if (HasOnlyBoolReturnType(opcode) && + !_.IsBoolScalarType(result_type)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": expected Result Type to be bool scalar type"; } } - uint32_t operand_index = - opcode == SpvOpAtomicFlagClear || opcode == SpvOpAtomicStore ? 0 : 2; + uint32_t operand_index = HasReturnType(opcode) ? 2 : 0; const uint32_t pointer_type = _.GetOperandTypeId(inst, operand_index++); - uint32_t data_type = 0; uint32_t storage_class = 0; if (!_.GetPointerTypeInfo(pointer_type, &data_type, &storage_class)) { @@ -204,6 +183,14 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { << ": expected Pointer to be of type OpTypePointer"; } + // Can't use result_type because OpAtomicStore doesn't have a result + if (_.GetBitWidth(data_type) == 64 && _.IsIntScalarType(data_type) && + !_.HasCapability(SpvCapabilityInt64Atomics)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": 64-bit atomics require the Int64Atomics capability"; + } + // Validate storage class against universal rules if (!IsStorageClassAllowedByUniversalRules(storage_class)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) @@ -213,6 +200,7 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { // Then Shader rules if (_.HasCapability(SpvCapabilityShader)) { + // Vulkan environment rule if (spvIsVulkanEnv(_.context()->target_env)) { if ((storage_class != SpvStorageClassUniform) && (storage_class != SpvStorageClassStorageBuffer) && @@ -231,6 +219,47 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { << ": Function storage class forbidden when the Shader " "capability is declared."; } + + if (opcode == SpvOpAtomicFAddEXT) { + // result type being float checked already + if ((_.GetBitWidth(result_type) == 32) && + (!_.HasCapability(SpvCapabilityAtomicFloat32AddEXT))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": float add atomics require the AtomicFloat32AddEXT " + "capability"; + } + if ((_.GetBitWidth(result_type) == 64) && + (!_.HasCapability(SpvCapabilityAtomicFloat64AddEXT))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": float add atomics require the AtomicFloat64AddEXT " + "capability"; + } + } else if (opcode == SpvOpAtomicFMinEXT || + opcode == SpvOpAtomicFMaxEXT) { + if ((_.GetBitWidth(result_type) == 16) && + (!_.HasCapability(SpvCapabilityAtomicFloat16MinMaxEXT))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": float min/max atomics require the " + "AtomicFloat16MinMaxEXT capability"; + } + if ((_.GetBitWidth(result_type) == 32) && + (!_.HasCapability(SpvCapabilityAtomicFloat32MinMaxEXT))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": float min/max atomics require the " + "AtomicFloat32MinMaxEXT capability"; + } + if ((_.GetBitWidth(result_type) == 64) && + (!_.HasCapability(SpvCapabilityAtomicFloat64MinMaxEXT))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": float min/max atomics require the " + "AtomicFloat64MinMaxEXT capability"; + } + } } // And finally OpenCL environment rules @@ -254,27 +283,27 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { } } + // If result and pointer type are different, need to do special check here if (opcode == SpvOpAtomicFlagTestAndSet || opcode == SpvOpAtomicFlagClear) { if (!_.IsIntScalarType(data_type) || _.GetBitWidth(data_type) != 32) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << spvOpcodeString(opcode) - << ": expected Pointer to point to a value of 32-bit int type"; + << ": expected Pointer to point to a value of 32-bit integer " + "type"; } } else if (opcode == SpvOpAtomicStore) { if (!_.IsFloatScalarType(data_type) && !_.IsIntScalarType(data_type)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << spvOpcodeString(opcode) - << ": expected Pointer to be a pointer to int or float " + << ": expected Pointer to be a pointer to integer or float " << "scalar type"; } - } else { - if (data_type != result_type) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": expected Pointer to point to a value of type Result " - "Type"; - } + } else if (data_type != result_type) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": expected Pointer to point to a value of type Result " + "Type"; } auto memory_scope = inst->GetOperandAs<const uint32_t>(operand_index++); @@ -283,14 +312,15 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { } const auto equal_semantics_index = operand_index++; - if (auto error = ValidateMemorySemantics(_, inst, equal_semantics_index)) + if (auto error = ValidateMemorySemantics(_, inst, equal_semantics_index, + memory_scope)) return error; if (opcode == SpvOpAtomicCompareExchange || opcode == SpvOpAtomicCompareExchangeWeak) { const auto unequal_semantics_index = operand_index++; - if (auto error = - ValidateMemorySemantics(_, inst, unequal_semantics_index)) + if (auto error = ValidateMemorySemantics( + _, inst, unequal_semantics_index, memory_scope)) return error; // Volatile bits must match for equal and unequal semantics. Previous diff --git a/source/val/validate_barriers.cpp b/source/val/validate_barriers.cpp index b499c8c0..3a9e3e7c 100644 --- a/source/val/validate_barriers.cpp +++ b/source/val/validate_barriers.cpp @@ -69,7 +69,7 @@ spv_result_t BarriersPass(ValidationState_t& _, const Instruction* inst) { return error; } - if (auto error = ValidateMemorySemantics(_, inst, 2)) { + if (auto error = ValidateMemorySemantics(_, inst, 2, memory_scope)) { return error; } break; @@ -82,7 +82,7 @@ spv_result_t BarriersPass(ValidationState_t& _, const Instruction* inst) { return error; } - if (auto error = ValidateMemorySemantics(_, inst, 1)) { + if (auto error = ValidateMemorySemantics(_, inst, 1, memory_scope)) { return error; } break; @@ -119,7 +119,7 @@ spv_result_t BarriersPass(ValidationState_t& _, const Instruction* inst) { return error; } - if (auto error = ValidateMemorySemantics(_, inst, 2)) { + if (auto error = ValidateMemorySemantics(_, inst, 2, memory_scope)) { return error; } break; diff --git a/source/val/validate_cfg.cpp b/source/val/validate_cfg.cpp index a5f6e6a1..36f632a8 100644 --- a/source/val/validate_cfg.cpp +++ b/source/val/validate_cfg.cpp @@ -654,18 +654,15 @@ spv_result_t ValidateStructuredSelections( << "Selection must be structured"; } } else if (terminator->opcode() == SpvOpSwitch) { - uint32_t count = 0; - // Mark the targets as seen now, but only error out if this block was - // missing a merge instruction and there were multiple unseen labels. + if (!merge) { + return _.diag(SPV_ERROR_INVALID_CFG, terminator) + << "OpSwitch must be preceeded by an OpSelectionMerge " + "instruction"; + } + // Mark the targets as seen. for (uint32_t i = 1; i < terminator->operands().size(); i += 2) { const auto target = terminator->GetOperandAs<uint32_t>(i); - if (seen.insert(target).second) { - count++; - } - } - if (!merge && count > 1) { - return _.diag(SPV_ERROR_INVALID_CFG, terminator) - << "Selection must be structured"; + seen.insert(target); } } } diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp index ed336b47..f076b04c 100644 --- a/source/val/validate_decorations.cpp +++ b/source/val/validate_decorations.cpp @@ -1619,7 +1619,7 @@ spv_result_t CheckLocationDecoration(ValidationState_t& vstate, { \ spv_result_t e##LINE = (X); \ if (e##LINE != SPV_SUCCESS) return e##LINE; \ - } + } static_assert(true, "require extra semicolon") #define PASS_OR_BAIL(X) PASS_OR_BAIL_AT_LINE(X, __LINE__) // Check rules for decorations where we start from the decoration rather diff --git a/source/val/validate_extensions.cpp b/source/val/validate_extensions.cpp index dc8c0243..a7167fc1 100644 --- a/source/val/validate_extensions.cpp +++ b/source/val/validate_extensions.cpp @@ -692,8 +692,8 @@ spv_result_t ValidateExtension(ValidationState_t& _, const Instruction* inst) { if (extension == ExtensionToString(kSPV_KHR_workgroup_memory_explicit_layout)) { return _.diag(SPV_ERROR_WRONG_VERSION, inst) - << "SPV_KHR_workgroup_memory_explicit_layout extension " - "requires SPIR-V version 1.4 or later."; + << "SPV_KHR_workgroup_memory_explicit_layout extension " + "requires SPIR-V version 1.4 or later."; } } @@ -1372,7 +1372,16 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { << "or vector type"; } - const uint32_t interpolant_type = _.GetOperandTypeId(inst, 4); + // If HLSL legalization and first operand is an OpLoad, use load + // pointer as the interpolant lvalue. Else use interpolate first + // operand. + uint32_t interp_id = inst->GetOperandAs<uint32_t>(4); + auto* interp_inst = _.FindDef(interp_id); + uint32_t interpolant_type = (_.options()->before_hlsl_legalization && + interp_inst->opcode() == SpvOpLoad) + ? _.GetOperandTypeId(interp_inst, 2) + : _.GetOperandTypeId(inst, 4); + uint32_t interpolant_storage_class = 0; uint32_t interpolant_data_type = 0; if (!_.GetPointerTypeInfo(interpolant_type, &interpolant_data_type, diff --git a/source/val/validate_logicals.cpp b/source/val/validate_logicals.cpp index 5886dbf5..bb35f558 100644 --- a/source/val/validate_logicals.cpp +++ b/source/val/validate_logicals.cpp @@ -188,7 +188,7 @@ spv_result_t LogicalsPass(ValidationState_t& _, const Instruction* inst) { case SpvOpTypeStruct: { if (!composites) return fail(); break; - }; + } default: return fail(); diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index 4dd6d941..a4bc0fab 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -466,6 +466,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { if (!_.IsValidStorageClass(storage_class)) { return _.diag(SPV_ERROR_INVALID_BINARY, inst) + << _.VkErrorID(4643) << "Invalid storage class for target environment"; } diff --git a/source/val/validate_memory_semantics.cpp b/source/val/validate_memory_semantics.cpp index 6c3e1d44..d9189313 100644 --- a/source/val/validate_memory_semantics.cpp +++ b/source/val/validate_memory_semantics.cpp @@ -25,7 +25,8 @@ namespace val { spv_result_t ValidateMemorySemantics(ValidationState_t& _, const Instruction* inst, - uint32_t operand_index) { + uint32_t operand_index, + uint32_t memory_scope) { const SpvOp opcode = inst->opcode(); const auto id = inst->GetOperandAs<const uint32_t>(operand_index); bool is_int32 = false, is_const_int32 = false; @@ -178,6 +179,18 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _, "of the following bits set: Acquire, Release, " "AcquireRelease " "or SequentiallyConsistent"; + } else if (opcode != SpvOpMemoryBarrier && num_memory_order_set_bits) { + // should leave only atomics and control barriers for Vulkan env + bool memory_is_int32 = false, memory_is_const_int32 = false; + uint32_t memory_value = 0; + std::tie(memory_is_int32, memory_is_const_int32, memory_value) = + _.EvalInt32IfConst(memory_scope); + if (memory_is_int32 && memory_value == SpvScopeInvocation) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4641) << spvOpcodeString(opcode) + << ": Vulkan specification requires Memory Semantics to be None " + "if used with Invocation Memory Scope"; + } } if (opcode == SpvOpMemoryBarrier && !includes_storage_class) { diff --git a/source/val/validate_memory_semantics.h b/source/val/validate_memory_semantics.h index 72a3e100..9e6f93a3 100644 --- a/source/val/validate_memory_semantics.h +++ b/source/val/validate_memory_semantics.h @@ -22,7 +22,8 @@ namespace val { spv_result_t ValidateMemorySemantics(ValidationState_t& _, const Instruction* inst, - uint32_t operand_index); + uint32_t operand_index, + uint32_t memory_scope); } // namespace val } // namespace spvtools diff --git a/source/val/validate_misc.cpp b/source/val/validate_misc.cpp index 0c30f3ca..3bc15ca0 100644 --- a/source/val/validate_misc.cpp +++ b/source/val/validate_misc.cpp @@ -72,6 +72,37 @@ spv_result_t ValidateShaderClock(ValidationState_t& _, return SPV_SUCCESS; } +spv_result_t ValidateAssumeTrue(ValidationState_t& _, const Instruction* inst) { + const auto operand_type_id = _.GetOperandTypeId(inst, 0); + if (!operand_type_id || !_.IsBoolScalarType(operand_type_id)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Value operand of OpAssumeTrueKHR must be a boolean scalar"; + } + return SPV_SUCCESS; +} + +spv_result_t ValidateExpect(ValidationState_t& _, const Instruction* inst) { + const auto result_type = inst->type_id(); + if (!_.IsBoolScalarOrVectorType(result_type) && + !_.IsIntScalarOrVectorType(result_type)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Result of OpExpectKHR must be a scalar or vector of integer " + "type or boolean type"; + } + + if (_.GetOperandTypeId(inst, 2) != result_type) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Type of Value operand of OpExpectKHR does not match the result " + "type "; + } + if (_.GetOperandTypeId(inst, 3) != result_type) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Type of ExpectedValue operand of OpExpectKHR does not match the " + "result type "; + } + return SPV_SUCCESS; +} + } // namespace spv_result_t MiscPass(ValidationState_t& _, const Instruction* inst) { @@ -152,6 +183,16 @@ spv_result_t MiscPass(ValidationState_t& _, const Instruction* inst) { return error; } break; + case SpvOpAssumeTrueKHR: + if (auto error = ValidateAssumeTrue(_, inst)) { + return error; + } + break; + case SpvOpExpectKHR: + if (auto error = ValidateExpect(_, inst)) { + return error; + } + break; default: break; } diff --git a/source/val/validate_scopes.cpp b/source/val/validate_scopes.cpp index a92f7fd3..29ba5831 100644 --- a/source/val/validate_scopes.cpp +++ b/source/val/validate_scopes.cpp @@ -105,21 +105,30 @@ spv_result_t ValidateExecutionScope(ValidationState_t& _, } } - // If OpControlBarrier is used in fragment, vertex, tessellation evaluation, - // or geometry stages, the execution Scope must be Subgroup. + // OpControlBarrier must only use Subgroup execution scope for a subset of + // execution models. if (opcode == SpvOpControlBarrier && value != SpvScopeSubgroup) { + std::string errorVUID = _.VkErrorID(4682); _.function(inst->function()->id()) - ->RegisterExecutionModelLimitation([](SpvExecutionModel model, - std::string* message) { + ->RegisterExecutionModelLimitation([errorVUID]( + SpvExecutionModel model, + std::string* message) { if (model == SpvExecutionModelFragment || model == SpvExecutionModelVertex || model == SpvExecutionModelGeometry || - model == SpvExecutionModelTessellationEvaluation) { + model == SpvExecutionModelTessellationEvaluation || + model == SpvExecutionModelRayGenerationKHR || + model == SpvExecutionModelIntersectionKHR || + model == SpvExecutionModelAnyHitKHR || + model == SpvExecutionModelClosestHitKHR || + model == SpvExecutionModelMissKHR) { if (message) { *message = - "in Vulkan evironment, OpControlBarrier execution scope " - "must be Subgroup for Fragment, Vertex, Geometry and " - "TessellationEvaluation execution models"; + errorVUID + + "in Vulkan environment, OpControlBarrier execution scope " + "must be Subgroup for Fragment, Vertex, Geometry, " + "TessellationEvaluation, RayGeneration, Intersection, " + "AnyHit, ClosestHit, and Miss execution models"; } return false; } @@ -127,11 +136,34 @@ spv_result_t ValidateExecutionScope(ValidationState_t& _, }); } + // Only subset of execution models support Workgroup. + if (value == SpvScopeWorkgroup) { + std::string errorVUID = _.VkErrorID(4637); + _.function(inst->function()->id()) + ->RegisterExecutionModelLimitation( + [errorVUID](SpvExecutionModel model, std::string* message) { + if (model != SpvExecutionModelTaskNV && + model != SpvExecutionModelMeshNV && + model != SpvExecutionModelTessellationControl && + model != SpvExecutionModelGLCompute) { + if (message) { + *message = + errorVUID + + "in Vulkan environment, Workgroup execution scope is " + "only for TaskNV, MeshNV, TessellationControl, and " + "GLCompute execution models"; + } + return false; + } + return true; + }); + } + // Vulkan generic rules // Scope for execution must be limited to Workgroup or Subgroup if (value != SpvScopeWorkgroup && value != SpvScopeSubgroup) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) + << _.VkErrorID(4636) << spvOpcodeString(opcode) << ": in Vulkan environment Execution Scope is limited to " << "Workgroup and Subgroup"; } diff --git a/source/val/validate_type.cpp b/source/val/validate_type.cpp index 6a5ea3c1..612fc5c2 100644 --- a/source/val/validate_type.cpp +++ b/source/val/validate_type.cpp @@ -427,7 +427,8 @@ spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) { if (spvIsVulkanEnv(_.context()->target_env) && !_.options()->before_hlsl_legalization && ContainsOpaqueType(_, inst)) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "In " << spvLogStringForEnv(_.context()->target_env) + << _.VkErrorID(4667) << "In " + << spvLogStringForEnv(_.context()->target_env) << ", OpTypeStruct must not contain an opaque type."; } @@ -462,6 +463,7 @@ spv_result_t ValidateTypePointer(ValidationState_t& _, if (!_.IsValidStorageClass(storage_class)) { return _.diag(SPV_ERROR_INVALID_BINARY, inst) + << _.VkErrorID(4643) << "Invalid storage class for target environment"; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 6dfc7bf6..db86fd25 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1255,12 +1255,12 @@ bool ValidationState_t::IsValidStorageClass( case SpvStorageClassFunction: case SpvStorageClassPushConstant: case SpvStorageClassPhysicalStorageBuffer: - case SpvStorageClassRayPayloadNV: - case SpvStorageClassIncomingRayPayloadNV: - case SpvStorageClassHitAttributeNV: - case SpvStorageClassCallableDataNV: - case SpvStorageClassIncomingCallableDataNV: - case SpvStorageClassShaderRecordBufferNV: + case SpvStorageClassRayPayloadKHR: + case SpvStorageClassIncomingRayPayloadKHR: + case SpvStorageClassHitAttributeKHR: + case SpvStorageClassCallableDataKHR: + case SpvStorageClassIncomingCallableDataKHR: + case SpvStorageClassShaderRecordBufferKHR: return true; default: return false; @@ -1676,16 +1676,26 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04492); case 4633: return VUID_WRAP(VUID-StandaloneSpirv-None-04633); + case 4634: + return VUID_WRAP(VUID-StandaloneSpirv-None-04634); case 4635: return VUID_WRAP(VUID-StandaloneSpirv-None-04635); + case 4636: + return VUID_WRAP(VUID-StandaloneSpirv-None-04636); + case 4637: + return VUID_WRAP(VUID-StandaloneSpirv-None-04637); case 4638: return VUID_WRAP(VUID-StandaloneSpirv-None-04638); case 4639: return VUID_WRAP(VUID-StandaloneSpirv-None-04639); case 4640: return VUID_WRAP(VUID-StandaloneSpirv-None-04640); + case 4641: + return VUID_WRAP(VUID-StandaloneSpirv-None-04641); case 4642: return VUID_WRAP(VUID-StandaloneSpirv-None-04642); + case 4643: + return VUID_WRAP(VUID-StandaloneSpirv-None-04643); case 4651: return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04651); case 4652: @@ -1710,12 +1720,16 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-Offset-04663); case 4664: return VUID_WRAP(VUID-StandaloneSpirv-OpImageGather-04664); + case 4667: + return VUID_WRAP(VUID-StandaloneSpirv-None-04667); case 4669: return VUID_WRAP(VUID-StandaloneSpirv-GLSLShared-04669); case 4675: return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675); case 4677: return VUID_WRAP(VUID-StandaloneSpirv-Invariant-04677); + case 4682: + return VUID_WRAP(VUID-StandaloneSpirv-OpControlBarrier-04682); case 4683: return VUID_WRAP(VUID-StandaloneSpirv-LocalSize-04683); case 4685: @@ -1736,7 +1750,7 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04733); default: return ""; // unknown id - }; + } // clang-format on } |