From: David Majnemer Date: Fri, 27 Mar 2015 04:17:07 +0000 (+0000) Subject: WinEH: Create a parent frame alloca for HandlerType xdata tables X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=db573736fdcd5cb377c2e585039beaf665bcf64b;p=oota-llvm.git 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 --- 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(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(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(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(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(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"()