llvm.org GIT mirror llvm / a736fb5
[WinEH] Find root frame correctly in CLR funclets Summary: The value that the CoreCLR personality passes to a funclet for the establisher frame may be the root function's frame or may be the parent funclet's (mostly empty) frame in the case of nested funclets. Each funclet stores a pointer to the root frame in its own (mostly empty) frame, as does the root function itself. All frames allocate this slot at the same offset, measured from the post-prolog stack pointer, so that the same sequence can accept any ancestor as an establisher frame parameter value, and so that a single offset can be reported to the GC, which also looks at this slot. This change allocate the slot when processing function entry, and records its frame index on the WinEHFuncInfo object, then inserts the code to set/copy it during prolog emission. Reviewers: majnemer, AndyAyers, pgavlin, rnk Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D14614 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252983 91177308-0d34-0410-b5e6-96231b3b80d8 Joseph Tremoulet 4 years ago
5 changed file(s) with 147 addition(s) and 28 deletion(s). Raw diff Collapse all Expand all
9595 SmallVector SEHUnwindMap;
9696 SmallVector ClrEHUnwindMap;
9797 int UnwindHelpFrameIdx = INT_MAX;
98 int PSPSymFrameIdx = INT_MAX;
9899
99100 int getLastStateNumber() const { return CxxUnwindMap.size() - 1; }
100101
899899 uint64_t MaxAlign = calculateMaxStackAlign(MF); // Desired stack alignment.
900900 uint64_t StackSize = MFI->getStackSize(); // Number of bytes to allocate.
901901 bool IsFunclet = MBB.isEHFuncletEntry();
902 bool IsClrFunclet =
903 IsFunclet &&
902 bool FnHasClrFunclet =
903 MMI.hasEHFunclets() &&
904904 classifyEHPersonality(Fn->getPersonalityFn()) == EHPersonality::CoreCLR;
905 bool IsClrFunclet = IsFunclet && FnHasClrFunclet;
905906 bool HasFP = hasFP(MF);
906907 bool IsWin64CC = STI.isCallingConvWin64(Fn->getCallingConv());
907908 bool IsWin64Prologue = MF.getTarget().getMCAsmInfo()->usesWindowsCFI();
11931194 .setMIFlag(MachineInstr::FrameSetup);
11941195
11951196 int SEHFrameOffset = 0;
1196 unsigned SPOrEstablisher = IsFunclet ? Establisher : StackPtr;
1197 unsigned SPOrEstablisher;
1198 if (IsFunclet) {
1199 if (IsClrFunclet) {
1200 // The establisher parameter passed to a CLR funclet is actually a pointer
1201 // to the (mostly empty) frame of its nearest enclosing funclet; we have
1202 // to find the root function establisher frame by loading the PSPSym from
1203 // the intermediate frame.
1204 unsigned PSPSlotOffset = getPSPSlotOffsetFromSP(MF);
1205 MachinePointerInfo NoInfo;
1206 MBB.addLiveIn(Establisher);
1207 addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64rm), Establisher),
1208 Establisher, false, PSPSlotOffset)
1209 .addMemOperand(MF.getMachineMemOperand(
1210 NoInfo, MachineMemOperand::MOLoad, SlotSize, SlotSize));
1211 ;
1212 // Save the root establisher back into the current funclet's (mostly
1213 // empty) frame, in case a sub-funclet or the GC needs it.
1214 addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64mr)), StackPtr,
1215 false, PSPSlotOffset)
1216 .addReg(Establisher)
1217 .addMemOperand(
1218 MF.getMachineMemOperand(NoInfo, MachineMemOperand::MOStore |
1219 MachineMemOperand::MOVolatile,
1220 SlotSize, SlotSize));
1221 }
1222 SPOrEstablisher = Establisher;
1223 } else {
1224 SPOrEstablisher = StackPtr;
1225 }
1226
11971227 if (IsWin64Prologue && HasFP) {
11981228 // Set RBP to a small fixed offset from RSP. In the funclet case, we base
11991229 // this calculation on the incoming establisher, which holds the value of
12411271 if (NeedsWinCFI)
12421272 BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_EndPrologue))
12431273 .setMIFlag(MachineInstr::FrameSetup);
1274
1275 if (FnHasClrFunclet && !IsFunclet) {
1276 // Save the so-called Initial-SP (i.e. the value of the stack pointer
1277 // immediately after the prolog) into the PSPSlot so that funclets
1278 // and the GC can recover it.
1279 unsigned PSPSlotOffset = getPSPSlotOffsetFromSP(MF);
1280 auto PSPInfo = MachinePointerInfo::getFixedStack(
1281 MF, MF.getMMI().getWinEHFuncInfo(Fn).PSPSymFrameIdx);
1282 addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64mr)), StackPtr, false,
1283 PSPSlotOffset)
1284 .addReg(StackPtr)
1285 .addMemOperand(MF.getMachineMemOperand(
1286 PSPInfo, MachineMemOperand::MOStore | MachineMemOperand::MOVolatile,
1287 SlotSize, SlotSize));
1288 }
12441289
12451290 // Realign stack after we spilled callee-saved registers (so that we'll be
12461291 // able to calculate their offsets from the frame pointer).
13271372 llvm_unreachable("impossible");
13281373 }
13291374
1330 unsigned X86FrameLowering::getWinEHFuncletFrameSize(const MachineFunction &MF) const {
1375 // CLR funclets use a special "Previous Stack Pointer Symbol" slot on the
1376 // stack. It holds a pointer to the bottom of the root function frame. The
1377 // establisher frame pointer passed to a nested funclet may point to the
1378 // (mostly empty) frame of its parent funclet, but it will need to find
1379 // the frame of the root function to access locals. To facilitate this,
1380 // every funclet copies the pointer to the bottom of the root function
1381 // frame into a PSPSym slot in its own (mostly empty) stack frame. Using the
1382 // same offset for the PSPSym in the root function frame that's used in the
1383 // funclets' frames allows each funclet to dynamically accept any ancestor
1384 // frame as its establisher argument (the runtime doesn't guarantee the
1385 // immediate parent for some reason lost to history), and also allows the GC,
1386 // which uses the PSPSym for some bookkeeping, to find it in any funclet's
1387 // frame with only a single offset reported for the entire method.
1388 unsigned
1389 X86FrameLowering::getPSPSlotOffsetFromSP(const MachineFunction &MF) const {
1390 MachineModuleInfo &MMI = MF.getMMI();
1391 WinEHFuncInfo &Info = MMI.getWinEHFuncInfo(MF.getFunction());
1392 // getFrameIndexReferenceFromSP has an out ref parameter for the stack
1393 // pointer register; pass a dummy that we ignore
1394 unsigned SPReg;
1395 int Offset = getFrameIndexReferenceFromSP(MF, Info.PSPSymFrameIdx, SPReg);
1396 assert(Offset >= 0);
1397 return static_cast(Offset);
1398 }
1399
1400 unsigned
1401 X86FrameLowering::getWinEHFuncletFrameSize(const MachineFunction &MF) const {
13311402 // This is the size of the pushed CSRs.
13321403 unsigned CSSize =
13331404 MF.getInfo()->getCalleeSavedFrameSize();
13341405 // This is the amount of stack a funclet needs to allocate.
1335 unsigned MaxCallSize = MF.getFrameInfo()->getMaxCallFrameSize();
1406 unsigned UsedSize;
1407 EHPersonality Personality =
1408 classifyEHPersonality(MF.getFunction()->getPersonalityFn());
1409 if (Personality == EHPersonality::CoreCLR) {
1410 // CLR funclets need to hold enough space to include the PSPSym, at the
1411 // same offset from the stack pointer (immediately after the prolog) as it
1412 // resides at in the main function.
1413 UsedSize = getPSPSlotOffsetFromSP(MF) + SlotSize;
1414 } else {
1415 // Other funclets just need enough stack for outgoing call arguments.
1416 UsedSize = MF.getFrameInfo()->getMaxCallFrameSize();
1417 }
13361418 // RBP is not included in the callee saved register block. After pushing RBP,
13371419 // everything is 16 byte aligned. Everything we allocate before an outgoing
13381420 // call must also be 16 byte aligned.
13391421 unsigned FrameSizeMinusRBP =
1340 RoundUpToAlignment(CSSize + MaxCallSize, getStackAlignment());
1422 RoundUpToAlignment(CSSize + UsedSize, getStackAlignment());
13411423 // Subtract out the size of the callee saved registers. This is how much stack
13421424 // each funclet will allocate.
13431425 return FrameSizeMinusRBP - CSSize;
186186 DebugLoc DL, int64_t Offset,
187187 bool InEpilogue) const;
188188
189 unsigned getPSPSlotOffsetFromSP(const MachineFunction &MF) const;
190
189191 unsigned getWinEHFuncletFrameSize(const MachineFunction &MF) const;
190192 };
191193
28772877
28782878 FuncInfo->setArgumentStackSize(StackSize);
28792879
2880 if (MMI.hasWinEHFuncInfo(Fn) && Is64Bit &&
2881 classifyEHPersonality(Fn->getPersonalityFn()) ==
2882 EHPersonality::MSVC_CXX) {
2883 int UnwindHelpFI = MFI->CreateStackObject(8, 8, /*isSS=*/false);
2884 SDValue StackSlot = DAG.getFrameIndex(UnwindHelpFI, MVT::i64);
2885 MMI.getWinEHFuncInfo(MF.getFunction()).UnwindHelpFrameIdx = UnwindHelpFI;
2886 SDValue Neg2 = DAG.getConstant(-2, dl, MVT::i64);
2887 Chain = DAG.getStore(Chain, dl, Neg2, StackSlot,
2888 MachinePointerInfo::getFixedStack(
2889 DAG.getMachineFunction(), UnwindHelpFI),
2890 /*isVolatile=*/true,
2891 /*isNonTemporal=*/false, /*Alignment=*/0);
2880 if (MMI.hasWinEHFuncInfo(Fn)) {
2881 EHPersonality Personality = classifyEHPersonality(Fn->getPersonalityFn());
2882 if (Personality == EHPersonality::MSVC_CXX) {
2883 if (Is64Bit) {
2884 int UnwindHelpFI = MFI->CreateStackObject(8, 8, /*isSS=*/false);
2885 SDValue StackSlot = DAG.getFrameIndex(UnwindHelpFI, MVT::i64);
2886 MMI.getWinEHFuncInfo(MF.getFunction()).UnwindHelpFrameIdx =
2887 UnwindHelpFI;
2888 SDValue Neg2 = DAG.getConstant(-2, dl, MVT::i64);
2889 Chain = DAG.getStore(Chain, dl, Neg2, StackSlot,
2890 MachinePointerInfo::getFixedStack(
2891 DAG.getMachineFunction(), UnwindHelpFI),
2892 /*isVolatile=*/true,
2893 /*isNonTemporal=*/false, /*Alignment=*/0);
2894 }
2895 } else if (Personality == EHPersonality::CoreCLR) {
2896 assert(Is64Bit);
2897 // TODO: Add a mechanism to frame lowering that will allow us to indicate
2898 // that we'd prefer this slot be allocated towards the bottom of the frame
2899 // (i.e. near the stack pointer after allocating the frame). Every
2900 // funclet needs a copy of this slot in its (mostly empty) frame, and the
2901 // offset from the bottom of this and each funclet's frame must be the
2902 // same, so the size of funclets' (mostly empty) frames is dictated by
2903 // how far this slot is from the bottom (since they allocate just enough
2904 // space to accomodate holding this slot at the correct offset).
2905 int PSPSymFI = MFI->CreateStackObject(8, 8, /*isSS=*/false);
2906 MMI.getWinEHFuncInfo(MF.getFunction()).PSPSymFrameIdx = PSPSymFI;
2907 }
28922908 }
28932909
28942910 return Chain;
None ; RUN: llc -mtriple=x86_64-pc-windows-coreclr < %s | FileCheck %s
0 ; RUN: llc -mtriple=x86_64-pc-windows-coreclr -verify-machineinstrs < %s | FileCheck %s
11
22 declare void @ProcessCLRException()
33 declare void @f(i32)
3131 define void @test1() personality i8* bitcast (void ()* @ProcessCLRException to i8*) {
3232 entry:
3333 ; CHECK: # %entry
34 ; CHECK: .seh_endprologue
34 ; CHECK: leaq [[FPOffset:[0-9]+]](%rsp), %rbp
35 ; CHECK: .seh_endprologue
36 ; CHECK: movq %rsp, [[PSPSymOffset:[0-9]+]](%rsp)
3537 ; CHECK: [[L_before_f1:.+]]:
3638 ; CHECK-NEXT: movl $1, %ecx
3739 ; CHECK-NEXT: callq f
5153 %catch1 = catchpad [i32 1]
5254 to label %catch1.body unwind label %catch2.pad
5355 catch1.body:
54 ; CHECK: leaq {{[0-9]+}}(%rcx), %rbp
55 ; ^ establisher frame pointer passed in rcx
56 ; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
57 ; ^ all funclets use the same frame size
58 ; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
59 ; ^ establisher frame pointer passed in rcx
60 ; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)
61 ; CHECK: leaq [[FPOffset]](%rcx), %rbp
5662 ; CHECK: .seh_endprologue
5763 ; CHECK: movq %rdx, %rcx
5864 ; ^ exception pointer passed in rdx
7278 %catch2 = catchpad [i32 2]
7379 to label %catch2.body unwind label %catch.end
7480 catch2.body:
75 ; CHECK: leaq {{[0-9]+}}(%rcx), %rbp
76 ; ^ establisher frame pointer passed in rcx
81 ; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
82 ; ^ all funclets use the same frame size
83 ; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
84 ; ^ establisher frame pointer passed in rcx
85 ; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)
86 ; CHECK: leaq [[FPOffset]](%rcx), %rbp
7787 ; CHECK: .seh_endprologue
7888 ; CHECK: movq %rdx, %rcx
7989 ; ^ exception pointer passed in rdx
97107 fault.pad:
98108 ; CHECK: .seh_proc [[L_fault:[^ ]+]]
99109 %fault = cleanuppad [i32 undef]
100 ; CHECK: leaq {{[0-9]+}}(%rcx), %rbp
101 ; ^ establisher frame pointer passed in rcx
110 ; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
111 ; ^ all funclets use the same frame size
112 ; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
113 ; ^ establisher frame pointer passed in rcx
114 ; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)
115 ; CHECK: leaq [[FPOffset]](%rcx), %rbp
102116 ; CHECK: .seh_endprologue
103117 ; CHECK: [[L_before_f6:.+]]:
104118 ; CHECK-NEXT: movl $6, %ecx
120134 finally.pad:
121135 ; CHECK: .seh_proc [[L_finally:[^ ]+]]
122136 %finally = cleanuppad []
123 ; CHECK: leaq {{[0-9]+}}(%rcx), %rbp
124 ; ^ establisher frame pointer passed in rcx
137 ; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
138 ; ^ all funclets use the same frame size
139 ; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
140 ; ^ establisher frame pointer passed in rcx
141 ; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)
142 ; CHECK: leaq [[FPOffset]](%rcx), %rbp
125143 ; CHECK: .seh_endprologue
126144 ; CHECK: [[L_before_f7:.+]]:
127145 ; CHECK-NEXT: movl $7, %ecx