1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[WinEH] Make funclet return instrs pseudo instrs

This makes catchret look more like a branch, and less like a weird use
of BlockAddress. It also lets us get away from
llvm.x86.seh.restoreframe, which relies on the old parentfpoffset label
arithmetic.

llvm-svn: 247936
This commit is contained in:
Reid Kleckner 2015-09-17 20:43:47 +00:00
parent f2ab1ed0ec
commit 5370cf8a53
13 changed files with 139 additions and 122 deletions

View File

@ -452,6 +452,7 @@ def brcond : SDNode<"ISD::BRCOND" , SDTBrcond, [SDNPHasChain]>;
def brind : SDNode<"ISD::BRIND" , SDTBrind, [SDNPHasChain]>;
def br : SDNode<"ISD::BR" , SDTBr, [SDNPHasChain]>;
def catchret : SDNode<"ISD::CATCHRET" , SDTBr, [SDNPHasChain]>;
def cleanupret : SDNode<"ISD::CLEANUPRET" , SDTNone, [SDNPHasChain]>;
def trap : SDNode<"ISD::TRAP" , SDTNone,
[SDNPHasChain, SDNPSideEffect]>;

View File

@ -141,6 +141,41 @@ bool X86ExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
// The EH_RETURN pseudo is really removed during the MC Lowering.
return true;
}
case X86::CLEANUPRET: {
// Replace CATCHRET with the appropriate RET.
unsigned RetOp = STI->is64Bit() ? X86::RETQ : X86::RETL;
BuildMI(MBB, MBBI, DL, TII->get(RetOp));
MBBI->eraseFromParent();
return true;
}
case X86::CATCHRET: {
MachineBasicBlock *TargetMBB = MBBI->getOperand(0).getMBB();
// Fill EAX/RAX with the address of the target block.
unsigned ReturnReg = STI->is64Bit() ? X86::RAX : X86::EAX;
unsigned RetOp = STI->is64Bit() ? X86::RETQ : X86::RETL;
if (STI->is64Bit()) {
// LEA64r TargetMBB(%rip), %rax
BuildMI(MBB, MBBI, DL, TII->get(X86::LEA64r), ReturnReg)
.addReg(X86::RIP)
.addImm(0)
.addReg(0)
.addMBB(TargetMBB)
.addReg(0);
} else {
// MOV32ri $TargetMBB, %eax
BuildMI(MBB, MBBI, DL, TII->get(X86::MOV32ri))
.addReg(ReturnReg)
.addMBB(TargetMBB);
}
// Replace CATCHRET with the appropriate RET.
BuildMI(MBB, MBBI, DL, TII->get(RetOp)).addReg(ReturnReg);
MBBI->eraseFromParent();
return true;
}
}
llvm_unreachable("Previous switch has a fallthrough?");
}

View File

