| 186 | } |
| 187 | |
| 188 | bool LoopFissionImpl::GroupInstructionsByUseDef() { |
| 189 | std::vector<std::set<Instruction*>> sets{}; |
| 190 | |
| 191 | // We want to ignore all the instructions stemming from the loop condition |
| 192 | // instruction. |
| 193 | BasicBlock* condition_block = loop_->FindConditionBlock(); |
| 194 | |
| 195 | if (!condition_block) return false; |
| 196 | Instruction* condition = &*condition_block->tail(); |
| 197 | |
| 198 | // We iterate over the blocks via iterating over all the blocks in the |
| 199 | // function, we do this so we are iterating in the same order which the blocks |
| 200 | // appear in the binary. |
| 201 | Function& function = *loop_->GetHeaderBlock()->GetParent(); |
| 202 | |
| 203 | // Create a temporary set to ignore certain groups of instructions within the |
| 204 | // loop. We don't want any instructions related to control flow to be removed |
| 205 | // from either loop only instructions within the control flow bodies. |
| 206 | std::set<Instruction*> instructions_to_ignore{}; |
| 207 | TraverseUseDef(condition, &instructions_to_ignore, true, true); |
| 208 | |
| 209 | // Traverse control flow instructions to ensure they are added to the |
| 210 | // seen_instructions_ set and will be ignored when it it called with actual |
| 211 | // sets. |
| 212 | for (BasicBlock& block : function) { |
| 213 | if (!loop_->IsInsideLoop(block.id())) continue; |
| 214 | |
| 215 | for (Instruction& inst : block) { |
| 216 | // Ignore all instructions related to control flow. |
| 217 | if (inst.opcode() == spv::Op::OpSelectionMerge || inst.IsBranch()) { |
| 218 | TraverseUseDef(&inst, &instructions_to_ignore, true, true); |
| 219 | } |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | // Traverse the instructions and generate the sets, automatically ignoring any |
| 224 | // instructions in instructions_to_ignore. |
| 225 | for (BasicBlock& block : function) { |
| 226 | if (!loop_->IsInsideLoop(block.id()) || |
| 227 | loop_->GetHeaderBlock()->id() == block.id()) |
| 228 | continue; |
| 229 | |
| 230 | for (Instruction& inst : block) { |
| 231 | // Record the order that each load/store is seen. |
| 232 | if (inst.opcode() == spv::Op::OpLoad || |
| 233 | inst.opcode() == spv::Op::OpStore) { |
| 234 | instruction_order_[&inst] = instruction_order_.size(); |
| 235 | } |
| 236 | |
| 237 | // Ignore instructions already seen in a traversal. |
| 238 | if (seen_instructions_.count(&inst) != 0) { |
| 239 | continue; |
| 240 | } |
| 241 | |
| 242 | // Build the set. |
| 243 | std::set<Instruction*> inst_set{}; |
| 244 | TraverseUseDef(&inst, &inst_set); |
| 245 | if (!inst_set.empty()) sets.push_back(std::move(inst_set)); |
no test coverage detected