mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
[SimplifyCFG] Teach simplifyUnreachable() to preserve DomTree
Pretty boring, removeUnwindEdge() already known how to update DomTree, so if we are to call it, we must first flush our own pending updates; otherwise, we just stop predecessors from branching to us, and for certain predecessors, stop their predecessors from branching to them also.
This commit is contained in:
parent
db36cde4ed
commit
a354d00a71
@ -4479,9 +4479,12 @@ bool SimplifyCFGOpt::simplifyUnreachable(UnreachableInst *UI) {
|
||||
if (&BB->front() != UI)
|
||||
return Changed;
|
||||
|
||||
std::vector<DominatorTree::UpdateType> Updates;
|
||||
|
||||
SmallVector<BasicBlock *, 8> Preds(pred_begin(BB), pred_end(BB));
|
||||
for (unsigned i = 0, e = Preds.size(); i != e; ++i) {
|
||||
Instruction *TI = Preds[i]->getTerminator();
|
||||
auto *Predecessor = Preds[i];
|
||||
Instruction *TI = Predecessor->getTerminator();
|
||||
IRBuilder<> Builder(TI);
|
||||
if (auto *BI = dyn_cast<BranchInst>(TI)) {
|
||||
if (BI->isUnconditional()) {
|
||||
@ -4491,6 +4494,9 @@ bool SimplifyCFGOpt::simplifyUnreachable(UnreachableInst *UI) {
|
||||
Changed = true;
|
||||
} else {
|
||||
Value* Cond = BI->getCondition();
|
||||
assert(BI->getSuccessor(0) != BI->getSuccessor(1) &&
|
||||
"Same-destination conditional branch instruction was "
|
||||
"already canonicalized into an unconditional branch.");
|
||||
if (BI->getSuccessor(0) == BB) {
|
||||
Builder.CreateAssumption(Builder.CreateNot(Cond));
|
||||
Builder.CreateBr(BI->getSuccessor(1));
|
||||
@ -4502,6 +4508,7 @@ bool SimplifyCFGOpt::simplifyUnreachable(UnreachableInst *UI) {
|
||||
EraseTerminatorAndDCECond(BI);
|
||||
Changed = true;
|
||||
}
|
||||
Updates.push_back({DominatorTree::Delete, Predecessor, BB});
|
||||
} else if (auto *SI = dyn_cast<SwitchInst>(TI)) {
|
||||
SwitchInstProfUpdateWrapper SU(*SI);
|
||||
for (auto i = SU->case_begin(), e = SU->case_end(); i != e;) {
|
||||
@ -4514,14 +4521,21 @@ bool SimplifyCFGOpt::simplifyUnreachable(UnreachableInst *UI) {
|
||||
e = SU->case_end();
|
||||
Changed = true;
|
||||
}
|
||||
Updates.push_back({DominatorTree::Delete, Predecessor, BB});
|
||||
} else if (auto *II = dyn_cast<InvokeInst>(TI)) {
|
||||
if (II->getUnwindDest() == BB) {
|
||||
removeUnwindEdge(TI->getParent());
|
||||
if (DTU)
|
||||
DTU->applyUpdatesPermissive(Updates);
|
||||
Updates.clear();
|
||||
removeUnwindEdge(TI->getParent(), DTU);
|
||||
Changed = true;
|
||||
}
|
||||
} else if (auto *CSI = dyn_cast<CatchSwitchInst>(TI)) {
|
||||
if (CSI->getUnwindDest() == BB) {
|
||||
removeUnwindEdge(TI->getParent());
|
||||
if (DTU)
|
||||
DTU->applyUpdatesPermissive(Updates);
|
||||
Updates.clear();
|
||||
removeUnwindEdge(TI->getParent(), DTU);
|
||||
Changed = true;
|
||||
continue;
|
||||
}
|
||||
@ -4536,34 +4550,53 @@ bool SimplifyCFGOpt::simplifyUnreachable(UnreachableInst *UI) {
|
||||
Changed = true;
|
||||
}
|
||||
}
|
||||
Updates.push_back({DominatorTree::Delete, Predecessor, BB});
|
||||
if (CSI->getNumHandlers() == 0) {
|
||||
BasicBlock *CatchSwitchBB = CSI->getParent();
|
||||
if (CSI->hasUnwindDest()) {
|
||||
// Redirect preds to the unwind dest
|
||||
CatchSwitchBB->replaceAllUsesWith(CSI->getUnwindDest());
|
||||
// Redirect all predecessors of the block containing CatchSwitchInst
|
||||
// to instead branch to the CatchSwitchInst's unwind destination.
|
||||
for (auto *PredecessorOfPredecessor : predecessors(Predecessor)) {
|
||||
Updates.push_back(
|
||||
{DominatorTree::Delete, PredecessorOfPredecessor, Predecessor});
|
||||
Updates.push_back({DominatorTree::Insert, PredecessorOfPredecessor,
|
||||
CSI->getUnwindDest()});
|
||||
}
|
||||
Predecessor->replaceAllUsesWith(CSI->getUnwindDest());
|
||||
} else {
|
||||
// Rewrite all preds to unwind to caller (or from invoke to call).
|
||||
SmallVector<BasicBlock *, 8> EHPreds(predecessors(CatchSwitchBB));
|
||||
if (DTU)
|
||||
DTU->applyUpdatesPermissive(Updates);
|
||||
Updates.clear();
|
||||
SmallVector<BasicBlock *, 8> EHPreds(predecessors(Predecessor));
|
||||
for (BasicBlock *EHPred : EHPreds)
|
||||
removeUnwindEdge(EHPred);
|
||||
removeUnwindEdge(EHPred, DTU);
|
||||
}
|
||||
// The catchswitch is no longer reachable.
|
||||
new UnreachableInst(CSI->getContext(), CSI);
|
||||
CSI->eraseFromParent();
|
||||
Changed = true;
|
||||
}
|
||||
} else if (isa<CleanupReturnInst>(TI)) {
|
||||
} else if (auto *CRI = dyn_cast<CleanupReturnInst>(TI)) {
|
||||
assert(CRI->hasUnwindDest() && CRI->getUnwindDest() == BB &&
|
||||
"Expected to always have an unwind to BB.");
|
||||
Updates.push_back({DominatorTree::Delete, Predecessor, BB});
|
||||
new UnreachableInst(TI->getContext(), TI);
|
||||
TI->eraseFromParent();
|
||||
Changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (DTU)
|
||||
DTU->applyUpdatesPermissive(Updates);
|
||||
|
||||
// If this block is now dead, remove it.
|
||||
if (pred_empty(BB) && BB != &BB->getParent()->getEntryBlock()) {
|
||||
// We know there are no successors, so just nuke the block.
|
||||
if (LoopHeaders)
|
||||
LoopHeaders->erase(BB);
|
||||
if (DTU)
|
||||
DTU->deleteBB(BB);
|
||||
else
|
||||
BB->eraseFromParent();
|
||||
return true;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt -S -callsite-splitting -simplifycfg < %s | FileCheck %s
|
||||
; RUN: opt -S -callsite-splitting -simplifycfg -simplifycfg-require-and-preserve-domtree=1 < %s | FileCheck %s
|
||||
|
||||
define i16 @test1() {
|
||||
; CHECK-LABEL: @test1(
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: opt < %s -inline -instcombine -jump-threading -licm -simple-loop-unswitch -instcombine -indvars -loop-deletion -gvn -simplifycfg -verify -disable-output
|
||||
; RUN: opt < %s -inline -instcombine -jump-threading -licm -simple-loop-unswitch -instcombine -indvars -loop-deletion -gvn -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -verify -disable-output
|
||||
|
||||
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
|
||||
target triple = "i386-apple-darwin9"
|
||||
|
@ -1,5 +1,5 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt < %s -simplifycfg -S | FileCheck %s
|
||||
; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
|
||||
|
||||
define void @test1(i1 %C, i1* %BP) {
|
||||
; CHECK-LABEL: @test1(
|
||||
|
@ -1,5 +1,5 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt -S -simplifycfg < %s | FileCheck %s
|
||||
; RUN: opt -S -simplifycfg -simplifycfg-require-and-preserve-domtree=1 < %s | FileCheck %s
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: opt < %s -simplifycfg -S | FileCheck %s
|
||||
; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
|
||||
|
||||
define void @test(i32* %P, i32* %Q, i1 %A, i1 %B) {
|
||||
; CHECK: test
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: opt < %s -simplifycfg -S | FileCheck %s
|
||||
; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
|
||||
|
||||
declare void @f()
|
||||
declare void @llvm.foo(i32) nounwind
|
||||
|
@ -1,5 +1,5 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt < %s -simplifycfg -S | FileCheck %s
|
||||
; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
|
||||
|
||||
declare void @llvm.lifetime.start.p0i8(i64, i8*)
|
||||
declare void @llvm.lifetime.end.p0i8(i64, i8*)
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -simplifycfg < %s | FileCheck %s
|
||||
; RUN: opt -S -simplifycfg -simplifycfg-require-and-preserve-domtree=1 < %s | FileCheck %s
|
||||
|
||||
declare i32 @f(i32 %val)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt %s -simplifycfg -S | FileCheck %s
|
||||
; RUN: opt %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
|
||||
|
||||
declare i32 @f(i32)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt %s -simplifycfg -instcombine -S | FileCheck %s
|
||||
; RUN: opt %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -instcombine -S | FileCheck %s
|
||||
|
||||
define i32 @assume1(i32 %p) {
|
||||
; CHECK-LABEL: @assume1(
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -simplifycfg < %s | FileCheck %s
|
||||
; RUN: opt -S -simplifycfg -simplifycfg-require-and-preserve-domtree=1 < %s | FileCheck %s
|
||||
|
||||
declare void @Personality()
|
||||
declare void @f()
|
||||
|
Loading…
Reference in New Issue
Block a user