From 4fe74caa61ff0a7b08c98a070fd1e4b85d4d9b7f Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 7 Jul 2015 23:23:03 +0000 Subject: [PATCH] [WinEH] Add localaddress intrinsic instead of using frameaddress Clang uses this for SEH finally. The new intrinsic will produce the right value when stack realignment is required. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@241643 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LangRef.rst | 8 ++++---- include/llvm/IR/Intrinsics.td | 16 ++++++++++++---- lib/CodeGen/WinEHPrepare.cpp | 17 ++++++++--------- lib/Target/X86/X86ISelLowering.cpp | 13 +++++++++++++ test/CodeGen/WinEH/seh-inlined-finally.ll | 6 +++--- test/CodeGen/WinEH/seh-outlined-finally.ll | 10 +++++----- test/CodeGen/X86/seh-except-finally.ll | 6 +++--- 7 files changed, 48 insertions(+), 28 deletions(-) diff --git a/docs/LangRef.rst b/docs/LangRef.rst index 877aed2b541..2f8d6f5d5c5 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -7811,10 +7811,10 @@ bitcasted pointer to a function defined in the current module. The code generator cannot determine the frame allocation offset of functions defined in other modules. -The ``fp`` argument to '``llvm.localrecover``' must be a frame -pointer of a call frame that is currently live. The return value of -'``llvm.frameaddress``' is one way to produce such a value, but most platforms -also expose the frame pointer through stack unwinding mechanisms. +The ``fp`` argument to '``llvm.localrecover``' must be a frame pointer of a +call frame that is currently live. The return value of '``llvm.localaddress``' +is one way to produce such a value, but various runtimes also expose a suitable +pointer in platform-specific ways. The ``idx`` argument to '``llvm.localrecover``' indicates which alloca passed to '``llvm.localescape``' to recover. It is zero-indexed. diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td index 5385a91e7b9..cb3cdf354a5 100644 --- a/include/llvm/IR/Intrinsics.td +++ b/include/llvm/IR/Intrinsics.td @@ -268,15 +268,23 @@ def int_gcwrite : Intrinsic<[], // def int_returnaddress : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty], [IntrNoMem]>; def int_frameaddress : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty], [IntrNoMem]>; -def int_localescape : Intrinsic<[], [llvm_vararg_ty]>; -def int_localrecover : Intrinsic<[llvm_ptr_ty], - [llvm_ptr_ty, llvm_ptr_ty, llvm_i32_ty], - [IntrNoMem]>; def int_read_register : Intrinsic<[llvm_anyint_ty], [llvm_metadata_ty], [IntrReadMem], "llvm.read_register">; def int_write_register : Intrinsic<[], [llvm_metadata_ty, llvm_anyint_ty], [], "llvm.write_register">; +// Gets the address of the local variable area. This is typically a copy of the +// stack, frame, or base pointer depending on the type of prologue. +def int_localaddress : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>; + +// Escapes local variables to allow access from other functions. +def int_localescape : Intrinsic<[], [llvm_vararg_ty]>; + +// Given a function and the localaddress of a parent frame, returns a pointer +// to an escaped allocation indicated by the index. +def int_localrecover : Intrinsic<[llvm_ptr_ty], + [llvm_ptr_ty, llvm_ptr_ty, llvm_i32_ty], + [IntrNoMem]>; // Note: we treat stacksave/stackrestore as writemem because we don't otherwise // model their dependencies on allocas. def int_stacksave : Intrinsic<[llvm_ptr_ty]>, diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp index 3447dd14da2..0f84ba0a723 100644 --- a/lib/CodeGen/WinEHPrepare.cpp +++ b/lib/CodeGen/WinEHPrepare.cpp @@ -155,7 +155,7 @@ private: // outlined but before the outlined code is pruned from the parent function. DenseMap LPadTargetBlocks; - // Map from outlined handler to call to llvm.frameaddress(1). Only used for + // Map from outlined handler to call to parent local address. Only used for // 32-bit EH. DenseMap HandlerToParentFP; @@ -1595,9 +1595,8 @@ void LandingPadMap::remapEHValues(ValueToValueMapTy &VMap, Value *EHPtrValue, VMap[Extract] = SelectorValue; } -static bool isFrameAddressCall(const Value *V) { - return match(const_cast(V), - m_Intrinsic(m_SpecificInt(0))); +static bool isLocalAddressCall(const Value *V) { + return match(const_cast(V), m_Intrinsic()); } CloningDirector::CloningAction WinEHCloningDirectorBase::handleInstruction( @@ -1639,9 +1638,9 @@ CloningDirector::CloningAction WinEHCloningDirectorBase::handleInstruction( if (match(Inst, m_Intrinsic())) return handleTypeIdFor(VMap, Inst, NewBB); - // When outlining llvm.frameaddress(i32 0), remap that to the second argument, + // When outlining llvm.localaddress(), remap that to the second argument, // which is the FP of the parent. - if (isFrameAddressCall(Inst)) { + if (isLocalAddressCall(Inst)) { VMap[Inst] = ParentFP; return CloningDirector::SkipInstruction; } @@ -2233,16 +2232,16 @@ static void createCleanupHandler(LandingPadActions &Actions, static CallSite matchOutlinedFinallyCall(BasicBlock *BB, Instruction *MaybeCall) { // Look for finally blocks that Clang has already outlined for us. - // %fp = call i8* @llvm.frameaddress(i32 0) + // %fp = call i8* @llvm.localaddress() // call void @"fin$parent"(iN 1, i8* %fp) - if (isFrameAddressCall(MaybeCall) && MaybeCall != BB->getTerminator()) + if (isLocalAddressCall(MaybeCall) && MaybeCall != BB->getTerminator()) MaybeCall = MaybeCall->getNextNode(); CallSite FinallyCall(MaybeCall); if (!FinallyCall || FinallyCall.arg_size() != 2) return CallSite(); if (!match(FinallyCall.getArgument(0), m_SpecificInt(1))) return CallSite(); - if (!isFrameAddressCall(FinallyCall.getArgument(1))) + if (!isLocalAddressCall(FinallyCall.getArgument(1))) return CallSite(); return FinallyCall; } diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 1b37912cf61..cc9374450ce 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -15737,6 +15737,19 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget *Subtarget "llvm.x86.seh.recoverfp must take a function as the first argument"); return recoverFramePointer(DAG, Fn, IncomingFPOp); } + + case Intrinsic::localaddress: { + // Returns one of the stack, base, or frame pointer registers, depending on + // which is used to reference local variables. + MachineFunction &MF = DAG.getMachineFunction(); + const X86RegisterInfo *RegInfo = Subtarget->getRegisterInfo(); + unsigned Reg; + if (RegInfo->hasBasePointer(MF)) + Reg = RegInfo->getBaseRegister(); + else // This function handles the SP or FP case. + Reg = RegInfo->getPtrSizedFrameRegister(MF); + return DAG.getCopyFromReg(DAG.getEntryNode(), dl, Reg, VT); + } } } diff --git a/test/CodeGen/WinEH/seh-inlined-finally.ll b/test/CodeGen/WinEH/seh-inlined-finally.ll index 6248b74f980..157adf0c818 100644 --- a/test/CodeGen/WinEH/seh-inlined-finally.ll +++ b/test/CodeGen/WinEH/seh-inlined-finally.ll @@ -14,7 +14,7 @@ declare i32 @puts(i8*) declare void @may_crash() declare i32 @__C_specific_handler(...) declare i8* @llvm.localrecover(i8*, i8*, i32) #1 -declare i8* @llvm.frameaddress(i32) +declare i8* @llvm.localaddress() declare void @llvm.localescape(...) declare dllimport void @EnterCriticalSection(%struct._RTL_CRITICAL_SECTION*) declare dllimport void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION*) @@ -53,7 +53,7 @@ entry: to label %invoke.cont unwind label %lpad invoke.cont: ; preds = %entry - %tmp2 = call i8* @llvm.frameaddress(i32 0) + %tmp2 = call i8* @llvm.localaddress() %tmp3 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @call_may_crash_locked to i8*), i8* %tmp2, i32 0) #2 %tmp6 = bitcast i8* %tmp3 to %struct._RTL_CRITICAL_SECTION* call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp6) @@ -62,7 +62,7 @@ invoke.cont: ; preds = %entry lpad: ; preds = %entry %tmp7 = landingpad { i8*, i32 } cleanup - %tmp8 = call i8* @llvm.frameaddress(i32 0) + %tmp8 = call i8* @llvm.localaddress() %tmp9 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @call_may_crash_locked to i8*), i8* %tmp8, i32 0) %tmp12 = bitcast i8* %tmp9 to %struct._RTL_CRITICAL_SECTION* call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp12) diff --git a/test/CodeGen/WinEH/seh-outlined-finally.ll b/test/CodeGen/WinEH/seh-outlined-finally.ll index 3c27212192d..529f85b9602 100644 --- a/test/CodeGen/WinEH/seh-outlined-finally.ll +++ b/test/CodeGen/WinEH/seh-outlined-finally.ll @@ -49,12 +49,12 @@ entry: to label %invoke.cont unwind label %lpad invoke.cont: ; preds = %entry - %0 = call i8* @llvm.frameaddress(i32 0) + %0 = call i8* @llvm.localaddress() invoke void @"\01?fin$1@0@main@@"(i1 zeroext false, i8* %0) #4 to label %invoke.cont2 unwind label %lpad1 invoke.cont2: ; preds = %invoke.cont - %1 = call i8* @llvm.frameaddress(i32 0) + %1 = call i8* @llvm.localaddress() call void @"\01?fin$0@0@main@@"(i1 zeroext false, i8* %1) ret i32 0 @@ -65,7 +65,7 @@ lpad: ; preds = %entry store i8* %3, i8** %exn.slot %4 = extractvalue { i8*, i32 } %2, 1 store i32 %4, i32* %ehselector.slot - %5 = call i8* @llvm.frameaddress(i32 0) + %5 = call i8* @llvm.localaddress() invoke void @"\01?fin$1@0@main@@"(i1 zeroext true, i8* %5) #4 to label %invoke.cont3 unwind label %lpad1 @@ -82,7 +82,7 @@ invoke.cont3: ; preds = %lpad br label %ehcleanup ehcleanup: ; preds = %invoke.cont3, %lpad1 - %9 = call i8* @llvm.frameaddress(i32 0) + %9 = call i8* @llvm.localaddress() call void @"\01?fin$0@0@main@@"(i1 zeroext true, i8* %9) br label %eh.resume @@ -146,7 +146,7 @@ entry: declare i32 @__C_specific_handler(...) ; Function Attrs: nounwind readnone -declare i8* @llvm.frameaddress(i32) #3 +declare i8* @llvm.localaddress() #3 attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" } diff --git a/test/CodeGen/X86/seh-except-finally.ll b/test/CodeGen/X86/seh-except-finally.ll index 4327a64468f..0630d001bb7 100644 --- a/test/CodeGen/X86/seh-except-finally.ll +++ b/test/CodeGen/X86/seh-except-finally.ll @@ -41,7 +41,7 @@ entry: to label %invoke.cont unwind label %lpad invoke.cont: ; preds = %entry - %0 = call i8* @llvm.frameaddress(i32 0) + %0 = call i8* @llvm.localaddress() invoke void @"\01?fin$0@0@use_both@@"(i1 zeroext false, i8* %0) #5 to label %invoke.cont2 unwind label %lpad1 @@ -56,7 +56,7 @@ lpad: ; preds = %entry store i8* %2, i8** %exn.slot %3 = extractvalue { i8*, i32 } %1, 1 store i32 %3, i32* %ehselector.slot - %4 = call i8* @llvm.frameaddress(i32 0) + %4 = call i8* @llvm.localaddress() invoke void @"\01?fin$0@0@use_both@@"(i1 zeroext true, i8* %4) #5 to label %invoke.cont3 unwind label %lpad1 @@ -153,7 +153,7 @@ declare i32 @puts(i8*) #3 declare i32 @__C_specific_handler(...) ; Function Attrs: nounwind readnone -declare i8* @llvm.frameaddress(i32) #4 +declare i8* @llvm.localaddress() #4 ; Function Attrs: nounwind readnone declare i32 @llvm.eh.typeid.for(i8*) #4