llvm.org GIT mirror llvm / f946dd0
[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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@247936 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 4 years ago
13 changed file(s) with 139 addition(s) and 122 deletion(s). Raw diff Collapse all Expand all
451451 def brind : SDNode<"ISD::BRIND" , SDTBrind, [SDNPHasChain]>;
452452 def br : SDNode<"ISD::BR" , SDTBr, [SDNPHasChain]>;
453453 def catchret : SDNode<"ISD::CATCHRET" , SDTBr, [SDNPHasChain]>;
454 def cleanupret : SDNode<"ISD::CLEANUPRET" , SDTNone, [SDNPHasChain]>;
454455
455456 def trap : SDNode<"ISD::TRAP" , SDTNone,
456457 [SDNPHasChain, SDNPSideEffect]>;
140140 // The EH_RETURN pseudo is really removed during the MC Lowering.
141141 return true;
142142 }
143
144 case X86::CLEANUPRET: {
145 // Replace CATCHRET with the appropriate RET.
146 unsigned RetOp = STI->is64Bit() ? X86::RETQ : X86::RETL;
147 BuildMI(MBB, MBBI, DL, TII->get(RetOp));
148 MBBI->eraseFromParent();
149 return true;
150 }
151
152 case X86::CATCHRET: {
153 MachineBasicBlock *TargetMBB = MBBI->getOperand(0).getMBB();
154
155 // Fill EAX/RAX with the address of the target block.
156 unsigned ReturnReg = STI->is64Bit() ? X86::RAX : X86::EAX;
157 unsigned RetOp = STI->is64Bit() ? X86::RETQ : X86::RETL;
158 if (STI->is64Bit()) {
159 // LEA64r TargetMBB(%rip), %rax
160 BuildMI(MBB, MBBI, DL, TII->get(X86::LEA64r), ReturnReg)
161 .addReg(X86::RIP)
162 .addImm(0)
163 .addReg(0)
164 .addMBB(TargetMBB)
165 .addReg(0);
166 } else {
167 // MOV32ri $TargetMBB, %eax
168 BuildMI(MBB, MBBI, DL, TII->get(X86::MOV32ri))
169 .addReg(ReturnReg)
170 .addMBB(TargetMBB);
171 }
172
173 // Replace CATCHRET with the appropriate RET.
174 BuildMI(MBB, MBBI, DL, TII->get(RetOp)).addReg(ReturnReg);
175 MBBI->eraseFromParent();
176 return true;
177 }
143178 }
144179 llvm_unreachable("Previous switch has a fallthrough?");
145180 }
710710 .addReg(MachineFramePtr, RegState::Kill)
711711 .setMIFlag(MachineInstr::FrameSetup);
712712 // Reset EBP / ESI to something good.
713 MBBI = restoreWin32EHFrameAndBasePtr(MBB, MBBI, DL);
713 MBBI = restoreWin32EHStackPointers(MBB, MBBI, DL);
714714 } else {
715715 // FIXME: Add SEH directives.
716716 NeedsWinCFI = false;
10371037 static bool isFuncletReturnInstr(MachineInstr *MI) {
10381038 switch (MI->getOpcode()) {
10391039 case X86::CATCHRET:
1040 case X86::CATCHRET64:
10411040 case X86::CLEANUPRET:
1042 case X86::CLEANUPRET64:
10431041 return true;
10441042 default:
10451043 return false;
10721070 unsigned CSSize = X86FI->getCalleeSavedFrameSize();
10731071 uint64_t NumBytes = 0;
10741072
1075 if (isFuncletReturnInstr(MBBI)) {
1073 if (MBBI->getOpcode() == X86::CATCHRET) {
10761074 NumBytes = MFI->getMaxCallFrameSize();
1077 assert(hasFP(MF) && "win64 EH funclets without FP not yet implemented");
1075 assert(hasFP(MF) && "EH funclets without FP not yet implemented");
1076 MachineBasicBlock *TargetMBB = MBBI->getOperand(0).getMBB();
1077
1078 // If this is SEH, this isn't really a funclet return.
1079 bool IsSEH = isAsynchronousEHPersonality(
1080 classifyEHPersonality(MF.getFunction()->getPersonalityFn()));
1081 if (IsSEH) {
1082 if (STI.is32Bit())
1083 restoreWin32EHStackPointers(MBB, MBBI, DL, /*RestoreSP=*/true);
1084 BuildMI(MBB, MBBI, DL, TII.get(X86::JMP_4)).addMBB(TargetMBB);
1085 MBBI->eraseFromParent();
1086 return;
1087 }
1088
1089 // For 32-bit, create a new block for the restore code.
1090 MachineBasicBlock *RestoreMBB = TargetMBB;
1091 if (STI.is32Bit()) {
1092 RestoreMBB = MF.CreateMachineBasicBlock(MBB.getBasicBlock());
1093 MF.insert(TargetMBB, RestoreMBB);
1094 MBB.transferSuccessors(RestoreMBB);
1095 MBB.addSuccessor(RestoreMBB);
1096 MBBI->getOperand(0).setMBB(RestoreMBB);
1097 }
10781098
10791099 // Pop EBP.
10801100 BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
1081 MachineFramePtr).setMIFlag(MachineInstr::FrameDestroy);
1101 MachineFramePtr)
1102 .setMIFlag(MachineInstr::FrameDestroy);
1103
1104 // Insert frame restoration code in a new block.
1105 if (STI.is32Bit()) {
1106 auto RestoreMBBI = RestoreMBB->begin();
1107 restoreWin32EHStackPointers(*RestoreMBB, RestoreMBBI, DL,
1108 /*RestoreSP=*/true);
1109 BuildMI(*RestoreMBB, RestoreMBBI, DL, TII.get(X86::JMP_4))
1110 .addMBB(TargetMBB);
1111 }
1112 } else if (isFuncletReturnInstr(MBBI)) {
1113 NumBytes = MFI->getMaxCallFrameSize();
1114 assert(hasFP(MF) && "EH funclets without FP not yet implemented");
1115 BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
1116 MachineFramePtr)
1117 .setMIFlag(MachineInstr::FrameDestroy);
10821118 } else if (hasFP(MF)) {
10831119 // Calculate required stack adjustment.
10841120 uint64_t FrameSize = StackSize - SlotSize;
20662102 return !terminatorsNeedFlagsAsInput(MBB);
20672103 }
20682104
2069 MachineBasicBlock::iterator X86FrameLowering::restoreWin32EHFrameAndBasePtr(
2105 MachineBasicBlock::iterator X86FrameLowering::restoreWin32EHStackPointers(
20702106 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
2071 DebugLoc DL) const {
2107 DebugLoc DL, bool RestoreSP) const {
20722108 assert(STI.isTargetWindowsMSVC() && "funclets only supported in MSVC env");
20732109 assert(STI.isTargetWin32() && "EBP/ESI restoration only required on win32");
20742110 assert(STI.is32Bit() && !Uses64BitFramePtr &&
20862122 // FIXME: Don't set FrameSetup flag in catchret case.
20872123
20882124 int FI = FuncInfo.EHRegNodeFrameIndex;
2125 int EHRegSize = MFI->getObjectSize(FI);
2126
2127 if (RestoreSP) {
2128 // MOV32rm -EHRegSize(%ebp), %esp
2129 addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32rm), X86::ESP),
2130 X86::EBP, true, -EHRegSize)
2131 .setMIFlag(MachineInstr::FrameSetup);
2132 }
2133
20892134 unsigned UsedReg;
20902135 int EHRegOffset = getFrameIndexReference(MF, FI, UsedReg);
2091 int EHRegSize = MFI->getObjectSize(FI);
20922136 int EndOffset = -EHRegOffset - EHRegSize;
20932137 FuncInfo.EHRegNodeEndOffset = EndOffset;
20942138 assert(EndOffset >= 0 &&
20952139 "end of registration object above normal EBP position!");
2140
20962141 if (UsedReg == FramePtr) {
20972142 // ADD $offset, %ebp
20982143 assert(UsedReg == FramePtr);
21092154 addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::LEA32r), BasePtr),
21102155 FramePtr, false, EndOffset)
21112156 .setMIFlag(MachineInstr::FrameSetup);
2112 // MOV32mr SavedEBPOffset(%esi), %ebp
2157 // MOV32rm SavedEBPOffset(%esi), %ebp
21132158 assert(X86FI->getHasSEHFramePtrSave());
21142159 int Offset =
21152160 getFrameIndexReference(MF, X86FI->getSEHFramePtrSaveIndex(), UsedReg);
21162161 assert(UsedReg == BasePtr);
2117 addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32mr)), UsedReg, true,
2118 Offset)
2119 .addReg(FramePtr)
2162 addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32rm), FramePtr),
2163 UsedReg, true, Offset)
21202164 .setMIFlag(MachineInstr::FrameSetup);
21212165 }
21222166 return MBBI;
157157 /// Sets up EBP and optionally ESI based on the incoming EBP value. Only
158158 /// needed for 32-bit. Used in funclet prologues and at catchret destinations.
159159 MachineBasicBlock::iterator
160 restoreWin32EHFrameAndBasePtr(MachineBasicBlock &MBB,
161 MachineBasicBlock::iterator MBBI,
162 DebugLoc DL) const;
160 restoreWin32EHStackPointers(MachineBasicBlock &MBB,
161 MachineBasicBlock::iterator MBBI, DebugLoc DL,
162 bool RestoreSP = false) const;
163163 };
164164
165165 } // End llvm namespace
416416 setOperationAction(ISD::SETCC , MVT::i64 , Custom);
417417 }
418418 setOperationAction(ISD::EH_RETURN , MVT::Other, Custom);
419 setOperationAction(ISD::CATCHRET , MVT::Other, Custom);
420 setOperationAction(ISD::CLEANUPRET , MVT::Other, Custom);
421419 // NOTE: EH_SJLJ_SETJMP/_LONGJMP supported here is NOT intended to support
422420 // SjLj exception handling but a light-weight setjmp/longjmp replacement to
423421 // support continuation, user-level threading, and etc.. As a result, no
1692116919 DAG.getRegister(StoreAddrReg, PtrVT));
1692216920 }
1692316921
16924 SDValue X86TargetLowering::LowerCATCHRET(SDValue Op, SelectionDAG &DAG) const {
16925 SDValue Chain = Op.getOperand(0);
16926 SDValue Dest = Op.getOperand(1);
16927 SDLoc DL(Op);
16928
16929 MVT PtrVT = getPointerTy(DAG.getDataLayout());
16930
16931 MachineFunction &MF = DAG.getMachineFunction();
16932 if (isAsynchronousEHPersonality(
16933 classifyEHPersonality(MF.getFunction()->getPersonalityFn()))) {
16934 // For SEH, codegen catchret as a branch for now.
16935 // FIXME: Insert something to restore the frame.
16936 return DAG.getNode(ISD::BR, DL, MVT::Other, Chain, Dest);
16937 }
16938
16939 unsigned ReturnReg = (PtrVT == MVT::i64 ? X86::RAX : X86::EAX);
16940
16941 // Load the address of the destination block.
16942 // FIXME: Do this without creating a BlockAddress.
16943 MachineBasicBlock *DestMBB = cast(Dest)->getBasicBlock();
16944 BlockAddress *BA =
16945 BlockAddress::get(const_cast(MF.getFunction()),
16946 const_cast(DestMBB->getBasicBlock()));
16947 DestMBB->setHasAddressTaken();
16948 SDValue BlockPtr = DAG.getBlockAddress(BA, PtrVT);
16949 Chain = DAG.getCopyToReg(Chain, DL, ReturnReg, BlockPtr);
16950 return DAG.getNode(X86ISD::CATCHRET, DL, MVT::Other, Chain,
16951 DAG.getRegister(ReturnReg, PtrVT));
16952 }
16953
16954 SDValue X86TargetLowering::LowerCLEANUPRET(SDValue Op, SelectionDAG &DAG) const {
16955 return DAG.getNode(X86ISD::CLEANUPRET, SDLoc(Op), MVT::Other,
16956 Op.getOperand(0));
16957 }
16958
1695916922 SDValue X86TargetLowering::lowerEH_SJLJ_SETJMP(SDValue Op,
1696016923 SelectionDAG &DAG) const {
1696116924 SDLoc DL(Op);
1919719160 return LowerFRAME_TO_ARGS_OFFSET(Op, DAG);
1919819161 case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
1919919162 case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG);
19200 case ISD::CLEANUPRET: return LowerCLEANUPRET(Op, DAG);
19201 case ISD::CATCHRET: return LowerCATCHRET(Op, DAG);
1920219163 case ISD::EH_SJLJ_SETJMP: return lowerEH_SJLJ_SETJMP(Op, DAG);
1920319164 case ISD::EH_SJLJ_LONGJMP: return lowerEH_SJLJ_LONGJMP(Op, DAG);
1920419165 case ISD::INIT_TRAMPOLINE: return LowerINIT_TRAMPOLINE(Op, DAG);
1953619497 case X86ISD::EH_SJLJ_SETJMP: return "X86ISD::EH_SJLJ_SETJMP";
1953719498 case X86ISD::EH_SJLJ_LONGJMP: return "X86ISD::EH_SJLJ_LONGJMP";
1953819499 case X86ISD::EH_RETURN: return "X86ISD::EH_RETURN";
19539 case X86ISD::CATCHRET: return "X86ISD::CATCHRET";
19540 case X86ISD::CLEANUPRET: return "X86ISD::CLEANUPRET";
1954119500 case X86ISD::TC_RETURN: return "X86ISD::TC_RETURN";
1954219501 case X86ISD::FNSTCW16m: return "X86ISD::FNSTCW16m";
1954319502 case X86ISD::FNSTSW16r: return "X86ISD::FNSTSW16r";
266266
267267 // Exception Handling helpers.
268268 EH_RETURN,
269
270 // CATCHRET - Represents a return from a catch block funclet. Used for
271 // MSVC compatible exception handling. Takes a chain operand and RAX.
272 CATCHRET,
273
274 // CLEANUPRET - Represents a return from a cleanup block funclet. Used
275 // for MSVC compatible exception handling. Takes only a chain operand.
276 CLEANUPRET,
277269
278270 // SjLj exception handling setjmp.
279271 EH_SJLJ_SETJMP,
10131005 SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
10141006 SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const;
10151007 SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const;
1016 SDValue LowerCATCHRET(SDValue Op, SelectionDAG &DAG) const;
10171008 SDValue LowerCLEANUPRET(SDValue Op, SelectionDAG &DAG) const;
10181009 SDValue lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
10191010 SDValue lowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const;
152152 }
153153
154154 let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1, isCodeGenOnly = 1, isReturn = 1 in {
155 def CATCHRET : I<0xC3, RawFrm, (outs), (ins GR32:$addr),
156 "ret{l}\t# CATCHRET",
157 [(X86catchret GR32:$addr)], IIC_RET>, Sched<[WriteJumpLd]>;
158 def CATCHRET64 : I<0xC3, RawFrm, (outs), (ins GR64:$addr),
159 "ret{q}\t# CATCHRET",
160 [(X86catchret GR64:$addr)], IIC_RET>, Sched<[WriteJumpLd]>;
161 def CLEANUPRET : I<0xC3, RawFrm, (outs), (ins),
162 "ret{l}\t# CLEANUPRET",
163 [(X86cleanupret)], IIC_RET>, Sched<[WriteJumpLd]>,
164 Requires<[Not64BitMode]>;
165 def CLEANUPRET64 : I<0xC3, RawFrm, (outs), (ins),
166 "ret{q}\t# CLEANUPRET",
167 [(X86cleanupret)], IIC_RET>, Sched<[WriteJumpLd]>,
168 Requires<[In64BitMode]>;
155 def CATCHRET : I<0, Pseudo, (outs), (ins brtarget32:$dst),
156 "# CATCHRET",
157 [(catchret bb:$dst)]>;
158 def CLEANUPRET : I<0, Pseudo, (outs), (ins), "# CLEANUPRET", [(cleanupret)]>;
169159 }
170160
171161 let hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1,
203203
204204 def X86ehret : SDNode<"X86ISD::EH_RETURN", SDT_X86EHRET,
205205 [SDNPHasChain]>;
206
207 def X86catchret : SDNode<"X86ISD::CATCHRET", SDT_X86EHRET, [SDNPHasChain]>;
208
209 def X86cleanupret : SDNode<"X86ISD::CLEANUPRET", SDTX86Void, [SDNPHasChain]>;
210206
211207 def X86eh_sjlj_setjmp : SDNode<"X86ISD::EH_SJLJ_SETJMP",
212208 SDTypeProfile<1, 1, [SDTCisInt<0>,
525525
526526 case X86::EH_RETURN:
527527 case X86::EH_RETURN64: {
528 OutMI = MCInst();
529 OutMI.setOpcode(getRetOpcode(AsmPrinter.getSubtarget()));
530 break;
531 }
532
533 case X86::CATCHRET:
534 case X86::CATCHRET64: {
535528 OutMI = MCInst();
536529 OutMI.setOpcode(getRetOpcode(AsmPrinter.getSubtarget()));
537530 break;
499499 insertStateNumberStore(ParentRegNode, II, State);
500500 }
501501 }
502
503 // Insert calls to llvm.x86.seh.restoreframe at catchret destinations. In
504 // SEH, insert them before the catchret.
505 // FIXME: We should probably do this as part of catchret lowering in the
506 // DAG.
507 if (auto *CR = dyn_cast(BB.getTerminator()))
508 insertRestoreFrame(Personality == EHPersonality::MSVC_X86SEH
509 ? CR->getParent()
510 : CR->getSuccessor());
511502 }
512503 }
513504
5858 ; X86: movl $0, -{{[0-9]+}}(%ebp)
5959 ; X86: movl $1, (%esp)
6060 ; X86: calll _f
61 ; X86: [[contbb:Ltmp[0-9]+]]: # Block address taken
62 ; X86: movl -{{[0-9]+}}(%ebp), %esp
63 ; X86: addl ${{[0-9]+}}, %esp
61 ; X86: [[contbb:LBB0_[0-9]+]]: # %try.cont
6462 ; X86: popl %esi
6563 ; X86: popl %edi
6664 ; X86: popl %ebx
7573 ; X86: movl $1, -{{[0-9]+}}(%ebp)
7674 ; X86: movl $2, (%esp)
7775 ; X86: calll _f
78 ; X86: movl $[[contbb]], %eax
79 ; X86-NEXT: addl $16, %esp
76 ; X86: addl $16, %esp
8077 ; X86-NEXT: popl %ebp
78 ; X86-NEXT: movl $[[restorebb:LBB0_[0-9]+]], %eax
8179 ; X86-NEXT: retl
80
81 ; FIXME: Lay this out in the parent funclet.
82 ; X86: [[restorebb]]:
83 ; X86: movl -16(%ebp), %esp
84 ; X86: addl $12, %ebp
85 ; X86: jmp [[contbb]]
8286
8387 ; X86: L__ehtable$try_catch_catch:
8488 ; X86: $handlerMap$0$try_catch_catch:
107111 ; X64: callq useints
108112 ; X64: movl $1, %ecx
109113 ; X64: callq f
110 ; X64: [[contbb:.Ltmp[0-9]+]]: # Block address taken
114 ; X64: [[contbb:\.LBB0_[0-9]+]]: # %try.cont
111115 ; X64: addq $40, %rsp
112116 ; X64: popq %rbp
113117 ; X64: retq
119123 ; X64: subq $32, %rsp
120124 ; X64: movl $2, %ecx
121125 ; X64: callq f
122 ; X64: leaq [[contbb]](%rip), %rax
123126 ; X64: addq $32, %rsp
124127 ; X64: popq %rbp
128 ; X64: leaq [[contbb]](%rip), %rax
125129 ; X64: retq
126130
127131 ; X64: $handlerMap$0$try_catch_catch:
6969 ; X86-DAG: movl %[[addr_reg]], 4(%esp)
7070 ; X86-DAG: movl $1, (%esp)
7171 ; X86: calll _f
72 ; X86: [[contbb:Ltmp[0-9]+]]: # Block address taken
73 ; X86: movl -{{[0-9]+}}(%ebp), %esp
72 ; X86: [[contbb:LBB0_[0-9]+]]: # %try.cont
7473 ; X86: retl
7574
7675 ; X86: [[catch1bb:LBB0_[0-9]+]]: # %catch{{$}}
8382 ; X86-DAG: movl %[[addr_reg]], 4(%esp)
8483 ; X86-DAG: movl %[[e_reg]], (%esp)
8584 ; X86: calll _f
86 ; X86: movl $[[contbb]], %eax
8785 ; X86-NEXT: addl $8, %esp
8886 ; X86-NEXT: popl %ebp
87 ; X86-NEXT: movl $[[restorebb:LBB0_[0-9]+]], %eax
8988 ; X86-NEXT: retl
9089
9190 ; X86: [[catch2bb:LBB0_[0-9]+]]: # %catch.2{{$}}
9796 ; X86-DAG: movl %[[addr_reg]], 4(%esp)
9897 ; X86-DAG: movl $3, (%esp)
9998 ; X86: calll _f
100 ; X86: movl $[[contbb]], %eax
10199 ; X86-NEXT: addl $8, %esp
102100 ; X86-NEXT: popl %ebp
101 ; X86-NEXT: movl $[[restorebb]], %eax
103102 ; X86-NEXT: retl
103
104 ; FIXME: We should lay this code out up with the parent function.
105 ; X86: [[restorebb]]:
106 ; X86: movl -16(%ebp), %esp
107 ; X86: addl $12, %ebp
108 ; X86: jmp [[contbb]]
104109
105110 ; X86: L__ehtable$try_catch_catch:
106111 ; X86: $handlerMap$0$try_catch_catch:
123128 ; X64-DAG: leaq -[[local_offs:[0-9]+]](%rbp), %rdx
124129 ; X64-DAG: movl $1, %ecx
125130 ; X64: callq f
126 ; X64: [[contbb:.Ltmp[0-9]+]]: # Block address taken
131 ; X64: [[contbb:\.LBB0_[0-9]+]]: # %try.cont
127132 ; X64: addq $48, %rsp
128133 ; X64: popq %rbp
129134 ; X64: retq
136141 ; X64-DAG: leaq -[[local_offs]](%rbp), %rdx
137142 ; X64-DAG: movl [[e_addr:[-0-9]+]](%rbp), %ecx
138143 ; X64: callq f
139 ; X64: leaq [[contbb]](%rip), %rax
140144 ; X64: addq $32, %rsp
141 ; X64: popq %rbp
142 ; X64: retq
145 ; X64-NEXT: popq %rbp
146 ; X64-NEXT: leaq [[contbb]](%rip), %rax
147 ; X64-NEXT: retq
143148
144149 ; X64: [[catch2bb:\.LBB0_[0-9]+]]: # %catch.2{{$}}
145150 ; X64: movq %rdx, 16(%rsp)
149154 ; X64-DAG: leaq -[[local_offs]](%rbp), %rdx
150155 ; X64-DAG: movl $3, %ecx
151156 ; X64: callq f
152 ; X64: leaq [[contbb]](%rip), %rax
153157 ; X64: addq $32, %rsp
154 ; X64: popq %rbp
155 ; X64: retq
158 ; X64-NEXT: popq %rbp
159 ; X64-NEXT: leaq [[contbb]](%rip), %rax
160 ; X64-NEXT: retq
156161
157162 ; X64: $handlerMap$0$try_catch_catch:
158163 ; X64: .long 0
6565 ; X86: calll _f
6666
6767 ; X86: LBB1_[[cleanup_inner:[0-9]+]]: # %cleanup.inner
68 ; X86: pushl %ebp
6869 ; X86: leal {{.*}}(%ebp), %ecx
6970 ; X86: calll "??1Dtor@@QAE@XZ"
70 ; X86: retl # CLEANUPRET
71 ; X86: popl %ebp
72 ; X86: retl
7173
7274 ; X86: LBB1_[[cleanup_outer:[0-9]+]]: # %cleanup.outer
75 ; X86: pushl %ebp
7376 ; X86: leal {{.*}}(%ebp), %ecx
7477 ; X86: calll "??1Dtor@@QAE@XZ"
75 ; X86: retl # CLEANUPRET
78 ; X86: popl %ebp
79 ; X86: retl
7680
7781 ; X86: L__ehtable$nested_cleanup:
7882 ; X86: .long 429065506
99103 ; X64: callq f
100104
101105 ; X64: .LBB1_[[cleanup_inner:[0-9]+]]: # %cleanup.inner
106 ; X64: pushq %rbp
102107 ; X64: leaq {{.*}}(%rbp), %rcx
103108 ; X64: callq "??1Dtor@@QAE@XZ"
104 ; X64: retq # CLEANUPRET
109 ; X64: popq %rbp
110 ; X64: retq
105111
106112 ; X64: .LBB1_[[cleanup_outer:[0-9]+]]: # %cleanup.outer
113 ; X64: pushq %rbp
107114 ; X64: leaq {{.*}}(%rbp), %rcx
108115 ; X64: callq "??1Dtor@@QAE@XZ"
109 ; X64: retq # CLEANUPRET
116 ; X64: popq %rbp
117 ; X64: retq
110118
111119 ; X64: .seh_handlerdata
112120 ; X64: .long ($cppxdata$nested_cleanup)@IMGREL