[WinEH] Make llvm.x86.seh.recoverfp work on x64
authorReid Kleckner <rnk@google.com>
Tue, 15 Dec 2015 23:40:58 +0000 (23:40 +0000)
committerReid Kleckner <rnk@google.com>
Tue, 15 Dec 2015 23:40:58 +0000 (23:40 +0000)
It adjusts from RSP-after-prologue to RBP, which is what SEH filters
need to do before they can use llvm.localrecover.

Fixes SEH filter captures, which were broken in r250088.

Issue reported by Alex Crichton.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@255707 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/CodeGen/WinEHFuncInfo.h
lib/CodeGen/AsmPrinter/WinException.cpp
lib/Target/X86/X86FrameLowering.cpp
lib/Target/X86/X86ISelLowering.cpp
test/CodeGen/X86/catchret-empty-fallthrough.ll
test/CodeGen/X86/seh-catch-all.ll
test/CodeGen/X86/seh-catchpad.ll
test/CodeGen/X86/seh-except-finally.ll
test/CodeGen/X86/seh-finally.ll
test/CodeGen/X86/seh-safe-div.ll

index 599f8595043b38e09fdef390c103d763eec4de06..86ecce3561a606d924a2ccd3dd55fc7819dac9a4 100644 (file)
@@ -108,6 +108,7 @@ struct WinEHFuncInfo {
 
   int EHRegNodeFrameIndex = INT_MAX;
   int EHRegNodeEndOffset = INT_MAX;
+  int SEHSetFrameOffset = INT_MAX;
 
   WinEHFuncInfo() {}
 };
index e299417241544c27ec424b76fc908d1e21a5df8d..c4f650e89e00dedc4601bc272b8e9d0683279394 100644 (file)
@@ -506,8 +506,18 @@ InvokeStateChangeIterator &InvokeStateChangeIterator::scan() {
 void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) {
   auto &OS = *Asm->OutStreamer;
   MCContext &Ctx = Asm->OutContext;
-
   const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();
+
+  // Emit a label assignment with the SEH frame offset so we can use it for
+  // llvm.x86.seh.recoverfp.
+  StringRef FLinkageName =
+      GlobalValue::getRealLinkageName(MF->getFunction()->getName());
+  MCSymbol *ParentFrameOffset =
+      Ctx.getOrCreateParentFrameOffsetSymbol(FLinkageName);
+  const MCExpr *MCOffset =
+      MCConstantExpr::create(FuncInfo.SEHSetFrameOffset, Ctx);
+  Asm->OutStreamer->EmitAssignment(ParentFrameOffset, MCOffset);
+
   // Use the assembler to compute the number of table entries through label
   // difference and division.
   MCSymbol *TableBegin =
index 7841a84326b4a757109f1923597da2920dcd0812..828dd7eca713b584d9812eac72e3707ea5d343ed 100644 (file)
@@ -912,9 +912,11 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
   uint64_t MaxAlign = calculateMaxStackAlign(MF); // Desired stack alignment.
   uint64_t StackSize = MFI->getStackSize();    // Number of bytes to allocate.
   bool IsFunclet = MBB.isEHFuncletEntry();
+  EHPersonality Personality = EHPersonality::Unknown;
+  if (Fn->hasPersonalityFn())
+    Personality = classifyEHPersonality(Fn->getPersonalityFn());
   bool FnHasClrFunclet =
-      MMI.hasEHFunclets() &&
-      classifyEHPersonality(Fn->getPersonalityFn()) == EHPersonality::CoreCLR;
+      MMI.hasEHFunclets() && Personality == EHPersonality::CoreCLR;
   bool IsClrFunclet = IsFunclet && FnHasClrFunclet;
   bool HasFP = hasFP(MF);
   bool IsWin64CC = STI.isCallingConvWin64(Fn->getCallingConv());
@@ -1250,19 +1252,21 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
           .addReg(SPOrEstablisher);
 
     // If this is not a funclet, emit the CFI describing our frame pointer.
-    if (NeedsWinCFI && !IsFunclet)
+    if (NeedsWinCFI && !IsFunclet) {
       BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_SetFrame))
           .addImm(FramePtr)
           .addImm(SEHFrameOffset)
           .setMIFlag(MachineInstr::FrameSetup);
