| 75 | } |
| 76 | |
| 77 | void ExportIndicesFeature::Inject(IL::Program &program, const MessageStreamView<> &specialization) { |
| 78 | // Options |
| 79 | const SetInstrumentationConfigMessage config = CollapseOrDefault<SetInstrumentationConfigMessage>(specialization); |
| 80 | |
| 81 | // Visit all instructions |
| 82 | IL::VisitUserInstructions(program, [&](IL::VisitContext& context, IL::BasicBlock::Iterator it) -> IL::BasicBlock::Iterator { |
| 83 | // Instruction of interest? |
| 84 | IL::ID outputIndex; |
| 85 | switch (it->opCode) { |
| 86 | default: |
| 87 | return it; |
| 88 | // TODO: SPIRV StoreOutput -> vertex and primitive |
| 89 | // TODO: DXIL EmitIndices |
| 90 | case IL::OpCode::StoreVertexOutput: |
| 91 | outputIndex = it->As<IL::StoreVertexOutputInstruction>()->vertexIndex; |
| 92 | break; |
| 93 | case IL::OpCode::StorePrimitiveOutput: |
| 94 | outputIndex = it->As<IL::StorePrimitiveOutputInstruction>()->primitiveIndex; |
| 95 | break; |
| 96 | } |
| 97 | |
| 98 | // Instrumentation Segmentation |
| 99 | // |
| 100 | // BEFORE AFTER |
| 101 | // |
| 102 | // ┌─────┬─────────────┬───────┐ ┌─────┐ ┌─────────────┬──────┐ |
| 103 | // │ │ │ │ │ │ OK │ │ │ |
| 104 | // │ Pre │ Instruction │ Post │ │ Pre ├───────────────────┤ Instruction │ Post │ |
| 105 | // │ │ │ │ │ │ │ [RESUME] │ │ |
| 106 | // └─────┴─────────────┴───────┘ └──┬──┘ └──────┬──────┴──────┘ |
| 107 | // │ ┌────────────┐ │ |
| 108 | // INV │ │ │ │ |
| 109 | // └────┤ noThreadID ├───────────┘ |
| 110 | // │ │ |
| 111 | // └────────────┘ |
| 112 | |
| 113 | // Bind the SGUID |
| 114 | ShaderSGUID sguid = sguidHost ? sguidHost->Bind(program, it) : InvalidShaderSGUID; |
| 115 | |
| 116 | uint64_t line = sguidHost->GetMapping(sguid).line; |
| 117 | std::string_view lineCode = sguidHost->GetSource(sguid); |
| 118 | |
| 119 | // Allocate resume |
| 120 | IL::BasicBlock* resumeBlock = context.function.GetBasicBlocks().AllocBlock(); |
| 121 | |
| 122 | // Split this basic block, move all instructions post and including the instrumented instruction to resume |
| 123 | // ! iterator invalidated |
| 124 | auto instr = context.basicBlock.Split(resumeBlock, it); |
| 125 | |
| 126 | // Perform instrumentation check |
| 127 | IL::Emitter<> pre(program, context.basicBlock); |
| 128 | |
| 129 | // Failure conditions: output index is not thread ID |
| 130 | IL::ID isNotThreadIndex = pre.NotEqual(outputIndex, pre.KernelValue(Backend::IL::KernelValue::FlattenedLocalThreadID)); |
| 131 | |
| 132 | // isNotThreadIndex block |
| 133 | IL::Emitter<> noTid(program, *context.function.GetBasicBlocks().AllocBlock()); |
| 134 | noTid.AddBlockFlag(BasicBlockFlag::NoInstrumentation); |
nothing calls this directly
no test coverage detected