@ -711,7 +711,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
.addReg(MachineFramePtr, RegState::Kill)
.setMIFlag(MachineInstr::FrameSetup);
// Reset EBP / ESI to something good.
MBBI = restoreWin32EHFrameAndBasePtr(MBB, MBBI, DL);
MBBI = restoreWin32EHStackPointers(MBB, MBBI, DL);
} else {
// FIXME: Add SEH directives.
NeedsWinCFI = false;
@ -1038,9 +1038,7 @@ bool X86FrameLowering::canUseLEAForSPInEpilogue(
static bool isFuncletReturnInstr(MachineInstr *MI) {
switch (MI->getOpcode()) {
case X86::CATCHRET:
case X86::CATCHRET64:
case X86::CLEANUPRET:
case X86::CLEANUPRET64:
return true;
default:
return false;
@ -1073,13 +1071,51 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
unsigned CSSize = X86FI->getCalleeSavedFrameSize();
uint64_t NumBytes = 0;
if (isFuncletReturnInstr(MBBI)) {
if (MBBI->getOpcode() == X86::CATCHRET) {
NumBytes = MFI->getMaxCallFrameSize();
assert(hasFP(MF) && "win64 EH funclets without FP not yet implemented");
assert(hasFP(MF) && "EH funclets without FP not yet implemented");
MachineBasicBlock *TargetMBB = MBBI->getOperand(0).getMBB();
// If this is SEH, this isn't really a funclet return.
bool IsSEH = isAsynchronousEHPersonality(
classifyEHPersonality(MF.getFunction()->getPersonalityFn()));
if (IsSEH) {
if (STI.is32Bit())
restoreWin32EHStackPointers(MBB, MBBI, DL, /*RestoreSP=*/true);
BuildMI(MBB, MBBI, DL, TII.get(X86::JMP_4)).addMBB(TargetMBB);
MBBI->eraseFromParent();
return;
}
// For 32-bit, create a new block for the restore code.
MachineBasicBlock *RestoreMBB = TargetMBB;
if (STI.is32Bit()) {
RestoreMBB = MF.CreateMachineBasicBlock(MBB.getBasicBlock());
MF.insert(TargetMBB, RestoreMBB);
MBB.transferSuccessors(RestoreMBB);
MBB.addSuccessor(RestoreMBB);
MBBI->getOperand(0).setMBB(RestoreMBB);
}
// Pop EBP.
BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
MachineFramePtr).setMIFlag(MachineInstr::FrameDestroy);
MachineFramePtr)
.setMIFlag(MachineInstr::FrameDestroy);
// Insert frame restoration code in a new block.
if (STI.is32Bit()) {
auto RestoreMBBI = RestoreMBB->begin();
restoreWin32EHStackPointers(*RestoreMBB, RestoreMBBI, DL,
/*RestoreSP=*/true);
BuildMI(*RestoreMBB, RestoreMBBI, DL, TII.get(X86::JMP_4))
.addMBB(TargetMBB);
}
} else if (isFuncletReturnInstr(MBBI)) {
NumBytes = MFI->getMaxCallFrameSize();
assert(hasFP(MF) && "EH funclets without FP not yet implemented");
BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
MachineFramePtr)
.setMIFlag(MachineInstr::FrameDestroy);
} else if (hasFP(MF)) {
// Calculate required stack adjustment.
uint64_t FrameSize = StackSize - SlotSize;
@ -2067,9 +2103,9 @@ bool X86FrameLowering::canUseAsEpilogue(const MachineBasicBlock &MBB) const {
return !terminatorsNeedFlagsAsInput(MBB);
}
MachineBasicBlock::iterator X86FrameLowering::restoreWin32EHFrameAndBasePtr(
MachineBasicBlock::iterator X86FrameLowering::restoreWin32EHStackPointers(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
DebugLoc DL) const {
DebugLoc DL, bool RestoreSP) const {
assert(STI.isTargetWindowsMSVC() && "funclets only supported in MSVC env");
assert(STI.isTargetWin32() && "EBP/ESI restoration only required on win32");
assert(STI.is32Bit() && !Uses64BitFramePtr &&
@ -2087,13 +2123,22 @@ MachineBasicBlock::iterator X86FrameLowering::restoreWin32EHFrameAndBasePtr(
// FIXME: Don't set FrameSetup flag in catchret case.
int FI = FuncInfo.EHRegNodeFrameIndex;
int EHRegSize = MFI->getObjectSize(FI);
if (RestoreSP) {
// MOV32rm -EHRegSize(%ebp), %esp
addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32rm), X86::ESP),
X86::EBP, true, -EHRegSize)
.setMIFlag(MachineInstr::FrameSetup);
}
unsigned UsedReg;
int EHRegOffset = getFrameIndexReference(MF, FI, UsedReg);
int EHRegSize = MFI->getObjectSize(FI);
int EndOffset = -EHRegOffset - EHRegSize;
FuncInfo.EHRegNodeEndOffset = EndOffset;
assert(EndOffset >= 0 &&
"end of registration object above normal EBP position!");
if (UsedReg == FramePtr) {
// ADD $offset, %ebp
assert(UsedReg == FramePtr);
@ -2110,14 +2155,13 @@ MachineBasicBlock::iterator X86FrameLowering::restoreWin32EHFrameAndBasePtr(
addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::LEA32r), BasePtr),
FramePtr, false, EndOffset)
.setMIFlag(MachineInstr::FrameSetup);
// MOV32mr SavedEBPOffset(%esi), %ebp
// MOV32rm SavedEBPOffset(%esi), %ebp
assert(X86FI->getHasSEHFramePtrSave());
int Offset =
getFrameIndexReference(MF, X86FI->getSEHFramePtrSaveIndex(), UsedReg);
assert(UsedReg == BasePtr);
addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32mr)), UsedReg, true,
Offset)
.addReg(FramePtr)
addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32rm), FramePtr),
UsedReg, true, Offset)
.setMIFlag(MachineInstr::FrameSetup);
}
return MBBI;

