[WinEH] Disable most forms of demotion

Now that the register allocator knows about the barriers on funclet
entry and exit, testing has shown that this is unnecessary.

We still demote PHIs on unsplittable blocks due to the differences
between the IR CFG and the Machine CFG.

llvm-svn: 253619
This commit is contained in:
Reid Kleckner 2015-11-19 23:23:33 +00:00
parent 9d47212194
commit cc2f6c35a3
5 changed files with 81 additions and 256 deletions

View File

@ -69,8 +69,6 @@ private:
AllocaInst *insertPHILoads(PHINode *PN, Function &F);
void replaceUseWithLoad(Value *V, Use &U, AllocaInst *&SpillSlot,
DenseMap<BasicBlock *, Value *> &Loads, Function &F);
void demoteNonlocalUses(Value *V, SetVector<BasicBlock *> &ColorsForBB,
Function &F);
bool prepareExplicitEH(Function &F,
SmallVectorImpl<BasicBlock *> &EntryBlocks);
void replaceTerminatePadWithCleanup(Function &F);
@ -90,8 +88,6 @@ private:
std::map<BasicBlock *, BasicBlock *> &Orig2Clone);
void demotePHIsOnFunclets(Function &F);
void demoteUsesBetweenFunclets(Function &F);
void demoteArgumentUses(Function &F);
void cloneCommonBlocks(Function &F,
SmallVectorImpl<BasicBlock *> &EntryBlocks);
void removeImplausibleTerminators(Function &F);
@ -1588,30 +1584,6 @@ void WinEHPrepare::demotePHIsOnFunclets(Function &F) {
}
}
void WinEHPrepare::demoteUsesBetweenFunclets(Function &F) {
// Turn all inter-funclet uses of a Value into loads and stores.
for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE;) {
BasicBlock *BB = &*FI++;
SetVector<BasicBlock *> &ColorsForBB = BlockColors[BB];
for (BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE;) {
Instruction *I = &*BI++;
// Funclets are permitted to use static allocas.
if (auto *AI = dyn_cast<AllocaInst>(I))
if (AI->isStaticAlloca())
continue;
demoteNonlocalUses(I, ColorsForBB, F);
}
}
}
void WinEHPrepare::demoteArgumentUses(Function &F) {
// Also demote function parameters used in funclets.
SetVector<BasicBlock *> &ColorsForEntry = BlockColors[&F.getEntryBlock()];
for (Argument &Arg : F.args())
demoteNonlocalUses(&Arg, ColorsForEntry, F);
}
void WinEHPrepare::cloneCommonBlocks(
Function &F, SmallVectorImpl<BasicBlock *> &EntryBlocks) {
// We need to clone all blocks which belong to multiple funclets. Values are
@ -1914,12 +1886,10 @@ void WinEHPrepare::verifyPreparedFunclets(Function &F) {
report_fatal_error("Uncolored BB!");
if (NumColors > 1)
report_fatal_error("Multicolor BB!");
if (!DisableDemotion) {
bool EHPadHasPHI = BB.isEHPad() && isa<PHINode>(BB.begin());
assert(!EHPadHasPHI && "EH Pad still has a PHI!");
if (EHPadHasPHI)
report_fatal_error("EH Pad still has a PHI!");
}
bool EHPadHasPHI = BB.isEHPad() && isa<PHINode>(BB.begin());
assert(!EHPadHasPHI && "EH Pad still has a PHI!");
if (EHPadHasPHI)
report_fatal_error("EH Pad still has a PHI!");
}
}
@ -1930,14 +1900,9 @@ bool WinEHPrepare::prepareExplicitEH(
// Determine which blocks are reachable from which funclet entries.
colorFunclets(F, EntryBlocks);
if (!DisableDemotion) {
if (!DisableDemotion)
demotePHIsOnFunclets(F);
demoteUsesBetweenFunclets(F);
demoteArgumentUses(F);
}
cloneCommonBlocks(F, EntryBlocks);
resolveFuncletAncestry(F, EntryBlocks);
@ -2050,83 +2015,6 @@ void WinEHPrepare::insertPHIStore(
new StoreInst(PredVal, SpillSlot, PredBlock->getTerminator());
}
// The SetVector == operator uses the std::vector == operator, so it doesn't
// actually tell us whether or not the two sets contain the same colors. This
// function does that.
// FIXME: Would it be better to add a isSetEquivalent() method to SetVector?
static bool isBlockColorSetEquivalent(SetVector<BasicBlock *> &SetA,
SetVector<BasicBlock *> &SetB) {
if (SetA.size() != SetB.size())
return false;
for (auto *Color : SetA)
if (!SetB.count(Color))
return false;
return true;
}
// TODO: Share loads for same-funclet uses (requires dominators if funclets
// aren't properly nested).
void WinEHPrepare::demoteNonlocalUses(Value *V,
SetVector<BasicBlock *> &ColorsForBB,
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;
AllocaInst *SpillSlot = nullptr;
for (Value::use_iterator UI = V->use_begin(), UE = V->use_end(); UI != UE;) {
Use &U = *UI++;
auto *UsingInst = cast<Instruction>(U.getUser());
BasicBlock *UsingBB = UsingInst->getParent();
// Is the Use inside a block which is colored the same as the Def?
// If so, we don't need to escape the Def because we will clone
// ourselves our own private copy.
SetVector<BasicBlock *> &ColorsForUsingBB = BlockColors[UsingBB];
if (isBlockColorSetEquivalent(ColorsForUsingBB, ColorsForBB))
continue;
replaceUseWithLoad(V, U, SpillSlot, Loads, F);
}
if (SpillSlot) {
// Insert stores of the computed value into the stack slot.
// We have to be careful if I is an invoke instruction,
// because we can't insert the store AFTER the terminator instruction.
BasicBlock::iterator InsertPt;
if (isa<Argument>(V)) {
InsertPt = F.getEntryBlock().getTerminator()->getIterator();
} else if (isa<TerminatorInst>(V)) {
auto *II = cast<InvokeInst>(V);
// We cannot demote invoke instructions to the stack if their normal
// edge is critical. Therefore, split the critical edge and create a
// basic block into which the store can be inserted.
if (!II->getNormalDest()->getSinglePredecessor()) {
unsigned SuccNum =
GetSuccessorNumber(II->getParent(), II->getNormalDest());
assert(isCriticalEdge(II, SuccNum) && "Expected a critical edge!");
BasicBlock *NewBlock = SplitCriticalEdge(II, SuccNum);
assert(NewBlock && "Unable to split critical edge.");
// Update the color mapping for the newly split edge.
SetVector<BasicBlock *> &ColorsForUsingBB = BlockColors[II->getParent()];
BlockColors[NewBlock] = ColorsForUsingBB;
for (BasicBlock *FuncletPad : ColorsForUsingBB)
FuncletBlocks[FuncletPad].insert(NewBlock);
}
InsertPt = II->getNormalDest()->getFirstInsertionPt();
} else {
InsertPt = cast<Instruction>(V)->getIterator();
++InsertPt;
// Don't insert before PHI nodes or EH pad instrs.
for (; isa<PHINode>(InsertPt) || InsertPt->isEHPad(); ++InsertPt)
;
}
new StoreInst(V, SpillSlot, &*InsertPt);
}
}
void WinEHPrepare::replaceUseWithLoad(Value *V, Use &U, AllocaInst *&SpillSlot,
DenseMap<BasicBlock *, Value *> &Loads,
Function &F) {

View File

@ -29,18 +29,16 @@ endcatch:
; for the use in entry's copy.
; CHECK-LABEL: define void @test1(
; CHECK: entry:
; CHECK: store i32 %x, i32* [[Slot:%[^ ]+]]
; CHECK: %x = call i32 @g()
; CHECK: invoke void @f()
; CHECK: to label %[[EntryCopy:[^ ]+]] unwind label %catch
; CHECK: catch:
; CHECK: catchpad []
; CHECK-NEXT: to label %[[CatchCopy:[^ ]+]] unwind
; CHECK: [[CatchCopy]]:
; CHECK: [[LoadX2:%[^ ]+]] = load i32, i32* [[Slot]]
; CHECK: call void @h(i32 [[LoadX2]]
; CHECK: call void @h(i32 %x)
; CHECK: [[EntryCopy]]:
; CHECK: [[LoadX1:%[^ ]+]] = load i32, i32* [[Slot]]
; CHECK: call void @h(i32 [[LoadX1]]
; CHECK: call void @h(i32 %x)
define void @test2() personality i32 (...)* @__CxxFrameHandler3 {
@ -281,12 +279,14 @@ exit:
; then calls @h, and that the call to @h doesn't return.
; CHECK-LABEL: define void @test6(
; CHECK: left:
; CHECK: %x.for.left = call i32 @g()
; CHECK: invoke void @f()
; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
; CHECK: right:
; CHECK: catchpad
; CHECK: to label %right.catch unwind label %right.end
; CHECK: right.catch:
; CHECK: %x = call i32 @g()
; CHECK: store i32 %x, i32* %x.wineh.spillslot
; CHECK: to label %shared.cont unwind label %[[INNER_RIGHT:.+]]
; CHECK: right.end:
; CHECK: catchendpad unwind to caller
@ -296,13 +296,11 @@ exit:
; CHECK: unreachable
; CHECK: [[INNER_RIGHT]]:
; CHECK: [[I_R:\%.+]] = cleanuppad []
; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_R]])
; CHECK: call void @h(i32 %x)
; CHECK: cleanupret [[I_R]] unwind label %right.end
; CHECK: [[INNER_LEFT]]:
; CHECK: [[I_L:\%.+]] = cleanuppad []
; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_L]])
; CHECK: call void @h(i32 %x.for.left)
; CHECK: unreachable

View File

@ -118,49 +118,6 @@ exit:
ret void
}
; CHECK-LABEL: @test3(
define void @test3(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
entry:
; need to spill parameter %B and def %x since they're used in a funclet
; CHECK: entry:
; CHECK-DAG: store i1 %B, i1* [[SlotB:%[^ ]+]]
; CHECK-DAG: store i32 %x, i32* [[SlotX:%[^ ]+]]
; CHECK: invoke void @f
%x = call i32 @g()
invoke void @f()
to label %exit unwind label %catchpad
catchpad:
%cp = catchpad [] to label %catch unwind label %catchend
catch:
; Need to reload %B here
; CHECK: catch:
; CHECK: [[ReloadB:%[^ ]+]] = load i1, i1* [[SlotB]]
; CHECK: br i1 [[ReloadB]]
br i1 %B, label %left, label %right
left:
; Use of %x is in a phi, so need reload here in pred
; CHECK: left:
; CHECK: [[ReloadX:%[^ ]+]] = load i32, i32* [[SlotX]]
; CHECK: br label %merge
br label %merge
right:
br label %merge
merge:
; CHECK: merge:
; CHECK: %phi = phi i32 [ [[ReloadX]], %left ]
%phi = phi i32 [ %x, %left ], [ 42, %right ]
call void @h(i32 %phi)
catchret %cp to label %exit
catchend:
catchendpad unwind to caller
exit:
ret void
}
; test4: don't need stores for %phi.inner, as its only use is to feed %phi.outer
; %phi.outer needs stores in %left, %right, and %join
; CHECK-LABEL: @test4(
@ -295,20 +252,15 @@ exit:
ret void
}
; We used to demote %x, but we don't need to anymore.
; CHECK-LABEL: @test6(
define void @test6() personality i32 (...)* @__CxxFrameHandler3 {
entry:
; Since %x needs to be stored but the edge to loop is critical,
; it needs to be split
; CHECK: entry:
; CHECK: invoke i32 @g
; CHECK-NEXT: to label %[[SplitBlock:[^ ]+]] unwind label %to_caller
; CHECK: %x = invoke i32 @g()
; CHECK-NEXT: to label %loop unwind label %to_caller
%x = invoke i32 @g()
to label %loop unwind label %to_caller
; The store should be in the split block
; CHECK: [[SplitBlock]]:
; CHECK: store i32 %x, i32* [[SpillSlot:%[^ ]+]]
; CHECK: br label %loop
to_caller:
%cp1 = cleanuppad []
cleanupret %cp1 unwind to caller
@ -317,8 +269,7 @@ loop:
to label %loop unwind label %cleanup
cleanup:
; CHECK: cleanup:
; CHECK: [[Load:%[^ ]+]] = load i32, i32* [[SpillSlot]]
; CHECK: call void @h(i32 [[Load]])
; CHECK: call void @h(i32 %x)
%cp2 = cleanuppad []
call void @h(i32 %x)
cleanupret %cp2 unwind to caller
@ -362,18 +313,15 @@ right:
; Edge from %right to %join needs to be split so that
; the load of %y can be inserted *after* the catchret
; CHECK: right:
; CHECK: store i32 %y, i32* [[SlotY:%[^ ]+]]
; CHECK: catchret %[[CatchPad]] to label %[[SplitRight:[^ ]+]]
; CHECK: %y = call i32 @g()
; CHECK: catchret %[[CatchPad]] to label %join
%y = call i32 @g()
catchret %cp to label %join
; CHECK: [[SplitRight]]:
; CHECK: [[LoadY:%[^ ]+]] = load i32, i32* [[SlotY]]
; CHECK: br label %join
catchend:
catchendpad unwind to caller
join:
; CHECK: join:
; CHECK: %phi = phi i32 [ [[LoadX]], %[[SplitLeft]] ], [ [[LoadY]], %[[SplitRight]] ]
; CHECK: %phi = phi i32 [ [[LoadX]], %[[SplitLeft]] ], [ %y, %right ]
%phi = phi i32 [ %x, %left ], [ %y, %right ]
call void @h(i32 %phi)
br label %exit

View File

@ -51,12 +51,14 @@ exit:
; then calls @h, and that the call to @h doesn't return.
; CHECK-LABEL: define void @test1(
; CHECK: left:
; CHECK: cleanuppad
; CHECK: %x.for.left = call i32 @g()
; CHECK: invoke void @f()
; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
; CHECK: right:
; CHECK: to label %right.catch unwind label %right.end
; CHECK: right.catch:
; CHECK: %x = call i32 @g()
; CHECK: store i32 %x, i32* %x.wineh.spillslot
; CHECK: to label %shared.cont unwind label %[[INNER_RIGHT:.+]]
; CHECK: right.end:
; CHECK: catchendpad unwind to caller
@ -66,13 +68,11 @@ exit:
; CHECK: unreachable
; CHECK: [[INNER_RIGHT]]:
; CHECK: [[I_R:\%.+]] = cleanuppad []
; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_R]])
; CHECK: call void @h(i32 %x)
; CHECK: cleanupret [[I_R]] unwind label %right.end
; CHECK: [[INNER_LEFT]]:
; CHECK: [[I_L:\%.+]] = cleanuppad []
; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_L]])
; CHECK: call void @h(i32 %x.for.left)
; CHECK: unreachable
@ -118,6 +118,9 @@ exit:
; %right.end (which belongs to the entry funclet).
; CHECK-LABEL: define void @test2(
; CHECK: left:
; CHECK: cleanuppad
; CHECK: %x.for.left = call i32 @g()
; CHECK: invoke void @f()
; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
; CHECK: right:
; CHECK: to label %right.catch unwind label %[[RIGHT_END:.+]]
@ -136,12 +139,10 @@ exit:
; CHECK: catchpad []
; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
; CHECK: [[INNER_CATCH_RIGHT]]:
; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_R]])
; CHECK: call void @h(i32 %x)
; CHECK: unreachable
; CHECK: [[INNER_CATCH_LEFT]]:
; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_L]])
; CHECK: call void @h(i32 %x.for.left)
; CHECK: unreachable
; CHECK: [[INNER_END_LEFT]]:
; CHECK: catchendpad unwind to caller
@ -190,6 +191,8 @@ exit:
; CHECK-LABEL: define void @test3(
; CHECK: left:
; CHECK: %l = cleanuppad []
; CHECK: %x.for.left = call i32 @g()
; CHECK: invoke void @f()
; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
; CHECK: [[LEFT_END:left.end.*]]:
; CHECK: cleanupendpad %l unwind label %right
@ -210,12 +213,10 @@ exit:
; CHECK: catchpad []
; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
; CHECK: [[INNER_CATCH_RIGHT]]:
; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_R]])
; CHECK: call void @h(i32 %x)
; CHECK: unreachable
; CHECK: [[INNER_CATCH_LEFT]]:
; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_R]])
; CHECK: call void @h(i32 %x.for.left)
; CHECK: unreachable
; CHECK: [[INNER_END_LEFT]]:
; CHECK: catchendpad unwind label %[[LEFT_END]]
@ -270,6 +271,8 @@ exit:
; CHECK: catchpad []
; CHECK: to label %left.catch unwind label %[[LEFT_END:.+]]
; CHECK: left.catch:
; CHECK: %x.for.left = call i32 @g()
; CHECK: invoke void @f()
; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
; CHECK: [[LEFT_END]]:
; CHECK: catchendpad unwind label %right
@ -290,12 +293,10 @@ exit:
; CHECK: catchpad []
; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
; CHECK: [[INNER_CATCH_RIGHT]]:
; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_R]])
; CHECK: call void @h(i32 %x)
; CHECK: unreachable
; CHECK: [[INNER_CATCH_LEFT]]:
; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_L]])
; CHECK: call void @h(i32 %x.for.left)
; CHECK: unreachable
; CHECK: [[INNER_END_RIGHT]]:
; CHECK: catchendpad unwind to caller
@ -362,12 +363,10 @@ exit:
; CHECK: catchpad []
; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
; CHECK: [[INNER_CATCH_RIGHT]]:
; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_R]])
; CHECK: call void @h(i32 %x)
; CHECK: unreachable
; CHECK: [[INNER_CATCH_LEFT]]:
; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_L]])
; CHECK: call void @h(i32 %x.for.left)
; CHECK: unreachable
; CHECK: [[INNER_END_RIGHT]]:
; CHECK: catchendpad unwind to caller
@ -446,12 +445,10 @@ exit:
; CHECK: catchpad []
; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
; CHECK: [[INNER_CATCH_RIGHT]]:
; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_R]])
; CHECK: call void @h(i32 %x)
; CHECK: unreachable
; CHECK: [[INNER_CATCH_LEFT]]:
; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_L]])
; CHECK: call void @h(i32 %x.for.left)
; CHECK: unreachable
; CHECK: [[INNER_END_RIGHT]]:
; CHECK: catchendpad unwind to caller
@ -522,12 +519,10 @@ exit:
; CHECK: catchpad []
; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
; CHECK: [[INNER_CATCH_RIGHT]]:
; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_R]])
; CHECK: call void @h(i32 %x)
; CHECK: unreachable
; CHECK: [[INNER_CATCH_LEFT]]:
; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_L]])
; CHECK: call void @h(i32 %x.for.left)
; CHECK: unreachable
; CHECK: [[INNER_END_RIGHT]]:
; CHECK: catchendpad unwind label %[[INNER_SIBLING_RIGHT:.+]]
@ -803,12 +798,10 @@ exit:
; CHECK: catchpad []
; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
; CHECK: [[INNER_CATCH_RIGHT]]:
; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_R]])
; CHECK: call void @h(i32 %x)
; CHECK: unreachable
; CHECK: [[INNER_CATCH_LEFT]]:
; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_L]])
; CHECK: call void @h(i32 %x.for.left)
; CHECK: unreachable
; CHECK: [[INNER_END_RIGHT]]:
; CHECK: catchendpad unwind to caller
@ -875,12 +868,10 @@ exit:
; CHECK: catchpad []
; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
; CHECK: [[INNER_CATCH_RIGHT]]:
; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_R]])
; CHECK: call void @h(i32 %x)
; CHECK: unreachable
; CHECK: [[INNER_CATCH_LEFT]]:
; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
; CHECK: call void @h(i32 [[X_RELOAD_L]])
; CHECK: call void @h(i32 %x.for.left)
; CHECK: unreachable
; CHECK: [[INNER_END_RIGHT]]:
; CHECK: catchendpad unwind label %[[RIGHT_END]]

