llvm.org GIT mirror llvm / dff7549
[WinEH] Emit prologues and epilogues for funclets Summary: 32-bit funclets have short prologues that allocate enough stack for the largest call in the whole function. The runtime saves CSRs for the funclet. It doesn't restore CSRs after we finally transfer control back to the parent funciton via a CATCHRET, but that's a separate issue. 32-bit funclets also have to adjust the incoming EBP value, which is what llvm.x86.seh.recoverframe does in the old model. 64-bit funclets need to spill CSRs as normal. For simplicity, this just spills the same set of CSRs as the parent function, rather than trying to compute different CSR sets for the parent function and each funclet. 64-bit funclets also allocate enough stack space for the largest outgoing call frame, like 32-bit. Reviewers: majnemer Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D12546 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@247092 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 4 years ago
11 changed file(s) with 401 addition(s) and 59 deletion(s). Raw diff Collapse all Expand all
1818 #include "llvm/ADT/DenseMap.h"
1919
2020 namespace llvm {
21 class AllocaInst;
2122 class BasicBlock;
2223 class Constant;
2324 class Function;
155156 /// localescape index of the 32-bit EH registration node. Set by
156157 /// WinEHStatePass and used indirectly by SEH filter functions of the parent.
157158 int EHRegNodeEscapeIndex = INT_MAX;
159 const AllocaInst *EHRegNode = nullptr;
160 int EHRegNodeFrameIndex = INT_MAX;
158161
159162 WinEHFuncInfo() {}
160163 };
472472 OS.EmitValue(create32bitRef(HT.Handler), 4);
473473
474474 if (shouldEmitPersonality) {
475 MCSymbol *ParentFrameOffset =
476 Asm->OutContext.getOrCreateParentFrameOffsetSymbol(
477 GlobalValue::getRealLinkageName(HT.Handler->getName()));
478 const MCSymbolRefExpr *ParentFrameOffsetRef = MCSymbolRefExpr::create(
479 ParentFrameOffset, Asm->OutContext);
480 OS.EmitValue(ParentFrameOffsetRef, 4); // ParentFrameOffset
475 if (FuncInfo.CatchHandlerParentFrameObjOffset.empty()) {
476 // With the new IR, this is always 16 + 8 + getMaxCallFrameSize().
477 // Keep this in sync with X86FrameLowering::emitPrologue.
478 int ParentFrameOffset =
479 16 + 8 + MF->getFrameInfo()->getMaxCallFrameSize();
480 OS.EmitIntValue(ParentFrameOffset, 4); // ParentFrameOffset
481 } else {
482 MCSymbol *ParentFrameOffset =
483 Asm->OutContext.getOrCreateParentFrameOffsetSymbol(
484 GlobalValue::getRealLinkageName(HT.Handler->getName()));
485 const MCSymbolRefExpr *ParentFrameOffsetRef =
486 MCSymbolRefExpr::create(ParentFrameOffset, Asm->OutContext);
487 OS.EmitValue(ParentFrameOffsetRef, 4); // ParentFrameOffset
488 }
481489 }
482490 }
483491 }
7070 // stack frame indexes.
7171 unsigned MinCSFrameIndex, MaxCSFrameIndex;
7272
73 // Save and Restore blocks of the current function.
74 MachineBasicBlock *SaveBlock;
73 // Save and Restore blocks of the current function. Typically there is a
74 // single save block, unless Windows EH funclets are involved.
75 SmallVector SaveBlocks;
7576 SmallVector RestoreBlocks;
7677
7778 // Flag to control whether to use the register scavenger to resolve
141142
142143 // Use the points found by shrink-wrapping, if any.
143144 if (MFI->getSavePoint()) {
144 SaveBlock = MFI->getSavePoint();
145 SaveBlocks.push_back(MFI->getSavePoint());
145146 assert(MFI->getRestorePoint() && "Both restore and save must be set");
146147 MachineBasicBlock *RestoreBlock = MFI->getRestorePoint();
147148 // If RestoreBlock does not have any successor and is not a return block
153154 }
154155
155156 // Save refs to entry and return blocks.
156 SaveBlock = Fn.begin();
157 for (MachineFunction::iterator MBB = Fn.begin(), E = Fn.end();
158 MBB != E; ++MBB)
159 if (isReturnBlock(MBB))
160 RestoreBlocks.push_back(MBB);
161
162 return;
157 SaveBlocks.push_back(Fn.begin());
158 for (MachineBasicBlock &MBB : Fn) {
159 if (MBB.isEHFuncletEntry())
160 SaveBlocks.push_back(&MBB);
161 if (isReturnBlock(&MBB))
162 RestoreBlocks.push_back(&MBB);
163 }
163164 }
164165
165166 /// StackObjSet - A set of stack object indexes
236237 }
237238
238239 delete RS;
240 SaveBlocks.clear();
239241 RestoreBlocks.clear();
240242 return true;
241243 }
445447 MachineBasicBlock::iterator I;
446448
447449 // Spill using target interface.
448 I = SaveBlock->begin();
449 if (!TFI->spillCalleeSavedRegisters(*SaveBlock, I, CSI, TRI)) {
450 for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
451 // Insert the spill to the stack frame.
452 unsigned Reg = CSI[i].getReg();
453 const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
454 TII.storeRegToStackSlot(*SaveBlock, I, Reg, true, CSI[i].getFrameIdx(),
455 RC, TRI);
456 }
457 }
458 // Update the live-in information of all the blocks up to the save point.
459 updateLiveness(Fn);
450 for (MachineBasicBlock *SaveBlock : SaveBlocks) {
451 I = SaveBlock->begin();
452 if (!TFI->spillCalleeSavedRegisters(*SaveBlock, I, CSI, TRI)) {
453 for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
454 // Insert the spill to the stack frame.
455 unsigned Reg = CSI[i].getReg();
456 const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
457 TII.storeRegToStackSlot(*SaveBlock, I, Reg, true, CSI[i].getFrameIdx(),
458 RC, TRI);
459 }
460 }
461 // Update the live-in information of all the blocks up to the save point.
462 updateLiveness(Fn);
463 }
460464
461465 // Restore using target interface.
462466 for (MachineBasicBlock *MBB : RestoreBlocks) {
770774 const TargetFrameLowering &TFI = *Fn.getSubtarget().getFrameLowering();
771775
772776 // Add prologue to the function...
773 TFI.emitPrologue(Fn, *SaveBlock);
777 for (MachineBasicBlock *SaveBlock : SaveBlocks)
778 TFI.emitPrologue(Fn, *SaveBlock);
774779
775780 // Add epilogue to restore the callee-save registers in each exiting block.
776781 for (MachineBasicBlock *RestoreBlock : RestoreBlocks)
780785 // we've been asked for it. This, when linked with a runtime with support
781786 // for segmented stacks (libgcc is one), will result in allocating stack
782787 // space in small chunks instead of one large contiguous block.
783 if (Fn.shouldSplitStack())
784 TFI.adjustForSegmentedStacks(Fn, *SaveBlock);
788 if (Fn.shouldSplitStack()) {
789 for (MachineBasicBlock *SaveBlock : SaveBlocks)
790 TFI.adjustForSegmentedStacks(Fn, *SaveBlock);
791 }
785792
786793 // Emit additional code that is required to explicitly handle the stack in
787794 // HiPE native code (if needed) when loaded in the Erlang/OTP runtime. The
789796 // different conditional check and another BIF for allocating more stack
790797 // space.
791798 if (Fn.getFunction()->getCallingConv() == CallingConv::HiPE)
792 TFI.adjustForHiPEPrologue(Fn, *SaveBlock);
799 for (MachineBasicBlock *SaveBlock : SaveBlocks)
800 TFI.adjustForHiPEPrologue(Fn, *SaveBlock);
793801 }
794802
795803 /// replaceFrameIndices - Replace all MO_FrameIndex operands with physical
279279 for (WinEHHandlerType &H : TBME.HandlerArray)
280280 if (const auto *BB = dyn_cast(H.Handler))
281281 H.HandlerMBB = MBBMap[BB];
282 // If there's an explicit EH registration node on the stack, record its
283 // frame index.
284 if (EHInfo.EHRegNode && EHInfo.EHRegNode->getParent()->getParent() == Fn) {
285 assert(StaticAllocaMap.count(EHInfo.EHRegNode));
286 EHInfo.EHRegNodeFrameIndex = StaticAllocaMap[EHInfo.EHRegNode];
287 }
282288 }
283289
284290 // Copy the state numbers to LandingPadInfo for the current function, which
2222 #include "llvm/CodeGen/MachineInstrBuilder.h"
2323 #include "llvm/CodeGen/MachineModuleInfo.h"
2424 #include "llvm/CodeGen/MachineRegisterInfo.h"
25 #include "llvm/CodeGen/WinEHFuncInfo.h"
2526 #include "llvm/IR/DataLayout.h"
2627 #include "llvm/IR/Function.h"
2728 #include "llvm/MC/MCAsmInfo.h"
8788 MFI->hasVarSizedObjects() ||
8889 MFI->isFrameAddressTaken() || MFI->hasOpaqueSPAdjustment() ||
8990 MF.getInfo()->getForceFramePointer() ||
90 MMI.callsUnwindInit() || MMI.callsEHReturn() ||
91 MMI.callsUnwindInit() || MMI.hasEHFunclets() || MMI.callsEHReturn() ||
9192 MFI->hasStackMap() || MFI->hasPatchPoint());
9293 }
9394
694695 uint64_t NumBytes = 0;
695696 int stackGrowth = -SlotSize;
696697
697 if (HasFP) {
698 if (MBB.isEHFuncletEntry()) {
699 assert(STI.isOSWindows() && "funclets only supported on Windows");
700
701 // Set up the FramePtr and BasePtr physical registers using the address
702 // passed as EBP or RDX by the MSVC EH runtime.
703 if (STI.is32Bit()) {
704 MBBI = restoreWin32EHFrameAndBasePtr(MBB, MBBI, DL);
705 } else {
706 // FIXME: Add SEH directives.
707 NeedsWinCFI = false;
708 // Immediately spill RDX into the home slot. The runtime cares about this.
709 unsigned RDX = Uses64BitFramePtr ? X86::RDX : X86::EDX;
710 // MOV64mr %rdx, 16(%rsp)
711 unsigned MOVmr = Uses64BitFramePtr ? X86::MOV64mr : X86::MOV32mr;
712 addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(MOVmr)),
713 StackPtr, true, 16)
714 .addReg(RDX)
715 .setMIFlag(MachineInstr::FrameSetup);
716 // PUSH64r %rbp
717 BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::PUSH64r : X86::PUSH32r))
718 .addReg(MachineFramePtr, RegState::Kill)
719 .setMIFlag(MachineInstr::FrameSetup);
720 // MOV64rr %rdx, %rbp
721 unsigned MOVrr = Uses64BitFramePtr ? X86::MOV64rr : X86::MOV32rr;
722 BuildMI(MBB, MBBI, DL, TII.get(MOVrr), FramePtr)
723 .addReg(RDX)
724 .setMIFlag(MachineInstr::FrameSetup);
725 assert(!TRI->hasBasePointer(MF) &&
726 "x64 funclets with base ptrs not yet implemented");
727 }
728
729 // For EH funclets, only allocate enough space for outgoing calls.
730 NumBytes = MFI->getMaxCallFrameSize();
731 } else if (HasFP) {
698732 // Calculate required stack adjustment.
699733 uint64_t FrameSize = StackSize - SlotSize;
700734 // If required, include space for extra hidden slot for stashing base pointer.
955989 // it recovers the frame pointer from the base pointer rather than the
956990 // other way around.
957991 unsigned Opm = Uses64BitFramePtr ? X86::MOV64mr : X86::MOV32mr;
958 unsigned IgnoredFrameReg;
959 addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(Opm)), BasePtr, true,
960 getFrameIndexReference(MF, X86FI->getSEHFramePtrSaveIndex(),
961 IgnoredFrameReg))
992 unsigned UsedReg;
993 int Offset =
994 getFrameIndexReference(MF, X86FI->getSEHFramePtrSaveIndex(), UsedReg);
995 assert(UsedReg == BasePtr);
996 addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(Opm)), UsedReg, true, Offset)
962997 .addReg(FramePtr)
963998 .setMIFlag(MachineInstr::FrameSetup);
964999 }
9881023 // 1. We *aren't* using the Win64 ABI which means we are free to use LEA.
9891024 // 2. We *have* a frame pointer which means we are permitted to use LEA.
9901025 return !MF.getTarget().getMCAsmInfo()->usesWindowsCFI() || hasFP(MF);
1026 }
1027
1028 static bool isFuncletReturnInstr(MachineInstr *MI) {
1029 switch (MI->getOpcode()) {
1030 case X86::CATCHRET:
1031 case X86::CATCHRET64:
1032 return true;
1033 default:
1034 return false;
1035 }
1036 llvm_unreachable("impossible");
9911037 }
9921038
9931039 void X86FrameLowering::emitEpilogue(MachineFunction &MF,
10151061 unsigned CSSize = X86FI->getCalleeSavedFrameSize();
10161062 uint64_t NumBytes = 0;
10171063
1018 if (hasFP(MF)) {
1064 if (isFuncletReturnInstr(MBBI)) {
1065 NumBytes = MFI->getMaxCallFrameSize();
1066
1067 if (Is64Bit) {
1068 assert(hasFP(MF) && "win64 EH funclets without FP not yet implemented");
1069 // POP64r %rbp
1070 BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
1071 MachineFramePtr);
1072 }
1073 } else if (hasFP(MF)) {
10191074 // Calculate required stack adjustment.
10201075 uint64_t FrameSize = StackSize - SlotSize;
10211076 NumBytes = FrameSize - CSSize;
13301385 const TargetRegisterInfo *TRI) const {
13311386 DebugLoc DL = MBB.findDebugLoc(MI);
13321387
1388 // Don't save CSRs in 32-bit EH funclets. The caller saves EBX, EBP, ESI, EDI
1389 // for us, and there are no XMM CSRs on Win32.
1390 if (MBB.isEHFuncletEntry() && STI.is32Bit() && STI.isOSWindows())
1391 return true;
1392
13331393 // Push GPRs. It increases frame size.
13341394 unsigned Opc = STI.is64Bit() ? X86::PUSH64r : X86::PUSH32r;
13351395 for (unsigned i = CSI.size(); i != 0; --i) {
13701430 const TargetRegisterInfo *TRI) const {
13711431 if (CSI.empty())
13721432 return false;
1433
1434 // Don't restore CSRs in 32-bit EH funclets. Matches
1435 // spillCalleeSavedRegisters.
1436 if (isFuncletReturnInstr(MI) && STI.is32Bit() && STI.isOSWindows())
1437 return true;
13731438
13741439 DebugLoc DL = MBB.findDebugLoc(MI);
13751440
14221487 }
14231488
14241489 // Spill the BasePtr if it's used.
1425 if (TRI->hasBasePointer(MF))
1490 if (TRI->hasBasePointer(MF)) {
14261491 SavedRegs.set(TRI->getBaseRegister());
1492
1493 // Allocate a spill slot for EBP if we have a base pointer and EH funclets.
1494 if (MF.getMMI().hasEHFunclets()) {
1495 int FI = MFI->CreateSpillStackObject(SlotSize, SlotSize);
1496 X86FI->setHasSEHFramePtrSave(true);
1497 X86FI->setSEHFramePtrSaveIndex(FI);
1498 }
1499 }
14271500 }
14281501
14291502 static bool
19752048 // safe to insert the epilogue here.
19762049 return !terminatorsNeedFlagsAsInput(MBB);
19772050 }
2051
2052 MachineBasicBlock::iterator X86FrameLowering::restoreWin32EHFrameAndBasePtr(
2053 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
2054 DebugLoc DL) const {
2055 assert(STI.isTargetWindowsMSVC() && "funclets only supported in MSVC env");
2056 assert(STI.isTargetWin32() && "EBP/ESI restoration only required on win32");
2057 assert(STI.is32Bit() && !Uses64BitFramePtr &&
2058 "restoring EBP/ESI on non-32-bit target");
2059
2060 MachineFunction &MF = *MBB.getParent();
2061 unsigned FramePtr = TRI->getFrameRegister(MF);
2062 unsigned BasePtr = TRI->getBaseRegister();
2063 MachineModuleInfo &MMI = MF.getMMI();
2064 const Function *Fn = MF.getFunction();
2065 WinEHFuncInfo &FuncInfo = MMI.getWinEHFuncInfo(Fn);
2066 X86MachineFunctionInfo *X86FI = MF.getInfo();
2067 MachineFrameInfo *MFI = MF.getFrameInfo();
2068
2069 // FIXME: Don't set FrameSetup flag in catchret case.
2070
2071 int FI = FuncInfo.EHRegNodeFrameIndex;
2072 unsigned UsedReg;
2073 int EHRegOffset = getFrameIndexReference(MF, FI, UsedReg);
2074 int EHRegSize = MFI->getObjectSize(FI);
2075 int EndOffset = -EHRegOffset - EHRegSize;
2076 assert(EndOffset >= 0 &&
2077 "end of registration object above normal EBP position!");
2078 if (UsedReg == FramePtr) {
2079 // ADD $offset, %ebp
2080 assert(UsedReg == FramePtr);
2081 unsigned ADDri = getADDriOpcode(false, EndOffset);
2082 BuildMI(MBB, MBBI, DL, TII.get(ADDri), FramePtr)
2083 .addReg(FramePtr)
2084 .addImm(EndOffset)
2085 .setMIFlag(MachineInstr::FrameSetup)
2086 ->getOperand(3)
2087 .setIsDead();
2088 } else {
2089 assert(UsedReg == BasePtr);
2090 // LEA offset(%ebp), %esi
2091 addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::LEA32r), BasePtr),
2092 FramePtr, false, EndOffset)
2093 .setMIFlag(MachineInstr::FrameSetup);
2094 // MOV32mr SavedEBPOffset(%esi), %ebp
2095 assert(X86FI->getHasSEHFramePtrSave());
2096 int Offset =
2097 getFrameIndexReference(MF, X86FI->getSEHFramePtrSaveIndex(), UsedReg);
2098 assert(UsedReg == BasePtr);
2099 addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32mr)), UsedReg, true,
2100 Offset)
2101 .addReg(FramePtr)
2102 .setMIFlag(MachineInstr::FrameSetup);
2103 }
2104 return MBBI;
2105 }
153153 MachineBasicBlock::iterator MBBI,
154154 DebugLoc DL, int64_t Offset,
155155 bool InEpilogue) const;
156
157 /// Sets up EBP and optionally ESI based on the incoming EBP value. Only
158 /// needed for 32-bit. Used in funclet prologues and at catchret destinations.
159 MachineBasicBlock::iterator
160 restoreWin32EHFrameAndBasePtr(MachineBasicBlock &MBB,
161 MachineBasicBlock::iterator MBBI,
162 DebugLoc DL) const;
156163 };
157164
158165 } // End llvm namespace
151151
152152 }
153153
154 let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1, isCodeGenOnly = 1 in {
154 let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1, isCodeGenOnly = 1, isReturn = 1 in {
155155 def CATCHRET : I<0xC3, RawFrm, (outs), (ins GR32:$addr),
156156 "ret{l}\t# CATCHRET",
157157 [(X86catchret GR32:$addr)], IIC_RET>, Sched<[WriteJumpLd]>;
530530 break;
531531 }
532532
533 case X86::CATCHRET: {
533 case X86::CATCHRET:
534 case X86::CATCHRET64: {
534535 OutMI = MCInst();
535536 OutMI.setOpcode(getRetOpcode(AsmPrinter.getSubtarget()));
536537 break;
177177 FuncInfoPtr.reset(new WinEHFuncInfo());
178178 WinEHFuncInfo &FuncInfo =
179179 *(MMI ? &MMI->getWinEHFuncInfo(&F) : FuncInfoPtr.get());
180
181 FuncInfo.EHRegNode = RegNode;
180182
181183 switch (Personality) {
182184 default: llvm_unreachable("unexpected personality function");
493495
494496 // Insert calls to llvm.x86.seh.restoreframe at catchret destinations.
495497 if (auto *CR = dyn_cast(BB.getTerminator())) {
496 //llvm::errs() << "BB: " << BB << '\n';
497 //llvm::errs() << "CR->getSuccessor(): " << *CR->getSuccessor() << '\n';
498 IRBuilder<> Builder(CR->getSuccessor()->begin());
498 Instruction *Start = CR->getSuccessor()->begin();
499 assert(!isa(Start) &&
500 "winehprepare failed to demote phi after catchret");
501 if (match(Start, m_Intrinsic()))
502 continue;
503 IRBuilder<> Builder(Start);
499504 Builder.CreateCall(RestoreFrame, {});
500505 }
501506 }
0 ; RUN: llc -mtriple=i686-pc-windows-msvc < %s | FileCheck --check-prefix=X86 %s
1 ; RUN: llc -mtriple=x86_64-pc-windows-msvc < %s | FileCheck --check-prefix=X64 %s
2
3 %rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
4 %eh.CatchableType = type { i32, i8*, i32, i32, i32, i32, i8* }
5 %eh.CatchableTypeArray.1 = type { i32, [1 x %eh.CatchableType*] }
6 %eh.ThrowInfo = type { i32, i8*, i8*, i8* }
7 %eh.CatchHandlerType = type { i32, i8* }
8
9 $"\01??_R0H@8" = comdat any
10
11 @"\01??_7type_info@@6B@" = external constant i8*
12 @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
13
14 @llvm.eh.handlertype.H.0 = private unnamed_addr constant %eh.CatchHandlerType { i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) }, section "llvm.metadata"
15 @llvm.eh.handlertype.H.1 = private unnamed_addr constant %eh.CatchHandlerType { i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) }, section "llvm.metadata"
16
17 declare i32 @getint()
18 declare void @useints(...)
19 declare void @f(i32 %p)
20 declare i32 @__CxxFrameHandler3(...)
21
22 define i32 @try_catch_catch() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
23 entry:
24 %a = call i32 @getint()
25 %b = call i32 @getint()
26 %c = call i32 @getint()
27 %d = call i32 @getint()
28 call void (...) @useints(i32 %a, i32 %b, i32 %c, i32 %d)
29 invoke void @f(i32 1)
30 to label %try.cont unwind label %catch.dispatch
31
32 catch.dispatch: ; preds = %entry
33 %0 = catchpad [%eh.CatchHandlerType* @llvm.eh.handlertype.H.0, i8* null]
34 to label %catch unwind label %catchendblock
35
36 catch:
37 invoke void @f(i32 2)
38 to label %invoke.cont.2 unwind label %catchendblock
39
40 invoke.cont.2: ; preds = %catch
41 catchret %0 to label %try.cont
42
43 try.cont: ; preds = %entry, %invoke.cont.2, %invoke.cont.3
44 ret i32 0
45
46 catchendblock: ; preds = %catch,
47 catchendpad unwind to caller
48 }
49
50 ; X86-LABEL: _try_catch_catch:
51 ; X86: pushl %ebp
52 ; X86: movl %esp, %ebp
53 ; X86: pushl %ebx
54 ; X86: pushl %edi
55 ; X86: pushl %esi
56 ; X86: subl ${{[0-9]+}}, %esp
57 ; X86: calll _getint
58 ; X86: calll _getint
59 ; X86: calll _getint
60 ; X86: calll _getint
61 ; X86: calll _useints
62 ; X86: movl $0, -{{[0-9]+}}(%ebp)
63 ; X86: movl $1, (%esp)
64 ; X86: calll _f
65 ; X86: [[contbb:LBB0_[0-9]+]]:
66 ; X86: movl -{{[0-9]+}}(%ebp), %esp
67 ; X86: addl ${{[0-9]+}}, %esp
68 ; X86: popl %esi
69 ; X86: popl %edi
70 ; X86: popl %ebx
71 ; X86: popl %ebp
72 ; X86: retl
73
74 ; X86: [[catch1bb:LBB0_[0-9]+]]: # %catch{{$}}
75 ; X86-NOT: pushl
76 ; X86: addl $12, %ebp
77 ; X86: subl $16, %esp
78 ; X86: movl $1, -{{[0-9]+}}(%ebp)
79 ; X86: movl $2, (%esp)
80 ; X86: calll _f
81 ; X86: movl $[[contbb]], %eax
82 ; X86-NEXT: addl $16, %esp
83 ; X86-NOT: popl
84 ; X86-NEXT: retl
85
86 ; X86: L__ehtable$try_catch_catch:
87 ; X86: $handlerMap$0$try_catch_catch:
88 ; X86: .long 0
89 ; X86: .long "??_R0H@8"
90 ; X86: .long 0
91 ; X86: .long [[catch1bb]]
92
93 ; X64-LABEL: try_catch_catch:
94 ; X64: pushq %rbp
95 ; X64: .seh_pushreg 5
96 ; X64: pushq %rsi
97 ; X64: .seh_pushreg 6
98 ; X64: pushq %rdi
99 ; X64: .seh_pushreg 7
100 ; X64: pushq %rbx
101 ; X64: .seh_pushreg 3
102 ; X64: subq $40, %rsp
103 ; X64: .seh_stackalloc 40
104 ; X64: leaq 32(%rsp), %rbp
105 ; X64: .seh_setframe 5, 32
106 ; X64: callq getint
107 ; X64: callq getint
108 ; X64: callq getint
109 ; X64: callq getint
110 ; X64: callq useints
111 ; X64: movl $1, %ecx
112 ; X64: callq f
113 ; X64: [[contbb:\.LBB0_[0-9]+]]:
114 ; X64: addq $40, %rsp
115 ; X64: popq %rbp
116 ; X64: retq
117
118 ; X64: [[catch1bb:\.LBB0_[0-9]+]]: # %catch{{$}}
119 ; X64: movq %rdx, 16(%rsp)
120 ; X64: pushq %rbp
121 ; X64: movq %rdx, %rbp
122 ; X64: subq $32, %rsp
123 ; X64: movl $2, %ecx
124 ; X64: callq f
125 ; X64: leaq [[contbb]](%rip), %rax
126 ; X64: addq $32, %rsp
127 ; X64: popq %rbp
128 ; X64: retq
129
130 ; X64: $handlerMap$0$try_catch_catch:
131 ; X64: .long 0
132 ; X64: .long "??_R0H@8"@IMGREL
133 ; X64: .long 0
134 ; X64: .long [[catch1bb]]@IMGREL
135 ; X64: .long 56
2626 @llvm.eh.handlertype.H.0 = private unnamed_addr constant %eh.CatchHandlerType { i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) }, section "llvm.metadata"
2727 @llvm.eh.handlertype.H.1 = private unnamed_addr constant %eh.CatchHandlerType { i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) }, section "llvm.metadata"
2828
29 declare void @f(i32 %p)
29 declare void @f(i32 %p, i32* %l)
3030 declare i32 @__CxxFrameHandler3(...)
31 declare void @barrier()
3132
3233 define i32 @try_catch_catch() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
3334 entry:
34 invoke void @f(i32 1)
35 %local = alloca i32
36 invoke void @f(i32 1, i32* %local)
3537 to label %try.cont unwind label %catch.dispatch
3638
3739 catch.dispatch: ; preds = %entry
3941 to label %catch unwind label %catch.dispatch.2
4042
4143 catch: ; preds = %catch.dispatch
42 invoke void @f(i32 2)
44 ; FIXME: Remove this barrier once we add more real register allocation barriers.
45 invoke void @barrier()
46 to label %barrier.split unwind label %catchendblock
47 barrier.split:
48 invoke void @f(i32 2, i32* %local)
4349 to label %invoke.cont.2 unwind label %catchendblock
4450
4551 invoke.cont.2: ; preds = %catch
5056 to label %catch.2 unwind label %catchendblock
5157
5258 catch.2: ; preds = %catch.dispatch.2
53 invoke void @f(i32 3)
59 invoke void @f(i32 3, i32* %local)
5460 to label %invoke.cont.3 unwind label %catchendblock
5561
5662 invoke.cont.3: ; preds = %catch.2
6571
6672 ; X86-LABEL: _try_catch_catch:
6773 ; X86: movl $0, -{{[0-9]+}}(%ebp)
68 ; X86: movl $1, (%esp)
74 ; X86: leal -[[local_offs:[0-9]+]](%ebp), %[[addr_reg:[a-z]+]]
75 ; X86-DAG: movl %[[addr_reg]], 4(%esp)
76 ; X86-DAG: movl $1, (%esp)
6977 ; X86: calll _f
7078 ; X86: [[contbb:LBB0_[0-9]+]]:
7179 ; X86: movl -{{[0-9]+}}(%ebp), %esp
7280 ; X86: retl
7381
7482 ; X86: [[catch1bb:LBB0_[0-9]+]]: # %catch{{$}}
83 ; X86: addl $12, %ebp
84 ; X86: subl $8, %esp
85 ; X86: calll _barrier
7586 ; X86: movl $1, -{{[0-9]+}}(%ebp)
76 ; X86: movl $2, (%esp)
87 ; X86: leal -[[local_offs]](%ebp), %[[addr_reg:[a-z]+]]
88 ; X86-DAG: movl %[[addr_reg]], 4(%esp)
89 ; X86-DAG: movl $2, (%esp)
7790 ; X86: calll _f
7891 ; X86: movl $[[contbb]], %eax
92 ; X86-NEXT: addl $8, %esp
7993 ; X86-NEXT: retl
8094
8195 ; X86: [[catch2bb:LBB0_[0-9]+]]: # %catch.2{{$}}
96 ; X86: addl $12, %ebp
97 ; X86: subl $8, %esp
8298 ; X86: movl $1, -{{[0-9]+}}(%ebp)
83 ; X86: movl $3, (%esp)
99 ; X86: leal -[[local_offs]](%ebp), %[[addr_reg:[a-z]+]]
100 ; X86-DAG: movl %[[addr_reg]], 4(%esp)
101 ; X86-DAG: movl $3, (%esp)
84102 ; X86: calll _f
85103 ; X86: movl $[[contbb]], %eax
104 ; X86-NEXT: addl $8, %esp
86105 ; X86-NEXT: retl
87106
88107 ; X86: L__ehtable$try_catch_catch:
97116 ; X86: .long [[catch2bb]]
98117
99118 ; X64-LABEL: try_catch_catch:
100 ; X64: movl $1, %ecx
119 ; X64: pushq %rbp
120 ; X64: .seh_pushreg 5
121 ; X64: subq $48, %rsp
122 ; X64: .seh_stackalloc 48
123 ; X64: leaq 48(%rsp), %rbp
124 ; X64: .seh_setframe 5, 48
125 ; X64-DAG: leaq -[[local_offs:[0-9]+]](%rbp), %rdx
126 ; X64-DAG: movl $1, %ecx
101127 ; X64: callq f
102128 ; X64: [[contbb:\.LBB0_[0-9]+]]:
129 ; X64: addq $48, %rsp
130 ; X64: popq %rbp
103131 ; X64: retq
104132
105133 ; X64: [[catch1bb:\.LBB0_[0-9]+]]: # %catch{{$}}
106 ; X64: movl $2, %ecx
134 ; X64: movq %rdx, 16(%rsp)
135 ; X64: pushq %rbp
136 ; X64: movq %rdx, %rbp
137 ; X64: subq $32, %rsp
138 ; X64-DAG: leaq -[[local_offs]](%rbp), %rdx
139 ; X64-DAG: movl $2, %ecx
107140 ; X64: callq f
108141 ; X64: leaq [[contbb]](%rip), %rax
142 ; X64: addq $32, %rsp
143 ; X64: popq %rbp
109144 ; X64: retq
110145
111146 ; X64: [[catch2bb:\.LBB0_[0-9]+]]: # %catch.2{{$}}
112 ; X64: movl $3, %ecx
147 ; X64: movq %rdx, 16(%rsp)
148 ; X64: pushq %rbp
149 ; X64: movq %rdx, %rbp
150 ; X64: subq $32, %rsp
151 ; X64-DAG: leaq -[[local_offs]](%rbp), %rdx
152 ; X64-DAG: movl $3, %ecx
113153 ; X64: callq f
114154 ; X64: leaq [[contbb]](%rip), %rax
155 ; X64: addq $32, %rsp
156 ; X64: popq %rbp
115157 ; X64: retq
116158
117 ; FIXME: Get rid of these parent_frame_offset things below. They are leftover
118 ; from our IR outlining strategy.
119159 ; X64: $handlerMap$0$try_catch_catch:
120160 ; X64: .long 0
121161 ; X64: .long "??_R0H@8"@IMGREL
122162 ; X64: .long 0
123163 ; X64: .long [[catch1bb]]@IMGREL
124 ; X64 .long .Lcatch$parent_frame_offset
164 ; X64: .long 56
125165 ; X64: .long 0
126166 ; X64: .long "??_R0H@8"@IMGREL
127167 ; X64: .long 0
128168 ; X64: .long [[catch2bb]]@IMGREL
129 ; X64 .long .Lcatch.2$parent_frame_offset
169 ; X64: .long 56