DeadBranchElim: Fix dead block elimination

The previous algorithm would leave invalid code in the case of unreachable
blocks pointing into a dead branch. It would leave the unreachable blocks
branching to labels that no longer exist. The previous algorithm also left
unreachable blocks in some cases (a loop following an orphaned merge block).
This fix also addresses that.

This code will soon be replaced with the coming CFG cleanup.
This commit is contained in:
GregF 2017-10-16 17:30:52 -06:00 committed by David Neto
parent 5834719fc1
commit e3a7209330
2 changed files with 51 additions and 21 deletions

View File

@ -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<ir::BasicBlock*>& structuredOrder) {
backedges_.clear();
std::unordered_set<uint32_t> 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<ir::BasicBlock*> structuredOrder;
ComputeStructuredOrder(func, &structuredOrder);
ComputeBackEdges(structuredOrder);
std::unordered_set<ir::BasicBlock*> 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<uint32_t> 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;

View File

@ -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<ir::BasicBlock*>& 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<const ir::BasicBlock*, std::vector<ir::BasicBlock*>>
block2structured_succs_;
// All backedge branches in current function
std::unordered_set<ir::Instruction*> backedges_;
// Extensions supported by this pass.
std::unordered_set<std::string> extensions_whitelist_;
};