[LICM] sink through non-trivially replicable PHI

Summary:
The current LICM allows sinking an instruction only when it is exposed to exit
blocks through a trivially replacable PHI of which all incoming values are the
same instruction. This change enhance LICM to sink a sinkable instruction
through non-trivially replacable PHIs by spliting predecessors of loop
exits.

Reviewers: hfinkel, majnemer, davidxl, bmakam, mcrosier, danielcdh, efriedma, jtony

Reviewed By: efriedma

Subscribers: nemanjai, dberlin, llvm-commits

Differential Revision: https://reviews.llvm.org/D37163

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@317335 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Jun Bum Lim
2017-11-03 16:24:53 +00:00
parent d16b502afd
commit 7c2eb4ec8b
3 changed files with 431 additions and 65 deletions
+144 -60
View File
@@ -62,6 +62,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/LoopPassManager.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/LoopUtils.h"
#include "llvm/Transforms/Utils/SSAUpdater.h"
@@ -93,9 +94,8 @@ static bool isNotUsedInLoop(const Instruction &I, const Loop *CurLoop,
static bool hoist(Instruction &I, const DominatorTree *DT, const Loop *CurLoop,
const LoopSafetyInfo *SafetyInfo,
OptimizationRemarkEmitter *ORE);
static bool sink(Instruction &I, const LoopInfo *LI, const DominatorTree *DT,
const Loop *CurLoop, AliasSetTracker *CurAST,
const LoopSafetyInfo *SafetyInfo,
static bool sink(Instruction &I, LoopInfo *LI, DominatorTree *DT,
const Loop *CurLoop, const LoopSafetyInfo *SafetyInfo,
OptimizationRemarkEmitter *ORE);
static bool isSafeToExecuteUnconditionally(Instruction &Inst,
const DominatorTree *DT,
@@ -394,8 +394,12 @@ bool llvm::sinkRegion(DomTreeNode *N, AliasAnalysis *AA, LoopInfo *LI,
//
if (isNotUsedInLoop(I, CurLoop, SafetyInfo) &&
canSinkOrHoistInst(I, AA, DT, CurLoop, CurAST, SafetyInfo, ORE)) {
++II;
Changed |= sink(I, LI, DT, CurLoop, CurAST, SafetyInfo, ORE);
if (sink(I, LI, DT, CurLoop, SafetyInfo, ORE)) {
++II;
CurAST->deleteValue(&I);
I.eraseFromParent();
Changed = true;
}
}
}
}
@@ -717,26 +721,6 @@ static bool isNotUsedInLoop(const Instruction &I, const Loop *CurLoop,
if (!BlockColors.empty() &&
BlockColors.find(const_cast<BasicBlock *>(BB))->second.size() != 1)
return false;
// A PHI node where all of the incoming values are this instruction are
// special -- they can just be RAUW'ed with the instruction and thus
// don't require a use in the predecessor. This is a particular important
// special case because it is the pattern found in LCSSA form.
if (isTriviallyReplacablePHI(*PN, I)) {
if (CurLoop->contains(PN))
return false;
else
continue;
}
// Otherwise, PHI node uses occur in predecessor blocks if the incoming
// values. Check for such a use being inside the loop.
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i)
if (PN->getIncomingValue(i) == &I)
if (CurLoop->contains(PN->getIncomingBlock(i)))
return false;
continue;
}
if (CurLoop->contains(UI))
@@ -806,14 +790,96 @@ CloneInstructionInExitBlock(Instruction &I, BasicBlock &ExitBlock, PHINode &PN,
return New;
}
static Instruction *sinkThroughTriviallyReplacablePHI(
PHINode *TPN, Instruction *I, LoopInfo *LI,
SmallDenseMap<BasicBlock *, Instruction *, 32> &SunkCopies,
const LoopSafetyInfo *SafetyInfo, const Loop *CurLoop) {
assert(isTriviallyReplacablePHI(*TPN, *I) &&
"Expect only trivially replacalbe PHI");
BasicBlock *ExitBlock = TPN->getParent();
Instruction *New;
auto It = SunkCopies.find(ExitBlock);
if (It != SunkCopies.end())
New = It->second;
else
New = SunkCopies[ExitBlock] =
CloneInstructionInExitBlock(*I, *ExitBlock, *TPN, LI, SafetyInfo);
return New;
}
static bool canSplitPredecessors(PHINode *PN) {
BasicBlock *BB = PN->getParent();
if (!BB->canSplitPredecessors())
return false;
for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) {
BasicBlock *BBPred = *PI;
if (isa<IndirectBrInst>(BBPred->getTerminator()))
return false;
}
return true;
}
static void splitPredecessorsOfLoopExit(PHINode *PN, DominatorTree *DT,
LoopInfo *LI, const Loop *CurLoop) {
#ifndef NDEBUG
SmallVector<BasicBlock *, 32> ExitBlocks;
CurLoop->getUniqueExitBlocks(ExitBlocks);
SmallPtrSet<BasicBlock *, 32> ExitBlockSet(ExitBlocks.begin(),
ExitBlocks.end());
#endif
BasicBlock *ExitBB = PN->getParent();
assert(ExitBlockSet.count(ExitBB) && "Expect the PHI is in an exit block.");
// Split predecessors of the loop exit to make instructions in the loop are
// exposed to exit blocks through trivially replacable PHIs while keeping the
// loop in the canonical form where each predecessor of each exit block should
// be contained within the loop. For example, this will convert the loop below
// from
//
// LB1:
// %v1 =
// br %LE, %LB2
// LB2:
// %v2 =
// br %LE, %LB1
// LE:
// %p = phi [%v1, %LB1], [%v2, %LB2] <-- non-trivially replacable
//
// to
//
// LB1:
// %v1 =
// br %LE.split, %LB2
// LB2:
// %v2 =
// br %LE.split2, %LB1
// LE.split:
// %p1 = phi [%v1, %LB1] <-- trivially replacable
// br %LE
// LE.split2:
// %p2 = phi [%v2, %LB2] <-- trivially replacable
// br %LE
// LE:
// %p = phi [%p1, %LE.split], [%p2, %LE.split2]
//
SmallSetVector<BasicBlock *, 8> PredBBs(pred_begin(ExitBB), pred_end(ExitBB));
while (!PredBBs.empty()) {
BasicBlock *PredBB = *PredBBs.begin();
assert(CurLoop->contains(PredBB) &&
"Expect all predecessors are in the loop");
if (PN->getBasicBlockIndex(PredBB) >= 0)
SplitBlockPredecessors(ExitBB, PredBB, ".split.loop.exit", DT, LI, true);
PredBBs.remove(PredBB);
}
}
/// When an instruction is found to only be used outside of the loop, this
/// function moves it to the exit blocks and patches up SSA form as needed.
/// This method is guaranteed to remove the original instruction from its
/// position, and may either delete it or move it to outside of the loop.
///
static bool sink(Instruction &I, const LoopInfo *LI, const DominatorTree *DT,
const Loop *CurLoop, AliasSetTracker *CurAST,
const LoopSafetyInfo *SafetyInfo,
static bool sink(Instruction &I, LoopInfo *LI, DominatorTree *DT,
const Loop *CurLoop, const LoopSafetyInfo *SafetyInfo,
OptimizationRemarkEmitter *ORE) {
DEBUG(dbgs() << "LICM sinking instruction: " << I << "\n");
ORE->emit([&]() {
@@ -828,6 +894,51 @@ static bool sink(Instruction &I, const LoopInfo *LI, const DominatorTree *DT,
++NumSunk;
Changed = true;
// Iterate over users to be ready for actual sinking. Replace users via
// unrechable blocks with undef and make all user PHIs trivially replcable.
SmallPtrSet<Instruction *, 8> VisitedUsers;
for (Value::user_iterator UI = I.user_begin(), UE = I.user_end(); UI != UE;) {
auto *User = cast<Instruction>(*UI);
Use &U = UI.getUse();
++UI;
if (VisitedUsers.count(User))
continue;
if (!DT->isReachableFromEntry(User->getParent())) {
User->replaceUsesOfWith(&I, UndefValue::get(I.getType()));
continue;
}
// The user must be a PHI node.
PHINode *PN = cast<PHINode>(User);
// Surprisingly, instructions can be used outside of loops without any
// exits. This can only happen in PHI nodes if the incoming block is
// unreachable.
BasicBlock *BB = PN->getIncomingBlock(U);
if (!DT->isReachableFromEntry(BB)) {
U = UndefValue::get(I.getType());
continue;
}
VisitedUsers.insert(PN);
if (isTriviallyReplacablePHI(*PN, I))
continue;
if (!canSplitPredecessors(PN))
return false;
// Split predecessors of the PHI so that we can make users trivially
// replacable.
splitPredecessorsOfLoopExit(PN, DT, LI, CurLoop);
// Should rebuild the iterators, as they may be invalidated by
// splitPredecessorsOfLoopExit().
UI = I.user_begin();
UE = I.user_end();
}
#ifndef NDEBUG
SmallVector<BasicBlock *, 32> ExitBlocks;
CurLoop->getUniqueExitBlocks(ExitBlocks);
@@ -843,42 +954,15 @@ static bool sink(Instruction &I, const LoopInfo *LI, const DominatorTree *DT,
// the instruction.
while (!I.use_empty()) {
Value::user_iterator UI = I.user_begin();
auto *User = cast<Instruction>(*UI);
if (!DT->isReachableFromEntry(User->getParent())) {
User->replaceUsesOfWith(&I, UndefValue::get(I.getType()));
continue;
}
// The user must be a PHI node.
PHINode *PN = cast<PHINode>(User);
// Surprisingly, instructions can be used outside of loops without any
// exits. This can only happen in PHI nodes if the incoming block is
// unreachable.
Use &U = UI.getUse();
BasicBlock *BB = PN->getIncomingBlock(U);
if (!DT->isReachableFromEntry(BB)) {
U = UndefValue::get(I.getType());
continue;
}
BasicBlock *ExitBlock = PN->getParent();
assert(ExitBlockSet.count(ExitBlock) &&
PHINode *PN = cast<PHINode>(*UI);
assert(ExitBlockSet.count(PN->getParent()) &&
"The LCSSA PHI is not in an exit block!");
Instruction *New;
auto It = SunkCopies.find(ExitBlock);
if (It != SunkCopies.end())
New = It->second;
else
New = SunkCopies[ExitBlock] =
CloneInstructionInExitBlock(I, *ExitBlock, *PN, LI, SafetyInfo);
// The PHI must be trivially replacable.
Instruction *New = sinkThroughTriviallyReplacablePHI(PN, &I, LI, SunkCopies,
SafetyInfo, CurLoop);
PN->replaceAllUsesWith(New);
PN->eraseFromParent();
}
CurAST->deleteValue(&I);
I.eraseFromParent();
return Changed;
}
+4 -4
View File
@@ -1,5 +1,5 @@
; RUN: llc -verify-machineinstrs -mcpu=pwr7 < %s | FileCheck %s
; RUN: llc -verify-machineinstrs -mcpu=pwr7 -ppc-gen-isel=false < %s | FileCheck --check-prefix=CHECK-NO-ISEL %s
; RUN: llc -verify-machineinstrs -mcpu=pwr7 -ppc-gep-opt=0 < %s | FileCheck %s
; RUN: llc -verify-machineinstrs -mcpu=pwr7 -ppc-gen-isel=false -ppc-gep-opt=0 < %s | FileCheck --check-prefix=CHECK-NO-ISEL %s
target datalayout = "E-m:e-i64:64-n32:64"
target triple = "powerpc64-unknown-linux-gnu"
@@ -38,10 +38,10 @@ while.end418: ; preds = %wait_on_buffer.exit
; CHECK: stdcx.
; CHECK: isel {{[0-9]+}}, {{[0-9]+}}, {{[0-9]+}}, [[REG]]
; CHECK-NO-ISEL: bc 12, 20, [[TRUE:.LBB[0-9]+]]
; CHECK-NO-ISEL: ori 4, 7, 0
; CHECK-NO-ISEL: ori 7, 8, 0
; CHECK-NO-ISEL-NEXT: b [[SUCCESSOR:.LBB[0-9]+]]
; CHECK-NO-ISEL: [[TRUE]]
; CHECK-NO-ISEL-NEXT: addi 4, 3, 0
; CHECK-NO-ISEL: addi 7, 3, 0
if.then420: ; preds = %while.end418
unreachable
+283 -1
View File
@@ -392,6 +392,288 @@ lab60:
indirectbr i8* undef, [label %lab21, label %lab19]
}
declare void @f(i32*)
; Check if LICM can sink a sinkable instruction the exit blocks through
; a non-trivially replacable PHI node.
;
; CHECK-LABEL: @test14
; CHECK-LABEL: Loop:
; CHECK-NOT: mul
; CHECK-NOT: sub
;
; CHECK-LABEL: Out12.split.loop.exit:
; CHECK: %[[LCSSAPHI:.*]] = phi i32 [ %N_addr.0.pn, %ContLoop ]
; CHECK: %[[MUL:.*]] = mul i32 %N, %[[LCSSAPHI]]
; CHECK: br label %Out12
;
; CHECK-LABEL: Out12.split.loop.exit1:
; CHECK: %[[LCSSAPHI2:.*]] = phi i32 [ %N_addr.0.pn, %Loop ]
; CHECK: %[[MUL2:.*]] = mul i32 %N, %[[LCSSAPHI2]]
; CHECK: %[[SUB:.*]] = sub i32 %[[MUL2]], %N
; CHECK: br label %Out12
;
; CHECK-LABEL: Out12:
; CHECK: phi i32 [ %[[MUL]], %Out12.split.loop.exit ], [ %[[SUB]], %Out12.split.loop.exit1 ]
define i32 @test14(i32 %N, i32 %N2, i1 %C) {
Entry:
br label %Loop
Loop:
%N_addr.0.pn = phi i32 [ %dec, %ContLoop ], [ %N, %Entry ]
%sink.mul = mul i32 %N, %N_addr.0.pn
%sink.sub = sub i32 %sink.mul, %N
%dec = add i32 %N_addr.0.pn, -1
br i1 %C, label %ContLoop, label %Out12
ContLoop:
%tmp.1 = icmp ne i32 %N_addr.0.pn, 1
br i1 %tmp.1, label %Loop, label %Out12
Out12:
%tmp = phi i32 [%sink.mul, %ContLoop], [%sink.sub, %Loop]
ret i32 %tmp
}
; In this test, splitting predecessors is not really required because the
; operations of sinkable instructions (sub and mul) are same. In this case, we
; can sink the same sinkable operations and modify the PHI to pass the operands
; to the shared operations. As of now, we split predecessors of non-trivially
; replicalbe PHIs by default in LICM because all incoming edges of a
; non-trivially replacable PHI in LCSSA is critical.
;
; CHECK-LABEL: @test15
; CHECK-LABEL: Loop:
; CHECK-NOT: mul
; CHECK-NOT: sub
;
; CHECK-LABEL: Out12.split.loop.exit:
; CHECK: %[[LCSSAPHI:.*]] = phi i32 [ %N_addr.0.pn, %ContLoop ]
; CHECK: %[[MUL:.*]] = mul i32 %N, %[[LCSSAPHI]]
; CHECK: %[[SUB:.*]] = sub i32 %[[MUL]], %N2
; CHECK: br label %Out12
;
; CHECK-LABEL: Out12.split.loop.exit1:
; CHECK: %[[LCSSAPHI2:.*]] = phi i32 [ %N_addr.0.pn, %Loop ]
; CHECK: %[[MUL2:.*]] = mul i32 %N, %[[LCSSAPHI2]]
; CHECK: %[[SUB2:.*]] = sub i32 %[[MUL2]], %N
; CHECK: br label %Out12
;
; CHECK-LABEL: Out12:
; CHECK: phi i32 [ %[[SUB]], %Out12.split.loop.exit ], [ %[[SUB2]], %Out12.split.loop.exit1 ]
define i32 @test15(i32 %N, i32 %N2, i1 %C) {
Entry:
br label %Loop
Loop:
%N_addr.0.pn = phi i32 [ %dec, %ContLoop ], [ %N, %Entry ]
%sink.mul = mul i32 %N, %N_addr.0.pn
%sink.sub = sub i32 %sink.mul, %N
%sink.sub2 = sub i32 %sink.mul, %N2
%dec = add i32 %N_addr.0.pn, -1
br i1 %C, label %ContLoop, label %Out12
ContLoop:
%tmp.1 = icmp ne i32 %N_addr.0.pn, 1
br i1 %tmp.1, label %Loop, label %Out12
Out12:
%tmp = phi i32 [%sink.sub2, %ContLoop], [%sink.sub, %Loop]
ret i32 %tmp
}
; Sink through a non-trivially replacable PHI node which use the same sinkable
; instruction multiple times.
;
; CHECK-LABEL: @test16
; CHECK-LABEL: Loop:
; CHECK-NOT: mul
;
; CHECK-LABEL: Out.split.loop.exit:
; CHECK: %[[PHI:.*]] = phi i32 [ %l2, %ContLoop ]
; CHECK: br label %Out
;
; CHECK-LABEL: Out.split.loop.exit1:
; CHECK: %[[SINKABLE:.*]] = mul i32 %l2.lcssa, %t.le
; CHECK: br label %Out
;
; CHECK-LABEL: Out:
; CHECK: %idx = phi i32 [ %[[PHI]], %Out.split.loop.exit ], [ %[[SINKABLE]], %Out.split.loop.exit1 ]
define i32 @test16(i1 %c, i8** %P, i32* %P2, i64 %V) {
entry:
br label %loop.ph
loop.ph:
br label %Loop
Loop:
%iv = phi i64 [ 0, %loop.ph ], [ %next, %ContLoop ]
%l2 = call i32 @getv()
%t = trunc i64 %iv to i32
%sinkable = mul i32 %l2, %t
switch i32 %l2, label %ContLoop [
i32 32, label %Out
i32 46, label %Out
i32 95, label %Out
]
ContLoop:
%next = add nuw i64 %iv, 1
%c1 = call i1 @getc()
br i1 %c1, label %Loop, label %Out
Out:
%idx = phi i32 [ %l2, %ContLoop ], [ %sinkable, %Loop ], [ %sinkable, %Loop ], [ %sinkable, %Loop ]
ret i32 %idx
}
; Sink a sinkable instruction through multiple non-trivially replacable PHIs in
; differect exit blocks.
;
; CHECK-LABEL: @test17
; CHECK-LABEL: Loop:
; CHECK-NOT: mul
;
; CHECK-LABEL:OutA.split.loop.exit{{.*}}:
; CHECK: %[[OP1:.*]] = phi i32 [ %N_addr.0.pn, %ContLoop1 ]
; CHECK: %[[SINKABLE:.*]] = mul i32 %N, %[[OP1]]
; CHECK: br label %OutA
;
; CHECK-LABEL:OutA:
; CHECK: phi i32{{.*}}[ %[[SINKABLE]], %OutA.split.loop.exit{{.*}} ]
;
; CHECK-LABEL:OutB.split.loop.exit{{.*}}:
; CHECK: %[[OP2:.*]] = phi i32 [ %N_addr.0.pn, %ContLoop2 ]
; CHECK: %[[SINKABLE2:.*]] = mul i32 %N, %[[OP2]]
; CHECK: br label %OutB
;
; CHECK-LABEL:OutB:
; CHECK: phi i32 {{.*}}[ %[[SINKABLE2]], %OutB.split.loop.exit{{.*}} ]
define i32 @test17(i32 %N, i32 %N2) {
Entry:
br label %Loop
Loop:
%N_addr.0.pn = phi i32 [ %dec, %ContLoop3 ], [ %N, %Entry ]
%sink.mul = mul i32 %N, %N_addr.0.pn
%c0 = call i1 @getc()
br i1 %c0 , label %ContLoop1, label %OutA
ContLoop1:
%c1 = call i1 @getc()
br i1 %c1, label %ContLoop2, label %OutA
ContLoop2:
%c2 = call i1 @getc()
br i1 %c2, label %ContLoop3, label %OutB
ContLoop3:
%c3 = call i1 @getc()
%dec = add i32 %N_addr.0.pn, -1
br i1 %c3, label %Loop, label %OutB
OutA:
%tmp1 = phi i32 [%sink.mul, %ContLoop1], [%N2, %Loop]
br label %Out12
OutB:
%tmp2 = phi i32 [%sink.mul, %ContLoop2], [%dec, %ContLoop3]
br label %Out12
Out12:
%tmp = phi i32 [%tmp1, %OutA], [%tmp2, %OutB]
ret i32 %tmp
}
; Sink a sinkable instruction through both trivially and non-trivially replacable PHIs.
;
; CHECK-LABEL: @test18
; CHECK-LABEL: Loop:
; CHECK-NOT: mul
; CHECK-NOT: sub
;
; CHECK-LABEL:Out12.split.loop.exit:
; CHECK: %[[OP:.*]] = phi i32 [ %iv, %ContLoop ]
; CHECK: %[[DEC:.*]] = phi i32 [ %dec, %ContLoop ]
; CHECK: %[[SINKMUL:.*]] = mul i32 %N, %[[OP]]
; CHECK: %[[SINKSUB:.*]] = sub i32 %[[SINKMUL]], %N2
; CHECK: br label %Out12
;
; CHECK-LABEL:Out12.split.loop.exit1:
; CHECK: %[[OP2:.*]] = phi i32 [ %iv, %Loop ]
; CHECK: %[[SINKMUL2:.*]] = mul i32 %N, %[[OP2]]
; CHECK: %[[SINKSUB2:.*]] = sub i32 %[[SINKMUL2]], %N2
; CHECK: br label %Out12
;
; CHECK-LABEL:Out12:
; CHECK: %tmp1 = phi i32 [ %[[SINKSUB]], %Out12.split.loop.exit ], [ %[[SINKSUB2]], %Out12.split.loop.exit1 ]
; CHECK: %tmp2 = phi i32 [ %[[DEC]], %Out12.split.loop.exit ], [ %[[SINKSUB2]], %Out12.split.loop.exit1 ]
; CHECK: %add = add i32 %tmp1, %tmp2
define i32 @test18(i32 %N, i32 %N2) {
Entry:
br label %Loop
Loop:
%iv = phi i32 [ %dec, %ContLoop ], [ %N, %Entry ]
%sink.mul = mul i32 %N, %iv
%sink.sub = sub i32 %sink.mul, %N2
%c0 = call i1 @getc()
br i1 %c0, label %ContLoop, label %Out12
ContLoop:
%dec = add i32 %iv, -1
%c1 = call i1 @getc()
br i1 %c1, label %Loop, label %Out12
Out12:
%tmp1 = phi i32 [%sink.sub, %ContLoop], [%sink.sub, %Loop]
%tmp2 = phi i32 [%dec, %ContLoop], [%sink.sub, %Loop]
%add = add i32 %tmp1, %tmp2
ret i32 %add
}
; Do not sink an instruction through a non-trivially replacable PHI, to avoid
; assert while splitting predecessors, if the terminator of predecessor is an
; indirectbr.
; CHECK-LABEL: @test19
; CHECK-LABEL: L0:
; CHECK: %sinkable = mul
; CHECK: %sinkable2 = add
define i32 @test19(i1 %cond, i1 %cond2, i8* %address, i32 %v1) nounwind {
entry:
br label %L0
L0:
%indirect.goto.dest = select i1 %cond, i8* blockaddress(@test19, %exit), i8* %address
%v2 = call i32 @getv()
%sinkable = mul i32 %v1, %v2
%sinkable2 = add i32 %v1, %v2
indirectbr i8* %indirect.goto.dest, [label %L1, label %exit]
L1:
%indirect.goto.dest2 = select i1 %cond2, i8* blockaddress(@test19, %exit), i8* %address
indirectbr i8* %indirect.goto.dest2, [label %L0, label %exit]
exit:
%r = phi i32 [%sinkable, %L0], [%sinkable2, %L1]
ret i32 %r
}
; Do not sink through a non-trivially replacable PHI if splitting predecessors
; not allowed in SplitBlockPredecessors().
;
; CHECK-LABEL: @test20
; CHECK-LABEL: while.cond
; CHECK: %sinkable = mul
; CHECK: %sinkable2 = add
define void @test20(i32* %s, i1 %b, i32 %v1, i32 %v2) personality i32 (...)* @__CxxFrameHandler3 {
entry:
br label %while.cond
while.cond:
%v = call i32 @getv()
%sinkable = mul i32 %v, %v2
%sinkable2 = add i32 %v, %v2
br i1 %b, label %try.cont, label %while.body
while.body:
invoke void @may_throw()
to label %while.body2 unwind label %catch.dispatch
while.body2:
invoke void @may_throw2()
to label %while.cond unwind label %catch.dispatch
catch.dispatch:
%.lcssa1 = phi i32 [ %sinkable, %while.body ], [ %sinkable2, %while.body2 ]
%cp = cleanuppad within none []
store i32 %.lcssa1, i32* %s
cleanupret from %cp unwind to caller
try.cont:
ret void
}
declare void @may_throw()
declare void @may_throw2()
declare i32 @__CxxFrameHandler3(...)
declare i32 @getv()
declare i1 @getc()
declare void @f(i32*)
declare void @g()