[WinEHPrepare] Replace unreasonable funclet terminators with unreachable

It is possible to be in a situation where more than one funclet token is
a valid SSA value.  If we see a terminator which exits a funclet which
doesn't use the funclet's token, replace it with unreachable.

Differential Revision: http://reviews.llvm.org/D12074

llvm-svn: 245238
This commit is contained in:
David Majnemer 2015-08-17 20:56:39 +00:00
parent 196e8cd792
commit 83f4bb23c4
2 changed files with 96 additions and 37 deletions

View File

@ -3085,6 +3085,33 @@ bool WinEHPrepare::prepareExplicitEH(Function &F) {
RemapInstruction(&I, VMap, RF_IgnoreMissingEntries); RemapInstruction(&I, VMap, RF_IgnoreMissingEntries);
} }
// Remove implausible terminators and replace them with UnreachableInst.
for (auto &Funclet : FuncletBlocks) {
BasicBlock *FuncletPadBB = Funclet.first;
std::set<BasicBlock *> &BlocksInFunclet = Funclet.second;
Instruction *FirstNonPHI = FuncletPadBB->getFirstNonPHI();
auto *CatchPad = dyn_cast<CatchPadInst>(FirstNonPHI);
auto *CleanupPad = dyn_cast<CleanupPadInst>(FirstNonPHI);
for (BasicBlock *BB : BlocksInFunclet) {
TerminatorInst *TI = BB->getTerminator();
// CatchPadInst and CleanupPadInst can't transfer control to a ReturnInst.
bool IsUnreachableRet = isa<ReturnInst>(TI) && (CatchPad || CleanupPad);
// The token consumed by a CatchReturnInst must match the funclet token.
bool IsUnreachableCatchret = false;
if (auto *CRI = dyn_cast<CatchReturnInst>(TI))
IsUnreachableCatchret = CRI->getReturnValue() != CatchPad;
// The token consumed by a CleanupPadInst must match the funclet token.
bool IsUnreachableCleanupret = false;
if (auto *CRI = dyn_cast<CleanupReturnInst>(TI))
IsUnreachableCleanupret = CRI->getReturnValue() != CleanupPad;
if (IsUnreachableRet || IsUnreachableCatchret || IsUnreachableCleanupret) {
new UnreachableInst(BB->getContext(), TI);
TI->eraseFromParent();
}
}
}
// Clean-up some of the mess we made by removing useles PHI nodes, trivial // Clean-up some of the mess we made by removing useles PHI nodes, trivial
// branches, etc. // branches, etc.
for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE;) { for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE;) {
@ -3094,9 +3121,6 @@ bool WinEHPrepare::prepareExplicitEH(Function &F) {
MergeBlockIntoPredecessor(BB); MergeBlockIntoPredecessor(BB);
} }
// TODO: Do something about cleanupblocks which branch to implausible
// cleanuprets.
// We might have some unreachable blocks after cleaning up some impossible // We might have some unreachable blocks after cleaning up some impossible
// control flow. // control flow.
removeUnreachableBlocks(F); removeUnreachableBlocks(F);
@ -3215,6 +3239,12 @@ void WinEHPrepare::insertPHIStore(
void WinEHPrepare::demoteNonlocalUses(Value *V, void WinEHPrepare::demoteNonlocalUses(Value *V,
std::set<BasicBlock *> &ColorsForBB, std::set<BasicBlock *> &ColorsForBB,
Function &F) { Function &F) {
// Tokens can only be used non-locally due to control flow involving
// unreachable edges. Don't try to demote the token usage, we'll simply
// delete the cloned user later.
if (isa<CatchPadInst>(V) || isa<CleanupPadInst>(V))
return;
DenseMap<BasicBlock *, Value *> Loads; DenseMap<BasicBlock *, Value *> Loads;
AllocaInst *SpillSlot = nullptr; AllocaInst *SpillSlot = nullptr;
for (Value::use_iterator UI = V->use_begin(), UE = V->use_end(); UI != UE;) { for (Value::use_iterator UI = V->use_begin(), UE = V->use_end(); UI != UE;) {

View File

@ -36,14 +36,14 @@ merge:
; CHECK: merge: ; CHECK: merge:
; CHECK-NOT: = phi ; CHECK-NOT: = phi
%phi = phi i32 [ %x, %left ], [ %y, %right ] %phi = phi i32 [ %x, %left ], [ %y, %right ]
catchpad void [] to label %catch unwind label %catchend %cp = catchpad token [] to label %catch unwind label %catchend
catch: catch:
; CHECK: catch: ; CHECK: catch:
; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]] ; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]]
; CHECK-NEXT: call void @h(i32 [[Reload]]) ; CHECK-NEXT: call void @h(i32 [[Reload]])
call void @h(i32 %phi) call void @h(i32 %phi)
catchret void to label %exit catchret token %cp to label %exit
catchend: catchend:
catchendpad unwind to caller catchendpad unwind to caller
@ -75,9 +75,9 @@ right:
merge.inner: merge.inner:
; CHECK: merge.inner: ; CHECK: merge.inner:
; CHECK-NOT: = phi ; CHECK-NOT: = phi
; CHECK: catchpad void ; CHECK: catchpad token
%x = phi i32 [ 1, %left ], [ 2, %right ] %x = phi i32 [ 1, %left ], [ 2, %right ]
catchpad void [] to label %catch.inner unwind label %catchend.inner %cpinner = catchpad token [] to label %catch.inner unwind label %catchend.inner
catch.inner: catch.inner:
; Need just one store here because only %y is affected ; Need just one store here because only %y is affected
@ -89,16 +89,16 @@ catch.inner:
to label %catchret.inner unwind label %merge.outer to label %catchret.inner unwind label %merge.outer
catchret.inner: catchret.inner:
catchret void to label %exit catchret token %cpinner to label %exit
catchend.inner: catchend.inner:
catchendpad unwind label %merge.outer catchendpad unwind label %merge.outer
merge.outer: merge.outer:
; CHECK: merge.outer: ; CHECK: merge.outer:
; CHECK-NOT: = phi ; CHECK-NOT: = phi
; CHECK: catchpad void ; CHECK: [[CatchPad:%[^ ]+]] = catchpad token
%y = phi i32 [ %x, %catchend.inner ], [ %z, %catch.inner ] %y = phi i32 [ %x, %catchend.inner ], [ %z, %catch.inner ]
catchpad void [] to label %catch.outer unwind label %catchend.outer %cpouter = catchpad token [] to label %catch.outer unwind label %catchend.outer
catchend.outer: catchend.outer:
catchendpad unwind to caller catchendpad unwind to caller
@ -109,10 +109,10 @@ catch.outer:
; CHECK: catch.outer: ; CHECK: catch.outer:
; CHECK-DAG: load i32, i32* [[Slot1]] ; CHECK-DAG: load i32, i32* [[Slot1]]
; CHECK-DAG: load i32, i32* [[Slot2]] ; CHECK-DAG: load i32, i32* [[Slot2]]
; CHECK: catchret void to label ; CHECK: catchret token [[CatchPad]] to label
call void @h(i32 %x) call void @h(i32 %x)
call void @h(i32 %y) call void @h(i32 %y)
catchret void to label %exit catchret token %cpouter to label %exit
exit: exit:
ret void ret void
@ -131,7 +131,7 @@ entry:
to label %exit unwind label %catchpad to label %exit unwind label %catchpad
catchpad: catchpad:
catchpad void [] to label %catch unwind label %catchend %cp = catchpad token [] to label %catch unwind label %catchend
catch: catch:
; Need to reload %B here ; Need to reload %B here
@ -152,7 +152,7 @@ merge:
; CHECK: %phi = phi i32 [ [[ReloadX]], %left ] ; CHECK: %phi = phi i32 [ [[ReloadX]], %left ]
%phi = phi i32 [ %x, %left ], [ 42, %right ] %phi = phi i32 [ %x, %left ], [ 42, %right ]
call void @h(i32 %phi) call void @h(i32 %phi)
catchret void to label %exit catchret token %cp to label %exit
catchend: catchend:
catchendpad unwind to caller catchendpad unwind to caller
@ -188,11 +188,11 @@ right:
to label %join unwind label %catchpad.inner to label %join unwind label %catchpad.inner
catchpad.inner: catchpad.inner:
; CHECK: catchpad.inner: ; CHECK: catchpad.inner:
; CHECK-NEXT: catchpad void ; CHECK-NEXT: catchpad token
%phi.inner = phi i32 [ %l, %left ], [ %r, %right ] %phi.inner = phi i32 [ %l, %left ], [ %r, %right ]
catchpad void [] to label %catch.inner unwind label %catchend.inner %cp1 = catchpad token [] to label %catch.inner unwind label %catchend.inner
catch.inner: catch.inner:
catchret void to label %join catchret token %cp1 to label %join
catchend.inner: catchend.inner:
catchendpad unwind label %catchpad.outer catchendpad unwind label %catchpad.outer
join: join:
@ -205,15 +205,15 @@ join:
to label %exit unwind label %catchpad.outer to label %exit unwind label %catchpad.outer
catchpad.outer: catchpad.outer:
; CHECK: catchpad.outer: ; CHECK: catchpad.outer:
; CHECK-NEXT: catchpad void ; CHECK-NEXT: catchpad token
%phi.outer = phi i32 [ %phi.inner, %catchend.inner ], [ %j, %join ] %phi.outer = phi i32 [ %phi.inner, %catchend.inner ], [ %j, %join ]
catchpad void [] to label %catch.outer unwind label %catchend.outer %cp2 = catchpad token [] to label %catch.outer unwind label %catchend.outer
catch.outer: catch.outer:
; CHECK: catch.outer: ; CHECK: catch.outer:
; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]] ; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]]
; CHECK: call void @h(i32 [[Reload]]) ; CHECK: call void @h(i32 [[Reload]])
call void @h(i32 %phi.outer) call void @h(i32 %phi.outer)
catchret void to label %exit catchret token %cp2 to label %exit
catchend.outer: catchend.outer:
catchendpad unwind to caller catchendpad unwind to caller
exit: exit:
@ -241,10 +241,10 @@ invoke.cont:
cleanup: cleanup:
; cleanup phi can be loaded at cleanup entry ; cleanup phi can be loaded at cleanup entry
; CHECK: cleanup: ; CHECK: cleanup:
; CHECK-NEXT: cleanuppad void ; CHECK-NEXT: cleanuppad token
; CHECK: [[CleanupReload:%[^ ]+]] = load i32, i32* [[CleanupSlot]] ; CHECK: [[CleanupReload:%[^ ]+]] = load i32, i32* [[CleanupSlot]]
%phi.cleanup = phi i32 [ 1, %entry ], [ 2, %invoke.cont ] %phi.cleanup = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
cleanuppad void [] %cp = cleanuppad token []
%b = call i1 @i() %b = call i1 @i()
br i1 %b, label %left, label %right br i1 %b, label %left, label %right
@ -264,8 +264,8 @@ merge:
; need store for %phi.catch ; need store for %phi.catch
; CHECK: merge: ; CHECK: merge:
; CHECK-NEXT: store i32 [[CleanupReload]], i32* [[CatchSlot:%[^ ]+]] ; CHECK-NEXT: store i32 [[CleanupReload]], i32* [[CatchSlot:%[^ ]+]]
; CHECK-NEXT: cleanupret void ; CHECK-NEXT: cleanupret token
cleanupret void unwind label %catchpad cleanupret token %cp unwind label %catchpad
invoke.cont2: invoke.cont2:
; need store for %phi.catch ; need store for %phi.catch
@ -277,16 +277,16 @@ invoke.cont2:
catchpad: catchpad:
; CHECK: catchpad: ; CHECK: catchpad:
; CHECK-NEXT: catchpad void ; CHECK-NEXT: catchpad token
%phi.catch = phi i32 [ %phi.cleanup, %merge ], [ 3, %invoke.cont2 ] %phi.catch = phi i32 [ %phi.cleanup, %merge ], [ 3, %invoke.cont2 ]
catchpad void [] to label %catch unwind label %catchend %cp2 = catchpad token [] to label %catch unwind label %catchend
catch: catch:
; CHECK: catch: ; CHECK: catch:
; CHECK: [[CatchReload:%[^ ]+]] = load i32, i32* [[CatchSlot]] ; CHECK: [[CatchReload:%[^ ]+]] = load i32, i32* [[CatchSlot]]
; CHECK: call void @h(i32 [[CatchReload]] ; CHECK: call void @h(i32 [[CatchReload]]
call void @h(i32 %phi.catch) call void @h(i32 %phi.catch)
catchret void to label %exit catchret token %cp2 to label %exit
catchend: catchend:
catchendpad unwind to caller catchendpad unwind to caller
@ -310,8 +310,8 @@ entry:
; CHECK: store i32 %x, i32* [[SpillSlot:%[^ ]+]] ; CHECK: store i32 %x, i32* [[SpillSlot:%[^ ]+]]
; CHECK: br label %loop ; CHECK: br label %loop
to_caller: to_caller:
cleanuppad void [] %cp1 = cleanuppad token []
cleanupret void unwind to caller cleanupret token %cp1 unwind to caller
loop: loop:
invoke void @f() invoke void @f()
to label %loop unwind label %cleanup to label %loop unwind label %cleanup
@ -319,9 +319,9 @@ cleanup:
; CHECK: cleanup: ; CHECK: cleanup:
; CHECK: [[Load:%[^ ]+]] = load i32, i32* [[SpillSlot]] ; CHECK: [[Load:%[^ ]+]] = load i32, i32* [[SpillSlot]]
; CHECK: call void @h(i32 [[Load]]) ; CHECK: call void @h(i32 [[Load]])
cleanuppad void [] %cp2 = cleanuppad token []
call void @h(i32 %x) call void @h(i32 %x)
cleanupret void unwind to caller cleanupret token %cp2 unwind to caller
} }
; CHECK-LABEL: @test7( ; CHECK-LABEL: @test7(
@ -343,9 +343,9 @@ invoke.cont:
catchpad: catchpad:
; %x phi should be eliminated ; %x phi should be eliminated
; CHECK: catchpad: ; CHECK: catchpad:
; CHECK-NEXT: catchpad void ; CHECK-NEXT: %[[CatchPad:[^ ]+]] = catchpad token
%x = phi i32 [ 1, %entry ], [ 2, %invoke.cont ] %x = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
catchpad void [] to label %catch unwind label %catchend %cp = catchpad token [] to label %catch unwind label %catchend
catch: catch:
%b = call i1 @i() %b = call i1 @i()
br i1 %b, label %left, label %right br i1 %b, label %left, label %right
@ -353,8 +353,8 @@ left:
; Edge from %left to %join needs to be split so that ; Edge from %left to %join needs to be split so that
; the load of %x can be inserted *after* the catchret ; the load of %x can be inserted *after* the catchret
; CHECK: left: ; CHECK: left:
; CHECK-NEXT: catchret void to label %[[SplitLeft:[^ ]+]] ; CHECK-NEXT: catchret token %[[CatchPad]] to label %[[SplitLeft:[^ ]+]]
catchret void to label %join catchret token %cp to label %join
; CHECK: [[SplitLeft]]: ; CHECK: [[SplitLeft]]:
; CHECK: [[LoadX:%[^ ]+]] = load i32, i32* [[SlotX]] ; CHECK: [[LoadX:%[^ ]+]] = load i32, i32* [[SlotX]]
; CHECK: br label %join ; CHECK: br label %join
@ -363,9 +363,9 @@ right:
; the load of %y can be inserted *after* the catchret ; the load of %y can be inserted *after* the catchret
; CHECK: right: ; CHECK: right:
; CHECK: store i32 %y, i32* [[SlotY:%[^ ]+]] ; CHECK: store i32 %y, i32* [[SlotY:%[^ ]+]]
; CHECK: catchret void to label %[[SplitRight:[^ ]+]] ; CHECK: catchret token %[[CatchPad]] to label %[[SplitRight:[^ ]+]]
%y = call i32 @g() %y = call i32 @g()
catchret void to label %join catchret token %cp to label %join
; CHECK: [[SplitRight]]: ; CHECK: [[SplitRight]]:
; CHECK: [[LoadY:%[^ ]+]] = load i32, i32* [[SlotY]] ; CHECK: [[LoadY:%[^ ]+]] = load i32, i32* [[SlotY]]
; CHECK: br label %join ; CHECK: br label %join
@ -380,3 +380,32 @@ join:
exit: exit:
ret void ret void
} }
; CHECK-LABEL: @test8(
define void @test8() personality i32 (...)* @__CxxFrameHandler3 { entry:
invoke void @f()
to label %done unwind label %cleanup1
invoke void @f()
to label %done unwind label %cleanup2
done:
ret void
cleanup1:
; CHECK: [[CleanupPad1:%[^ ]+]] = cleanuppad token
; CHECK-NEXT: call void @f()
; CHECK-NEXT: cleanupret token [[CleanupPad1]]
%cp0 = cleanuppad token []
br label %cleanupexit
cleanup2:
; CHECK: cleanuppad token
; CHECK-NEXT: call void @f()
; CHECK-NEXT: unreachable
%cp1 = cleanuppad token []
br label %cleanupexit
cleanupexit:
call void @f()
cleanupret token %cp0 unwind label %cleanup2
}