View File

@ -158,9 +158,9 @@ private:
/// Sets up EBP and optionally ESI based on the incoming EBP value. Only
/// needed for 32-bit. Used in funclet prologues and at catchret destinations.
MachineBasicBlock::iterator
restoreWin32EHFrameAndBasePtr(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
DebugLoc DL) const;
restoreWin32EHStackPointers(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI, DebugLoc DL,
bool RestoreSP = false) const;
};
} // End llvm namespace

View File

@ -417,8 +417,6 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::SETCC , MVT::i64 , Custom);
}
setOperationAction(ISD::EH_RETURN , MVT::Other, Custom);
setOperationAction(ISD::CATCHRET , MVT::Other, Custom);
setOperationAction(ISD::CLEANUPRET , MVT::Other, Custom);
// NOTE: EH_SJLJ_SETJMP/_LONGJMP supported here is NOT intended to support
// SjLj exception handling but a light-weight setjmp/longjmp replacement to
// support continuation, user-level threading, and etc.. As a result, no
@ -16922,41 +16920,6 @@ SDValue X86TargetLowering::LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const {
DAG.getRegister(StoreAddrReg, PtrVT));
}
SDValue X86TargetLowering::LowerCATCHRET(SDValue Op, SelectionDAG &DAG) const {
SDValue Chain = Op.getOperand(0);
SDValue Dest = Op.getOperand(1);
SDLoc DL(Op);
MVT PtrVT = getPointerTy(DAG.getDataLayout());
MachineFunction &MF = DAG.getMachineFunction();
if (isAsynchronousEHPersonality(
classifyEHPersonality(MF.getFunction()->getPersonalityFn()))) {
// For SEH, codegen catchret as a branch for now.
// FIXME: Insert something to restore the frame.
return DAG.getNode(ISD::BR, DL, MVT::Other, Chain, Dest);
}
unsigned ReturnReg = (PtrVT == MVT::i64 ? X86::RAX : X86::EAX);
// Load the address of the destination block.
// FIXME: Do this without creating a BlockAddress.
MachineBasicBlock *DestMBB = cast<BasicBlockSDNode>(Dest)->getBasicBlock();
BlockAddress *BA =
BlockAddress::get(const_cast<Function *>(MF.getFunction()),
const_cast<BasicBlock *>(DestMBB->getBasicBlock()));
DestMBB->setHasAddressTaken();
SDValue BlockPtr = DAG.getBlockAddress(BA, PtrVT);
Chain = DAG.getCopyToReg(Chain, DL, ReturnReg, BlockPtr);
return DAG.getNode(X86ISD::CATCHRET, DL, MVT::Other, Chain,
DAG.getRegister(ReturnReg, PtrVT));
}
SDValue X86TargetLowering::LowerCLEANUPRET(SDValue Op, SelectionDAG &DAG) const {
return DAG.getNode(X86ISD::CLEANUPRET, SDLoc(Op), MVT::Other,
Op.getOperand(0));
}
SDValue X86TargetLowering::lowerEH_SJLJ_SETJMP(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
@ -19198,8 +19161,6 @@ SDValue X86TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
return LowerFRAME_TO_ARGS_OFFSET(Op, DAG);
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG);
case ISD::CLEANUPRET: return LowerCLEANUPRET(Op, DAG);
case ISD::CATCHRET: return LowerCATCHRET(Op, DAG);
case ISD::EH_SJLJ_SETJMP: return lowerEH_SJLJ_SETJMP(Op, DAG);
case ISD::EH_SJLJ_LONGJMP: return lowerEH_SJLJ_LONGJMP(Op, DAG);
case ISD::INIT_TRAMPOLINE: return LowerINIT_TRAMPOLINE(Op, DAG);
@ -19537,8 +19498,6 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
case X86ISD::EH_SJLJ_SETJMP: return "X86ISD::EH_SJLJ_SETJMP";
case X86ISD::EH_SJLJ_LONGJMP: return "X86ISD::EH_SJLJ_LONGJMP";
case X86ISD::EH_RETURN: return "X86ISD::EH_RETURN";
case X86ISD::CATCHRET: return "X86ISD::CATCHRET";
case X86ISD::CLEANUPRET: return "X86ISD::CLEANUPRET";
case X86ISD::TC_RETURN: return "X86ISD::TC_RETURN";
case X86ISD::FNSTCW16m: return "X86ISD::FNSTCW16m";
case X86ISD::FNSTSW16r: return "X86ISD::FNSTSW16r";