+      if (isAsynchronousEHPersonality(Personality))
+        MF.getWinEHFuncInfo()->SEHSetFrameOffset = SEHFrameOffset;
+    }
   } else if (IsFunclet && STI.is32Bit()) {
     // Reset EBP / ESI to something good for funclets.
     MBBI = restoreWin32EHStackPointers(MBB, MBBI, DL);
     // If we're a catch funclet, we can be returned to via catchret. Save ESP
     // into the registration node so that the runtime will restore it for us.
     if (!MBB.isCleanupFuncletEntry()) {
-      assert(classifyEHPersonality(Fn->getPersonalityFn()) ==
-             EHPersonality::MSVC_CXX);
+      assert(Personality == EHPersonality::MSVC_CXX);
       unsigned FrameReg;
       int FI = MF.getWinEHFuncInfo()->EHRegNodeFrameIndex;
       int64_t EHRegOffset = getFrameIndexReference(MF, FI, FrameReg);
index fa4370085ea97130529543d8f39aa98e53121017..e34534050cc42ec8fe64338890a897f8d871e097 100644 (file)
@@ -16173,12 +16173,12 @@ static int getSEHRegistrationNodeSize(const Function *Fn) {
       "can only recover FP for 32-bit MSVC EH personality functions");
 }
 
-/// When the 32-bit MSVC runtime transfers control to us, either to an outlined
+/// When the MSVC runtime transfers control to us, either to an outlined
 /// function or when returning to a parent frame after catching an exception, we
 /// recover the parent frame pointer by doing arithmetic on the incoming EBP.
 /// Here's the math:
 ///   RegNodeBase = EntryEBP - RegNodeSize
-///   ParentFP = RegNodeBase - RegNodeFrameOffset
+///   ParentFP = RegNodeBase - ParentFrameOffset
 /// Subtracting RegNodeSize takes us to the offset of the registration node, and
 /// subtracting the offset (negative on x86) takes us back to the parent FP.
 static SDValue recoverFramePointer(SelectionDAG &DAG, const Function *Fn,
@@ -16195,22 +16195,28 @@ static SDValue recoverFramePointer(SelectionDAG &DAG, const Function *Fn,
   if (!Fn->hasPersonalityFn())
     return EntryEBP;
 
-  int RegNodeSize = getSEHRegistrationNodeSize(Fn);
-
   // Get an MCSymbol that will ultimately resolve to the frame offset of the EH
-  // registration.
+  // registration, or the .set_setframe offset.
   MCSymbol *OffsetSym =
       MF.getMMI().getContext().getOrCreateParentFrameOffsetSymbol(
           GlobalValue::getRealLinkageName(Fn->getName()));
   SDValue OffsetSymVal = DAG.getMCSymbol(OffsetSym, PtrVT);
-  SDValue RegNodeFrameOffset =
+  SDValue ParentFrameOffset =
       DAG.getNode(ISD::LOCAL_RECOVER, dl, PtrVT, OffsetSymVal);
 
+  // Return EntryEBP + ParentFrameOffset for x64. This adjusts from RSP after
+  // prologue to RBP in the parent function.
+  const X86Subtarget &Subtarget =
+      static_cast<const X86Subtarget &>(DAG.getSubtarget());
+  if (Subtarget.is64Bit())
+    return DAG.getNode(ISD::ADD, dl, PtrVT, EntryEBP, ParentFrameOffset);
+
+  int RegNodeSize = getSEHRegistrationNodeSize(Fn);
   // RegNodeBase = EntryEBP - RegNodeSize
-  // ParentFP = RegNodeBase - RegNodeFrameOffset
+  // ParentFP = RegNodeBase - ParentFrameOffset
   SDValue RegNodeBase = DAG.getNode(ISD::SUB, dl, PtrVT, EntryEBP,
                                     DAG.getConstant(RegNodeSize, dl, PtrVT));
-  return DAG.getNode(ISD::SUB, dl, PtrVT, RegNodeBase, RegNodeFrameOffset);
+  return DAG.getNode(ISD::SUB, dl, PtrVT, RegNodeBase, ParentFrameOffset);
 }
 
 static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget *Subtarget,
index 585f7bc33e3a7a85ae59b50e31c0d1a3eb62a254..5405d570b15e396a86184f17c4bbbc8dba87125b 100644 (file)
@@ -42,6 +42,7 @@ return:                                           ; preds = %catch, %entry
 ; CHECK: .LBB0_[[return]]:
 
 ; CHECK: .seh_handlerdata
+; CHECK-NEXT: .Lfoo$parent_frame_offset = 32
 ; CHECK-NEXT: .long   (.Llsda_end0-.Llsda_begin0)/16
 ; CHECK-NEXT: .Llsda_begin0:
 ; CHECK-NEXT: .long   .Ltmp0@IMGREL+1
index 76823bd476b1c957b80c631b990f154bc65e9a76..c6a2e4a1094aa81b3622f0a71a6d8d3f9d529a1f 100644 (file)
@@ -36,6 +36,7 @@ catchall:
 ; CHECK: callq printf
 
 ; CHECK: .seh_handlerdata
+; CHECK-NEXT: .Lmain$parent_frame_offset
 ; CHECK-NEXT: .long (.Llsda_end0-.Llsda_begin0)/16
 ; CHECK-NEXT: .Llsda_begin0:
 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}}@IMGREL
