diff --git a/source/opt/dead_branch_elim_pass.cpp b/source/opt/dead_branch_elim_pass.cpp index 6af103ccc..44e4f903f 100644 --- a/source/opt/dead_branch_elim_pass.cpp +++ b/source/opt/dead_branch_elim_pass.cpp @@ -24,6 +24,7 @@ namespace opt { namespace { +const uint32_t kBranchTargetLabIdInIdx = 0; const uint32_t kBranchCondTrueLabIdInIdx = 1; const uint32_t kBranchCondFalseLabIdInIdx = 2; const uint32_t kSelectionMergeMergeBlockIdInIdx = 0; @@ -190,20 +191,57 @@ bool DeadBranchElimPass::GetSelectionBranch(ir::BasicBlock* bp, return true; } -bool DeadBranchElimPass::HasNonPhiRef(uint32_t labelId) { +bool DeadBranchElimPass::HasNonPhiNonBackedgeRef(uint32_t labelId) { analysis::UseList* uses = def_use_mgr_->GetUses(labelId); if (uses == nullptr) return false; - for (auto u : *uses) - if (u.inst->opcode() != SpvOpPhi) + for (auto u : *uses) { + if (u.inst->opcode() != SpvOpPhi && + backedges_.find(u.inst) == backedges_.end()) return true; + } return false; } +void DeadBranchElimPass::ComputeBackEdges( + std::list& structuredOrder) { + backedges_.clear(); + std::unordered_set visited; + // In structured order, edges to visited blocks are back edges + for (auto bi = structuredOrder.begin(); bi != structuredOrder.end(); ++bi) { + visited.insert((*bi)->id()); + auto ii = (*bi)->end(); + --ii; + switch(ii->opcode()) { + case SpvOpBranch: { + const uint32_t labId = ii->GetSingleWordInOperand( + kBranchTargetLabIdInIdx); + if (visited.find(labId) != visited.end()) + backedges_.insert(&*ii); + } break; + case SpvOpBranchConditional: { + const uint32_t tLabId = ii->GetSingleWordInOperand( + kBranchCondTrueLabIdInIdx); + if (visited.find(tLabId) != visited.end()) { + backedges_.insert(&*ii); + break; + } + const uint32_t fLabId = ii->GetSingleWordInOperand( + kBranchCondFalseLabIdInIdx); + if (visited.find(fLabId) != visited.end()) + backedges_.insert(&*ii); + } break; + default: + break; + } + } +} + bool DeadBranchElimPass::EliminateDeadBranches(ir::Function* func) { // Traverse blocks in structured order std::list structuredOrder; ComputeStructuredOrder(func, &structuredOrder); + ComputeBackEdges(structuredOrder); std::unordered_set elimBlocks; bool modified = false; for (auto bi = structuredOrder.begin(); bi != structuredOrder.end(); ++bi) { @@ -265,37 +303,23 @@ bool DeadBranchElimPass::EliminateDeadBranches(ir::Function* func) { modified = true; - // Initialize live block set to the live label - std::unordered_set liveLabIds; - liveLabIds.insert(liveLabId); - // Iterate to merge block adding dead blocks to elimination set auto dbi = bi; ++dbi; uint32_t dLabId = (*dbi)->id(); while (dLabId != mergeLabId) { - if (liveLabIds.find(dLabId) == liveLabIds.end()) { + if (!HasNonPhiNonBackedgeRef(dLabId)) { // Kill use/def for all instructions and mark block for elimination KillAllInsts(*dbi); elimBlocks.insert(*dbi); } - else { - // Mark all successors as live - (*dbi)->ForEachSuccessorLabel([&liveLabIds](const uint32_t succId){ - liveLabIds.insert(succId); - }); - // Mark merge and continue blocks as live - (*dbi)->ForMergeAndContinueLabel([&liveLabIds](const uint32_t succId){ - liveLabIds.insert(succId); - }); - } ++dbi; dLabId = (*dbi)->id(); } // If merge block is unreachable, continue eliminating blocks until // a live block or last block is reached. - while (!HasNonPhiRef(dLabId)) { + while (!HasNonPhiNonBackedgeRef(dLabId)) { KillAllInsts(*dbi); elimBlocks.insert(*dbi); ++dbi; diff --git a/source/opt/dead_branch_elim_pass.h b/source/opt/dead_branch_elim_pass.h index bbff303e3..0b0f25d79 100644 --- a/source/opt/dead_branch_elim_pass.h +++ b/source/opt/dead_branch_elim_pass.h @@ -97,8 +97,11 @@ class DeadBranchElimPass : public MemPass { bool GetSelectionBranch(ir::BasicBlock* bp, ir::Instruction** branchInst, ir::Instruction** mergeInst, uint32_t *condId); - // Return true if |labelId| has any non-phi references - bool HasNonPhiRef(uint32_t labelId); + // Return true if |labelId| has any non-phi, non-backedge references + bool HasNonPhiNonBackedgeRef(uint32_t labelId); + + // Compute backedges for blocks in |structuredOrder|. + void ComputeBackEdges(std::list& structuredOrder); // For function |func|, look for BranchConditionals with constant condition // and convert to a Branch to the indicated label. Delete resulting dead @@ -125,6 +128,9 @@ class DeadBranchElimPass : public MemPass { std::unordered_map> block2structured_succs_; + // All backedge branches in current function + std::unordered_set backedges_; + // Extensions supported by this pass. std::unordered_set extensions_whitelist_; };