summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Majnemer <david.majnemer@gmail.com>2015-03-27 04:17:07 +0000
committerDavid Majnemer <david.majnemer@gmail.com>2015-03-27 04:17:07 +0000
commitdb573736fdcd5cb377c2e585039beaf665bcf64b (patch)
treea3d4d6f3cf17bdf21398abcf9f6cb397256d830b
parent6284bcd95b6f9c1fcf54985c8361640044067987 (diff)
WinEH: Create a parent frame alloca for HandlerType xdata tables
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
-rw-r--r--docs/ExceptionHandling.rst11
-rw-r--r--include/llvm/IR/Intrinsics.td4
-rw-r--r--lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp12
-rw-r--r--lib/CodeGen/WinEHPrepare.cpp10
-rw-r--r--lib/IR/Verifier.cpp7
-rw-r--r--test/CodeGen/WinEH/cppeh-catch-unwind.ll6
6 files changed, 49 insertions, 1 deletions
diff --git a/docs/ExceptionHandling.rst b/docs/ExceptionHandling.rst
index 21de19b0752..26774e63ed0 100644
--- a/docs/ExceptionHandling.rst
+++ b/docs/ExceptionHandling.rst
@@ -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
---------------
diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td
index da9d8cb61f5..c5ab91ec9b5 100644
--- a/include/llvm/IR/Intrinsics.td
+++ b/include/llvm/IR/Intrinsics.td
@@ -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.
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 6c14e7969c5..6a08fff09cd 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -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;
}
diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp
index ab0f96ef05f..3f9aaec366e 100644
--- a/lib/CodeGen/WinEHPrepare.cpp
+++ b/lib/CodeGen/WinEHPrepare.cpp
@@ -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));
diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp
index fcf48c452e2..248d1279eaf 100644
--- a/lib/IR/Verifier.cpp
+++ b/lib/IR/Verifier.cpp
@@ -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(),
diff --git a/test/CodeGen/WinEH/cppeh-catch-unwind.ll b/test/CodeGen/WinEH/cppeh-catch-unwind.ll
index 3db1635a110..a9849d9cb1c 100644
--- a/test/CodeGen/WinEH/cppeh-catch-unwind.ll
+++ b/test/CodeGen/WinEH/cppeh-catch-unwind.ll
@@ -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"()