Make the set |blocks| closed SSA. The set is closed SSA if all the uses outside the set are phi instructions in exiting basic block set (hold by |lcssa_rewriter|).
| 281 | // outside the set are phi instructions in exiting basic block set (hold by |
| 282 | // |lcssa_rewriter|). |
| 283 | inline bool MakeSetClosedSSA(IRContext* context, Function* function, |
| 284 | const std::unordered_set<uint32_t>& blocks, |
| 285 | const std::unordered_set<BasicBlock*>& exit_bb, |
| 286 | LCSSARewriter* lcssa_rewriter) { |
| 287 | CFG& cfg = *context->cfg(); |
| 288 | DominatorTree& dom_tree = |
| 289 | context->GetDominatorAnalysis(function)->GetDomTree(); |
| 290 | analysis::DefUseManager* def_use_manager = context->get_def_use_mgr(); |
| 291 | |
| 292 | for (uint32_t bb_id : blocks) { |
| 293 | BasicBlock* bb = cfg.block(bb_id); |
| 294 | // If bb does not dominate an exit block, then it cannot have escaping defs. |
| 295 | if (!DominatesAnExit(bb, exit_bb, dom_tree)) continue; |
| 296 | for (Instruction& inst : *bb) { |
| 297 | LCSSARewriter::UseRewriter rewriter(lcssa_rewriter, inst); |
| 298 | bool success = def_use_manager->WhileEachUse( |
| 299 | &inst, [&blocks, &rewriter, &exit_bb, context]( |
| 300 | Instruction* use, uint32_t operand_index) { |
| 301 | BasicBlock* use_parent = context->get_instr_block(use); |
| 302 | assert(use_parent); |
| 303 | if (blocks.count(use_parent->id())) return true; |
| 304 | |
| 305 | if (use->opcode() == spv::Op::OpPhi) { |
| 306 | // If the use is a Phi instruction and the incoming block is |
| 307 | // coming from the loop, then that's consistent with LCSSA form. |
| 308 | if (exit_bb.count(use_parent)) { |
| 309 | return true; |
| 310 | } else { |
| 311 | // That's not an exit block, but the user is a phi instruction. |
| 312 | // Consider the incoming branch only. |
| 313 | use_parent = context->get_instr_block( |
| 314 | use->GetSingleWordOperand(operand_index + 1)); |
| 315 | } |
| 316 | } |
| 317 | // Rewrite the use. Note that this call does not invalidate the |
| 318 | // def/use manager. So this operation is safe. |
| 319 | return rewriter.RewriteUse(use_parent, use, operand_index); |
| 320 | }); |
| 321 | if (!success) { |
| 322 | return false; |
| 323 | } |
| 324 | rewriter.UpdateManagers(); |
| 325 | } |
| 326 | } |
| 327 | return true; |
| 328 | } |
| 329 | |
| 330 | } // namespace |
| 331 |
no test coverage detected