View File

@ -35,40 +35,34 @@ return: ; preds = %entry, %catch
; X64-LABEL: .seh_proc f
; X64: pushq %rbp
; X64: pushq %rsi
; X64: subq $56, %rsp
; X64: leaq 48(%rsp), %rbp
; X64: movq $-2, (%rbp)
; X64: subq $64, %rsp
; X64: leaq 64(%rsp), %rbp
; X64: movq $-2, -8(%rbp)
; X64: movl $-1, -20(%rbp) # 4-byte Folded Spill
; X64: callq g
; X64: movl %esi, %eax
; X64: addq $56, %rsp
; X64: popq %rsi
; X64: .LBB0_1
; X64: movl -20(%rbp), %eax # 4-byte Reload
; X64: addq $64, %rsp
; X64: popq %rbp
; X64: movl -4(%rbp), %esi
; X64: jmp
; X64-LABEL: "?catch$1@?0?f@4HA":
; X64: .seh_proc "?catch$1@?0?f@4HA"
; X64-LABEL: "?catch${{[0-9]}}@?0?f@4HA":
; X64: .seh_proc "?catch${{[0-9]}}@?0?f@4HA"
; X64: movq %rdx, 16(%rsp)
; X64: pushq %rbp
; X64: pushq %rsi
; X64: subq $40, %rsp
; X64: leaq 48(%rdx), %rbp
; X64: subq $32, %rsp
; X64: leaq 64(%rdx), %rbp
; arg2 is at RBP+40:
; start at arg2
; + 8 for arg1
; + 8 for retaddr
; + 8 for RBP
; + 8 for RSI
; + 56 for stackalloc
; - 48 for setframe
; + 64 for stackalloc
; - 64 for setframe
; = 40
; X64: movl 40(%rbp), %eax
; X64: movl %eax, -4(%rbp)
; X64: leaq .LBB0_2(%rip), %rax
; X64: addq $40, %rsp
; X64: popq %rsi
; X64: movl 24(%rbp), %eax
; X64: movl %eax, -20(%rbp) # 4-byte Spill
; X64: leaq .LBB0_1(%rip), %rax
; X64: addq $32, %rsp
; X64: popq %rbp
; X64: retq # CATCHRET
@ -78,27 +72,33 @@ return: ; preds = %entry, %catch
; X86: pushl %ebx
; X86: pushl %edi
; X86: pushl %esi
; X86: subl $28, %esp
; X86: movl $-1, -40(%ebp)
; X86: subl $24, %esp
; X86: movl $-1, -36(%ebp)
; X86: calll _g
; X86: movl -40(%ebp), %eax
; X86: addl $28, %esp
; X86: LBB0_[[retbb:[0-9]+]]:
; X86: movl -36(%ebp), %eax
; X86: addl $24, %esp
; X86: popl %esi
; X86: popl %edi
; X86: popl %ebx
; X86: popl %ebp
; X86: retl
; X86-LABEL: "?catch$1@?0?f@4HA":
; X86: pushl %ebp
; X86: addl $12, %ebp
; X86: LBB0_[[restorebb:[0-9]+]]: # Block address taken
; X86: addl $12, %ebp
; arg2 is at EBP offset 12:
; + 4 for arg1
; + 4 for retaddr
; + 4 for EBP
; X86: movl 12(%ebp), %eax
; X86: movl %eax, -36(%ebp)
; X86: jmp LBB0_[[retbb]]
; X86-LABEL: "?catch${{[0-9]}}@?0?f@4HA":
; X86: pushl %ebp
; X86: addl $12, %ebp
; Done due to mov %esp, %ebp
; X86: movl 12(%ebp), %eax
; X86: movl %eax, -32(%ebp)
; X86: movl $LBB0_2, %eax
; X86: leal 12(%ebp), %eax
; X86: movl $LBB0_[[restorebb]], %eax
; X86: popl %ebp
; X86: retl # CATCHRET