View File

@ -268,14 +268,6 @@ namespace llvm {
// Exception Handling helpers.
EH_RETURN,
// CATCHRET - Represents a return from a catch block funclet. Used for
// MSVC compatible exception handling. Takes a chain operand and RAX.
CATCHRET,
// CLEANUPRET - Represents a return from a cleanup block funclet. Used
// for MSVC compatible exception handling. Takes only a chain operand.
CLEANUPRET,
// SjLj exception handling setjmp.
EH_SJLJ_SETJMP,
@ -1014,7 +1006,6 @@ namespace llvm {
SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerCATCHRET(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerCLEANUPRET(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const;

View File

@ -153,20 +153,10 @@ def EH_RETURN64 : I<0xC3, RawFrm, (outs), (ins GR64:$addr),
}
let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1, isCodeGenOnly = 1, isReturn = 1 in {
def CATCHRET : I<0xC3, RawFrm, (outs), (ins GR32:$addr),
"ret{l}\t# CATCHRET",
[(X86catchret GR32:$addr)], IIC_RET>, Sched<[WriteJumpLd]>;
def CATCHRET64 : I<0xC3, RawFrm, (outs), (ins GR64:$addr),
"ret{q}\t# CATCHRET",
[(X86catchret GR64:$addr)], IIC_RET>, Sched<[WriteJumpLd]>;
def CLEANUPRET : I<0xC3, RawFrm, (outs), (ins),
"ret{l}\t# CLEANUPRET",
[(X86cleanupret)], IIC_RET>, Sched<[WriteJumpLd]>,
Requires<[Not64BitMode]>;
def CLEANUPRET64 : I<0xC3, RawFrm, (outs), (ins),
"ret{q}\t# CLEANUPRET",
[(X86cleanupret)], IIC_RET>, Sched<[WriteJumpLd]>,
Requires<[In64BitMode]>;
def CATCHRET : I<0, Pseudo, (outs), (ins brtarget32:$dst),
"# CATCHRET",
[(catchret bb:$dst)]>;
def CLEANUPRET : I<0, Pseudo, (outs), (ins), "# CLEANUPRET", [(cleanupret)]>;
}
let hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1,

View File

@ -205,10 +205,6 @@ def X86tlsbaseaddr : SDNode<"X86ISD::TLSBASEADDR", SDT_X86TLSBASEADDR,
def X86ehret : SDNode<"X86ISD::EH_RETURN", SDT_X86EHRET,
[SDNPHasChain]>;
def X86catchret : SDNode<"X86ISD::CATCHRET", SDT_X86EHRET, [SDNPHasChain]>;
def X86cleanupret : SDNode<"X86ISD::CLEANUPRET", SDTX86Void, [SDNPHasChain]>;
def X86eh_sjlj_setjmp : SDNode<"X86ISD::EH_SJLJ_SETJMP",
SDTypeProfile<1, 1, [SDTCisInt<0>,
SDTCisPtrTy<1>]>,

View File

@ -531,13 +531,6 @@ ReSimplify:
break;
}
case X86::CATCHRET:
case X86::CATCHRET64: {
OutMI = MCInst();
OutMI.setOpcode(getRetOpcode(AsmPrinter.getSubtarget()));
break;
}
// TAILJMPd, TAILJMPd64 - Lower to the correct jump instructions.
case X86::TAILJMPr:
case X86::TAILJMPd:

View File

@ -500,15 +500,6 @@ void WinEHStatePass::addStateStoresToFunclet(Value *ParentRegNode,
insertStateNumberStore(ParentRegNode, II, State);
}
}
// Insert calls to llvm.x86.seh.restoreframe at catchret destinations. In
// SEH, insert them before the catchret.
// FIXME: We should probably do this as part of catchret lowering in the
// DAG.
if (auto *CR = dyn_cast<CatchReturnInst>(BB.getTerminator()))
insertRestoreFrame(Personality == EHPersonality::MSVC_X86SEH
? CR->getParent()
: CR->getSuccessor());
}
}

