| 31 | transformations, ignore_inapplicable_transformations) {} |
| 32 | |
| 33 | void FuzzerPassSplitBlocks::Apply() { |
| 34 | // Gather up pointers to all the blocks in the module. We are then able to |
| 35 | // iterate over these pointers and split the blocks to which they point; |
| 36 | // we cannot safely split blocks while we iterate through the module. |
| 37 | std::vector<opt::BasicBlock*> blocks; |
| 38 | for (auto& function : *GetIRContext()->module()) { |
| 39 | for (auto& block : function) { |
| 40 | blocks.push_back(&block); |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | // Now go through all the block pointers that were gathered. |
| 45 | for (auto& block : blocks) { |
| 46 | // Probabilistically decide whether to try to split this block. |
| 47 | if (!GetFuzzerContext()->ChoosePercentage( |
| 48 | GetFuzzerContext()->GetChanceOfSplittingBlock())) { |
| 49 | // We are not going to try to split this block. |
| 50 | continue; |
| 51 | } |
| 52 | |
| 53 | // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2964): consider |
| 54 | // taking a simpler approach to identifying the instruction before which |
| 55 | // to split a block. |
| 56 | |
| 57 | // We are going to try to split this block. We now need to choose where |
| 58 | // to split it. We describe the instruction before which we would like to |
| 59 | // split a block via an InstructionDescriptor, details of which are |
| 60 | // commented in the protobufs definition file. |
| 61 | std::vector<protobufs::InstructionDescriptor> instruction_descriptors; |
| 62 | |
| 63 | // The initial base instruction is the block label. |
| 64 | uint32_t base = block->id(); |
| 65 | |
| 66 | // Counts the number of times we have seen each opcode since we reset the |
| 67 | // base instruction. |
| 68 | std::map<spv::Op, uint32_t> skip_count; |
| 69 | |
| 70 | // Consider every instruction in the block. The label is excluded: it is |
| 71 | // only necessary to consider it as a base in case the first instruction |
| 72 | // in the block does not have a result id. |
| 73 | for (auto& inst : *block) { |
| 74 | if (inst.HasResultId()) { |
| 75 | // In the case that the instruction has a result id, we use the |
| 76 | // instruction as its own base, and clear the skip counts we have |
| 77 | // collected. |
| 78 | base = inst.result_id(); |
| 79 | skip_count.clear(); |
| 80 | } |
| 81 | const spv::Op opcode = inst.opcode(); |
| 82 | instruction_descriptors.emplace_back(MakeInstructionDescriptor( |
| 83 | base, opcode, skip_count.count(opcode) ? skip_count.at(opcode) : 0)); |
| 84 | if (!inst.HasResultId()) { |
| 85 | skip_count[opcode] = |
| 86 | skip_count.count(opcode) ? skip_count.at(opcode) + 1 : 1; |
| 87 | } |
| 88 | } |
| 89 | // Having identified all the places we might be able to split the block, |
| 90 | // we choose one of them. |
nothing calls this directly
no test coverage detected