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);
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);
}
}
-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
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!");
}
}
// 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);
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) {
; 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 {
; 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
; 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
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(
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
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
; 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
; 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
; 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
; %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:.+]]
; 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
; 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
; 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]]
; 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
; 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
; 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
; 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
; 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:.+]]
; 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
; 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]]
; 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
; 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