View File

@ -59,9 +59,7 @@ catchendblock: ; preds = %catch,
; X86: movl $0, -{{[0-9]+}}(%ebp)
; X86: movl $1, (%esp)
; X86: calll _f
; X86: [[contbb:Ltmp[0-9]+]]: # Block address taken
; X86: movl -{{[0-9]+}}(%ebp), %esp
; X86: addl ${{[0-9]+}}, %esp
; X86: [[contbb:LBB0_[0-9]+]]: # %try.cont
; X86: popl %esi
; X86: popl %edi
; X86: popl %ebx
@ -76,11 +74,17 @@ catchendblock: ; preds = %catch,
; X86: movl $1, -{{[0-9]+}}(%ebp)
; X86: movl $2, (%esp)
; X86: calll _f
; X86: movl $[[contbb]], %eax
; X86-NEXT: addl $16, %esp
; X86: addl $16, %esp
; X86-NEXT: popl %ebp
; X86-NEXT: movl $[[restorebb:LBB0_[0-9]+]], %eax
; X86-NEXT: retl
; FIXME: Lay this out in the parent funclet.
; X86: [[restorebb]]:
; X86: movl -16(%ebp), %esp
; X86: addl $12, %ebp
; X86: jmp [[contbb]]
; X86: L__ehtable$try_catch_catch:
; X86: $handlerMap$0$try_catch_catch:
; X86: .long 0
@ -108,7 +112,7 @@ catchendblock: ; preds = %catch,
; X64: callq useints
; X64: movl $1, %ecx
; X64: callq f
; X64: [[contbb:.Ltmp[0-9]+]]: # Block address taken
; X64: [[contbb:\.LBB0_[0-9]+]]: # %try.cont
; X64: addq $40, %rsp
; X64: popq %rbp
; X64: retq
@ -120,9 +124,9 @@ catchendblock: ; preds = %catch,
; X64: subq $32, %rsp
; X64: movl $2, %ecx
; X64: callq f
; X64: leaq [[contbb]](%rip), %rax
; X64: addq $32, %rsp
; X64: popq %rbp
; X64: leaq [[contbb]](%rip), %rax
; X64: retq
; X64: $handlerMap$0$try_catch_catch:

View File

