summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/bgfx/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/bgfx/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp')
-rw-r--r--3rdparty/bgfx/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp101
1 files changed, 101 insertions, 0 deletions
diff --git a/3rdparty/bgfx/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp b/3rdparty/bgfx/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp
index 823f2e09a23..1da53f42620 100644
--- a/3rdparty/bgfx/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp
+++ b/3rdparty/bgfx/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp
@@ -14,6 +14,8 @@
#include "source/fuzz/fuzzer_pass.h"
+#include "source/fuzz/instruction_descriptor.h"
+
namespace spvtools {
namespace fuzz {
@@ -27,5 +29,104 @@ FuzzerPass::FuzzerPass(opt::IRContext* ir_context, FactManager* fact_manager,
FuzzerPass::~FuzzerPass() = default;
+std::vector<opt::Instruction*> FuzzerPass::FindAvailableInstructions(
+ const opt::Function& function, opt::BasicBlock* block,
+ opt::BasicBlock::iterator inst_it,
+ std::function<bool(opt::IRContext*, opt::Instruction*)>
+ instruction_is_relevant) {
+ // TODO(afd) The following is (relatively) simple, but may end up being
+ // prohibitively inefficient, as it walks the whole dominator tree for
+ // every instruction that is considered.
+
+ std::vector<opt::Instruction*> result;
+ // Consider all global declarations
+ for (auto& global : GetIRContext()->module()->types_values()) {
+ if (instruction_is_relevant(GetIRContext(), &global)) {
+ result.push_back(&global);
+ }
+ }
+
+ // Consider all previous instructions in this block
+ for (auto prev_inst_it = block->begin(); prev_inst_it != inst_it;
+ ++prev_inst_it) {
+ if (instruction_is_relevant(GetIRContext(), &*prev_inst_it)) {
+ result.push_back(&*prev_inst_it);
+ }
+ }
+
+ // Walk the dominator tree to consider all instructions from dominating
+ // blocks
+ auto dominator_analysis = GetIRContext()->GetDominatorAnalysis(&function);
+ for (auto next_dominator = dominator_analysis->ImmediateDominator(block);
+ next_dominator != nullptr;
+ next_dominator =
+ dominator_analysis->ImmediateDominator(next_dominator)) {
+ for (auto& dominating_inst : *next_dominator) {
+ if (instruction_is_relevant(GetIRContext(), &dominating_inst)) {
+ result.push_back(&dominating_inst);
+ }
+ }
+ }
+ return result;
+}
+
+void FuzzerPass::MaybeAddTransformationBeforeEachInstruction(
+ std::function<
+ void(const opt::Function& function, opt::BasicBlock* block,
+ opt::BasicBlock::iterator inst_it,
+ const protobufs::InstructionDescriptor& instruction_descriptor)>
+ maybe_apply_transformation) {
+ // Consider every block in every function.
+ for (auto& function : *GetIRContext()->module()) {
+ for (auto& block : function) {
+ // We now consider every instruction in the block, randomly deciding
+ // whether to apply a transformation before it.
+
+ // In order for transformations to insert new instructions, they need to
+ // be able to identify the instruction to insert before. We describe an
+ // instruction via its opcode, 'opc', a base instruction 'base' that has a
+ // result id, and the number of instructions with opcode 'opc' that we
+ // should skip when searching from 'base' for the desired instruction.
+ // (An instruction that has a result id is represented by its own opcode,
+ // itself as 'base', and a skip-count of 0.)
+ std::vector<std::tuple<uint32_t, SpvOp, uint32_t>>
+ base_opcode_skip_triples;
+
+ // The initial base instruction is the block label.
+ uint32_t base = block.id();
+
+ // Counts the number of times we have seen each opcode since we reset the
+ // base instruction.
+ std::map<SpvOp, uint32_t> skip_count;
+
+ // Consider every instruction in the block. The label is excluded: it is
+ // only necessary to consider it as a base in case the first instruction
+ // in the block does not have a result id.
+ for (auto inst_it = block.begin(); inst_it != block.end(); ++inst_it) {
+ if (inst_it->HasResultId()) {
+ // In the case that the instruction has a result id, we use the
+ // instruction as its own base, and clear the skip counts we have
+ // collected.
+ base = inst_it->result_id();
+ skip_count.clear();
+ }
+ const SpvOp opcode = inst_it->opcode();
+
+ // Invoke the provided function, which might apply a transformation.
+ maybe_apply_transformation(
+ function, &block, inst_it,
+ MakeInstructionDescriptor(
+ base, opcode,
+ skip_count.count(opcode) ? skip_count.at(opcode) : 0));
+
+ if (!inst_it->HasResultId()) {
+ skip_count[opcode] =
+ skip_count.count(opcode) ? skip_count.at(opcode) + 1 : 1;
+ }
+ }
+ }
+ }
+}
+
} // namespace fuzz
} // namespace spvtools