forked from OSchip/llvm-project
[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:
parent
196e8cd792
commit
83f4bb23c4
|
@ -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;) {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue