| 145 | } |
| 146 | |
| 147 | void LoopFeature::Inject(IL::Program &program, const MessageStreamView<> &specialization) { |
| 148 | // Options |
| 149 | const SetLoopInstrumentationConfigMessage config = FindOrDefault(specialization, SetLoopInstrumentationConfigMessage { |
| 150 | .useIterationLimits = true, |
| 151 | .iterationLimit = 32'000, |
| 152 | .atomicIterationInterval = 256 |
| 153 | }); |
| 154 | |
| 155 | // Get constant literals |
| 156 | IL::ID interval = program.GetConstants().UInt(config.atomicIterationInterval)->id; |
| 157 | IL::ID maxIterations = program.GetConstants().UInt(config.iterationLimit)->id; |
| 158 | |
| 159 | // Get the data ids |
| 160 | IL::ID terminationBufferDataID = program.GetShaderDataMap().Get(terminationBufferID)->id; |
| 161 | IL::ID terminationAllocationDataID = program.GetShaderDataMap().Get(terminationAllocationID)->id; |
| 162 | |
| 163 | // Get the program capabilities |
| 164 | const IL::CapabilityTable &capabilityTable = program.GetCapabilityTable(); |
| 165 | |
| 166 | // Allocate all the counters |
| 167 | LoopCounterMap functionCounters; |
| 168 | InjectLoopCounters(program, functionCounters); |
| 169 | |
| 170 | // If the program has structured control flow, we can take quite a few liberties in instrumentation |
| 171 | if (capabilityTable.hasControlFlow) { |
| 172 | // Visit all instructions |
| 173 | IL::VisitUserInstructions(program, [&](IL::VisitContext &context, IL::BasicBlock::Iterator it) -> IL::BasicBlock::Iterator { |
| 174 | IL::BranchControlFlow controlFlow; |
| 175 | |
| 176 | // Must have a continue based, i.e. loop styled, control flow |
| 177 | if (!Backend::IL::GetControlFlow(it, controlFlow) || controlFlow._continue == IL::InvalidID) { |
| 178 | return it; |
| 179 | } |
| 180 | |
| 181 | // All basic blocks |
| 182 | IL::BasicBlockList& basicBlocks = context.function.GetBasicBlocks(); |
| 183 | |
| 184 | // Bind the SGUID |
| 185 | ShaderSGUID sguid = sguidHost ? sguidHost->Bind(program, it) : InvalidShaderSGUID; |
| 186 | |
| 187 | // Get merge block |
| 188 | // On termination this is the block we reach |
| 189 | IL::BasicBlock* mergeBlock = context.function.GetBasicBlocks().GetBlock(controlFlow.merge); |
| 190 | |
| 191 | // Allocate blocks |
| 192 | IL::BasicBlock *postEntry = context.function.GetBasicBlocks().AllocBlock(); |
| 193 | IL::BasicBlock *terminationBlock = context.function.GetBasicBlocks().AllocBlock(); |
| 194 | IL::BasicBlock* atomicBlock = context.function.GetBasicBlocks().AllocBlock(); |
| 195 | IL::BasicBlock* atomicMergeBlock = context.function.GetBasicBlocks().AllocBlock(); |
| 196 | |
| 197 | // The selection merge target, typically this is the post-entry (i.e. the split body entry point block), |
| 198 | // however, if the continue block is the body, then we need to split things further. |
| 199 | IL::BasicBlock* selectionMerge = postEntry; |
| 200 | |
| 201 | // Expected entry point |
| 202 | IL::BasicBlock* entryBlock = nullptr; |
| 203 | |
| 204 | // Determine entry point |
nothing calls this directly
no test coverage detected