@ -70,8 +70,7 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X86-DAG: movl %[[addr_reg]], 4(%esp)
; X86-DAG: movl $1, (%esp)
; X86: calll _f
; X86: [[contbb:Ltmp[0-9]+]]: # Block address taken
; X86: movl -{{[0-9]+}}(%ebp), %esp
; X86: [[contbb:LBB0_[0-9]+]]: # %try.cont
; X86: retl
; X86: [[catch1bb:LBB0_[0-9]+]]: # %catch{{$}}
@ -84,9 +83,9 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X86-DAG: movl %[[addr_reg]], 4(%esp)
; X86-DAG: movl %[[e_reg]], (%esp)
; X86: calll _f
; X86: movl $[[contbb]], %eax
; X86-NEXT: addl $8, %esp
; X86-NEXT: popl %ebp
; X86-NEXT: movl $[[restorebb:LBB0_[0-9]+]], %eax
; X86-NEXT: retl
; X86: [[catch2bb:LBB0_[0-9]+]]: # %catch.2{{$}}
@ -98,11 +97,17 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X86-DAG: movl %[[addr_reg]], 4(%esp)
; X86-DAG: movl $3, (%esp)
; X86: calll _f
; X86: movl $[[contbb]], %eax
; X86-NEXT: addl $8, %esp
; X86-NEXT: popl %ebp
; X86-NEXT: movl $[[restorebb]], %eax
; X86-NEXT: retl
; FIXME: We should lay this code out up with the parent function.
; X86: [[restorebb]]:
; X86: movl -16(%ebp), %esp
; X86: addl $12, %ebp
; X86: jmp [[contbb]]
; X86: L__ehtable$try_catch_catch:
; X86: $handlerMap$0$try_catch_catch:
; X86-NEXT: .long 0
@ -124,7 +129,7 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X64-DAG: leaq -[[local_offs:[0-9]+]](%rbp), %rdx
; X64-DAG: movl $1, %ecx
; X64: callq f
; X64: [[contbb:.Ltmp[0-9]+]]: # Block address taken
; X64: [[contbb:\.LBB0_[0-9]+]]: # %try.cont
; X64: addq $48, %rsp
; X64: popq %rbp
; X64: retq
@ -137,10 +142,10 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X64-DAG: leaq -[[local_offs]](%rbp), %rdx
; X64-DAG: movl [[e_addr:[-0-9]+]](%rbp), %ecx
; X64: callq f
; X64: leaq [[contbb]](%rip), %rax
; X64: addq $32, %rsp
; X64: popq %rbp
; X64: retq
; X64-NEXT: popq %rbp
; X64-NEXT: leaq [[contbb]](%rip), %rax
; X64-NEXT: retq
; X64: [[catch2bb:\.LBB0_[0-9]+]]: # %catch.2{{$}}
; X64: movq %rdx, 16(%rsp)
@ -150,10 +155,10 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X64-DAG: leaq -[[local_offs]](%rbp), %rdx
; X64-DAG: movl $3, %ecx
; X64: callq f
; X64: leaq [[contbb]](%rip), %rax
; X64: addq $32, %rsp
; X64: popq %rbp
; X64: retq
; X64-NEXT: popq %rbp
; X64-NEXT: leaq [[contbb]](%rip), %rax
; X64-NEXT: retq
; X64: $handlerMap$0$try_catch_catch:
; X64: .long 0

View File

@ -66,14 +66,18 @@ cleanup.outer: ; preds = %invoke.cont.1, %c
; X86: calll _f
; X86: LBB1_[[cleanup_inner:[0-9]+]]: # %cleanup.inner
; X86: pushl %ebp
; X86: leal {{.*}}(%ebp), %ecx
; X86: calll "??1Dtor@@QAE@XZ"
; X86: retl # CLEANUPRET
; X86: popl %ebp
; X86: retl
; X86: LBB1_[[cleanup_outer:[0-9]+]]: # %cleanup.outer
; X86: pushl %ebp
; X86: leal {{.*}}(%ebp), %ecx
; X86: calll "??1Dtor@@QAE@XZ"
; X86: retl # CLEANUPRET
; X86: popl %ebp
; X86: retl
; X86: L__ehtable$nested_cleanup:
; X86: .long 429065506
@ -100,14 +104,18 @@ cleanup.outer: ; preds = %invoke.cont.1, %c
; X64: callq f
; X64: .LBB1_[[cleanup_inner:[0-9]+]]: # %cleanup.inner
; X64: pushq %rbp
; X64: leaq {{.*}}(%rbp), %rcx
; X64: callq "??1Dtor@@QAE@XZ"
; X64: retq # CLEANUPRET
; X64: popq %rbp
; X64: retq
; X64: .LBB1_[[cleanup_outer:[0-9]+]]: # %cleanup.outer
; X64: pushq %rbp
; X64: leaq {{.*}}(%rbp), %rcx
; X64: callq "??1Dtor@@QAE@XZ"
; X64: retq # CLEANUPRET
; X64: popq %rbp
; X64: retq
; X64: .seh_handlerdata
; X64: .long ($cppxdata$nested_cleanup)@IMGREL