WinEH: Create a parent frame alloca for HandlerType xdata tables
authorDavid Majnemer <david.majnemer@gmail.com>
Fri, 27 Mar 2015 04:17:07 +0000 (04:17 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Fri, 27 Mar 2015 04:17:07 +0000 (04:17 +0000)
We don't have any logic to emit those tables yet, so the SDAG lowering
of this intrinsic is just a stub.  We can see the intrinsic in the
prepared IR, though.

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

docs/ExceptionHandling.rst
include/llvm/IR/Intrinsics.td
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
lib/CodeGen/WinEHPrepare.cpp
lib/IR/Verifier.cpp
test/CodeGen/WinEH/cppeh-catch-unwind.ll

index 21de19b0752c7bbf3983cb966a9a8c1ab7e86eea..26774e63ed0f56b6990c00bfda532eaa5a957d80 100644 (file)
@@ -551,6 +551,17 @@ This object is used by Windows native exception handling on non-x86 platforms
 where xdata unwind information is used. It is typically an 8 byte chunk of
 memory treated as two 32-bit integers.
 
+``llvm.eh.parentframe``
+----------------------
+
+.. code-block:: llvm
+
+  void @llvm.eh.parentframe(i8*)
+
+This intrinsic designates the provided static alloca as the object which holds
+the address of the parent frame.
+This object is used by Windows native exception handling on non-x86 platforms
+where xdata unwind information is used.
 
 SJLJ Intrinsics
 ---------------
index da9d8cb61f52536c9a0f730a33bbcc2b10fda503..c5ab91ec9b544740806785f719ca2f310ad90cec 100644 (file)
@@ -425,6 +425,10 @@ def int_eh_actions : Intrinsic<[llvm_ptr_ty], [llvm_vararg_ty], []>;
 // for WinEH.
 def int_eh_unwindhelp : Intrinsic<[], [llvm_ptr_ty], []>;
 
+// Designates the provided static alloca as the object which holds the address
+// of the parent frame. Required for WinEH.
+def int_eh_parentframe : Intrinsic<[], [llvm_ptrptr_ty], []>;
+
 // __builtin_unwind_init is an undocumented GCC intrinsic that causes all
 // callee-saved registers to be saved and restored (regardless of whether they
 // are used) in the calling function. It is used by libgcc_eh.
index 6c14e7969c54666424cc2e7a7017821c94b2e219..6a08fff09cdccd200075ad33c3562dafc6904e34 100644 (file)
@@ -5446,13 +5446,23 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
   case Intrinsic::eh_begincatch:
   case Intrinsic::eh_endcatch:
     llvm_unreachable("begin/end catch intrinsics not lowered in codegen");
+  case Intrinsic::eh_parentframe: {
+    AllocaInst *Slot =
+        cast<AllocaInst>(I.getArgOperand(0)->stripPointerCasts());
+    assert(FuncInfo.StaticAllocaMap.count(Slot) &&
+           "can only use static allocas with llvm.eh.parentframe");
+    int FI = FuncInfo.StaticAllocaMap[Slot];
+    // TODO: Save this in the not-yet-existent WinEHFuncInfo struct.
+    (void)FI;
+    return nullptr;
+  }
   case Intrinsic::eh_unwindhelp: {
     AllocaInst *Slot =
         cast<AllocaInst>(I.getArgOperand(0)->stripPointerCasts());
     assert(FuncInfo.StaticAllocaMap.count(Slot) &&
            "can only use static allocas with llvm.eh.unwindhelp");
     int FI = FuncInfo.StaticAllocaMap[Slot];
-    // TODO: Save this in the not-yet-existant WinEHFuncInfo struct.
+    // TODO: Save this in the not-yet-existent WinEHFuncInfo struct.
     (void)FI;
     return nullptr;
   }
index ab0f96ef05fb17d63c45193da3b3f83c09711ef3..3f9aaec366e4d37e330b13fd566efb94a5f35818 100644 (file)
@@ -695,6 +695,16 @@ bool WinEHPrepare::outlineHandler(ActionHandler *Action, Function *SrcFn,
   if (!LPadMap.isInitialized())
     LPadMap.mapLandingPad(LPad);
   if (auto *CatchAction = dyn_cast<CatchHandler>(Action)) {
+    // Insert an alloca for the object which holds the address of the parent's
+    // frame pointer.  The stack offset of this object needs to be encoded in
+    // xdata.
+    AllocaInst *ParentFrame = new AllocaInst(Int8PtrType, "parentframe", Entry);
+    Builder.CreateStore(&Handler->getArgumentList().back(), ParentFrame,
+                        /*isStore=*/true);
+    Function *ParentFrameFn =
+        Intrinsic::getDeclaration(M, Intrinsic::eh_parentframe);
+    Builder.CreateCall(ParentFrameFn, ParentFrame);
+
     Constant *Sel = CatchAction->getSelector();
     Director.reset(new WinEHCatchDirector(Handler, Sel, VarInfo, LPadMap));
     LPadMap.remapSelector(VMap, ConstantInt::get(Type::getInt32Ty(Context), 1));
index fcf48c452e2102a04e01af072750699e6700ef6b..248d1279eafc5fbc48c1c75859b2fb0c6b32578f 100644 (file)
@@ -2909,6 +2909,13 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
     break;
   }
 
+  case Intrinsic::eh_parentframe: {
+    auto *AI = dyn_cast<AllocaInst>(CI.getArgOperand(0)->stripPointerCasts());
+    Assert(AI && AI->isStaticAlloca(),
+           "llvm.eh.parentframe requires a static alloca", &CI);
+    break;
+  }
+
   case Intrinsic::eh_unwindhelp: {
     auto *AI = dyn_cast<AllocaInst>(CI.getArgOperand(0)->stripPointerCasts());
     Assert(AI && AI->isStaticAlloca(),
index 3db1635a110c8dc7daa813082952c78de646578d..a9849d9cb1c59ca9a19d0da8585428fae0583ed3 100644 (file)
@@ -180,6 +180,9 @@ eh.resume:                                        ; preds = %catch.dispatch7
 
 ; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) {
 ; CHECK: entry:
+; CHECK:   [[PARENTFRAME:\%.+]] = alloca i8*
+; CHECK:   store volatile i8* %1, i8** [[PARENTFRAME]]
+; CHECK:   call void @llvm.eh.parentframe(i8** [[PARENTFRAME]])
 ; CHECK:   [[RECOVER_TMP1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
 ; CHECK:   [[TMP1_PTR:\%.+]] = bitcast i8* [[RECOVER_TMP1]] to i32*
 ; CHECK:   call void @"\01?handle_exception@@YAXXZ"()
@@ -196,6 +199,9 @@ eh.resume:                                        ; preds = %catch.dispatch7
 
 ; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch1"(i8*, i8*) {
 ; CHECK: entry:
+; CHECK:   [[PARENTFRAME:\%.+]] = alloca i8*
+; CHECK:   store volatile i8* %1, i8** [[PARENTFRAME]]
+; CHECK:   call void @llvm.eh.parentframe(i8** [[PARENTFRAME]])
 ; CHECK:   [[RECOVER_TMP0:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2)
 ; CHECK:   [[TMP0_PTR:\%.+]] = bitcast i8* [[RECOVER_TMP0]] to i32*
 ; CHECK:   invoke void @"\01?handle_exception@@YAXXZ"()