index 321d3a70cf8afbdbe464aa58afeb657bd1c5b440..d9b4c5c6bcf54032766d731b509ef9a0ba002a86 100644 (file)
@@ -117,6 +117,7 @@ __except.ret:                                     ; preds = %catch.dispatch.7
 ; CHECK:         jmp     .LBB1_[[epilogue]]
 
 ; CHECK:         .seh_handlerdata
+; CHECK-NEXT:         .Lmain$parent_frame_offset = 32
 ; CHECK-NEXT:         .long   (.Llsda_end0-.Llsda_begin0)/16
 ; CHECK-NEXT: .Llsda_begin0:
 ; CHECK-NEXT:         .long   .Ltmp0@IMGREL+1
index c15ecfcd77b261e8cdd39e381dba98e0524c7716..b29788cd015d2c00427dc05c49f69bc8ee05b284 100644 (file)
@@ -79,6 +79,7 @@ __try.cont:                                       ; preds = %__except, %invoke.c
 ; CHECK: retq
 ;
 ; CHECK: .seh_handlerdata
+; CHECK-NEXT: .Luse_both$parent_frame_offset
 ; CHECK-NEXT: .long (.Llsda_end0-.Llsda_begin0)/16
 ; CHECK-NEXT: .Llsda_begin0:
 ; CHECK-NEXT: .long .Ltmp0@IMGREL+1
index 8405d200776d74bfc693c98e23693b13c0b4ab2a..d42dffb8de8f45518c64c057622b4dd46124f73b 100644 (file)
@@ -26,6 +26,7 @@ lpad:                                             ; preds = %entry
 ; X64: retq
 
 ; X64: .seh_handlerdata
+; X64-NEXT: .Lmain$parent_frame_offset = 32
 ; X64-NEXT: .long   (.Llsda_end0-.Llsda_begin0)/16
 ; X64-NEXT: .Llsda_begin0:
 ; X64-NEXT: .long   .Ltmp0@IMGREL+1
index dd5752e8a716995acf13e39dec8cc2ed3aa91174..60918cf07058ac6eebc6ea3d95fdc546b9d38db4 100644 (file)
@@ -78,6 +78,7 @@ __try.cont:
 ; CHECK: jmp [[cont_bb]]
 
 ; CHECK: .seh_handlerdata
+; CHECK-NEXT: .Lsafe_div$parent_frame_offset
 ; CHECK-NEXT: .long (.Llsda_end0-.Llsda_begin0)/16
 ; CHECK-NEXT: .Llsda_begin0:
 ; CHECK-NEXT: .long .Ltmp0@IMGREL+1