1
0
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:
Roman Lebedev 2020-12-17 21:30:37 +03:00
parent db36cde4ed
commit a354d00a71
12 changed files with 56 additions and 23 deletions

View File

@ -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;
}

View File

@ -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(

View File

@ -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"

View File

@ -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(

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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*)

View File

@ -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)

View File

@ -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)

View File

@ -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(

View File

@ -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()