[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.

llvm-svn: 241643
This commit is contained in:
Reid Kleckner 2015-07-07 23:23:03 +00:00
parent 142ec39739
commit d5afc62ff6
7 changed files with 48 additions and 28 deletions

View File

@ -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 generator cannot determine the frame allocation offset of functions defined in
other modules. other modules.
The ``fp`` argument to '``llvm.localrecover``' must be a frame The ``fp`` argument to '``llvm.localrecover``' must be a frame pointer of a
pointer of a call frame that is currently live. The return value of call frame that is currently live. The return value of '``llvm.localaddress``'
'``llvm.frameaddress``' is one way to produce such a value, but most platforms is one way to produce such a value, but various runtimes also expose a suitable
also expose the frame pointer through stack unwinding mechanisms. pointer in platform-specific ways.
The ``idx`` argument to '``llvm.localrecover``' indicates which alloca passed to The ``idx`` argument to '``llvm.localrecover``' indicates which alloca passed to
'``llvm.localescape``' to recover. It is zero-indexed. '``llvm.localescape``' to recover. It is zero-indexed.

View File

@ -268,15 +268,23 @@ def int_gcwrite : Intrinsic<[],
// //
def int_returnaddress : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty], [IntrNoMem]>; def int_returnaddress : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty], [IntrNoMem]>;
def int_frameaddress : 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], def int_read_register : Intrinsic<[llvm_anyint_ty], [llvm_metadata_ty],
[IntrReadMem], "llvm.read_register">; [IntrReadMem], "llvm.read_register">;
def int_write_register : Intrinsic<[], [llvm_metadata_ty, llvm_anyint_ty], def int_write_register : Intrinsic<[], [llvm_metadata_ty, llvm_anyint_ty],
[], "llvm.write_register">; [], "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 // Note: we treat stacksave/stackrestore as writemem because we don't otherwise
// model their dependencies on allocas. // model their dependencies on allocas.
def int_stacksave : Intrinsic<[llvm_ptr_ty]>, def int_stacksave : Intrinsic<[llvm_ptr_ty]>,

View File

@ -155,7 +155,7 @@ private:
// outlined but before the outlined code is pruned from the parent function. // outlined but before the outlined code is pruned from the parent function.
DenseMap<const BasicBlock *, BasicBlock *> LPadTargetBlocks; DenseMap<const BasicBlock *, BasicBlock *> 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. // 32-bit EH.
DenseMap<Function *, Value *> HandlerToParentFP; DenseMap<Function *, Value *> HandlerToParentFP;
@ -1595,9 +1595,8 @@ void LandingPadMap::remapEHValues(ValueToValueMapTy &VMap, Value *EHPtrValue,
VMap[Extract] = SelectorValue; VMap[Extract] = SelectorValue;
} }
static bool isFrameAddressCall(const Value *V) { static bool isLocalAddressCall(const Value *V) {
return match(const_cast<Value *>(V), return match(const_cast<Value *>(V), m_Intrinsic<Intrinsic::localaddress>());
m_Intrinsic<Intrinsic::frameaddress>(m_SpecificInt(0)));
} }
CloningDirector::CloningAction WinEHCloningDirectorBase::handleInstruction( CloningDirector::CloningAction WinEHCloningDirectorBase::handleInstruction(
@ -1639,9 +1638,9 @@ CloningDirector::CloningAction WinEHCloningDirectorBase::handleInstruction(
if (match(Inst, m_Intrinsic<Intrinsic::eh_typeid_for>())) if (match(Inst, m_Intrinsic<Intrinsic::eh_typeid_for>()))
return handleTypeIdFor(VMap, Inst, NewBB); 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. // which is the FP of the parent.
if (isFrameAddressCall(Inst)) { if (isLocalAddressCall(Inst)) {
VMap[Inst] = ParentFP; VMap[Inst] = ParentFP;
return CloningDirector::SkipInstruction; return CloningDirector::SkipInstruction;
} }
@ -2233,16 +2232,16 @@ static void createCleanupHandler(LandingPadActions &Actions,
static CallSite matchOutlinedFinallyCall(BasicBlock *BB, static CallSite matchOutlinedFinallyCall(BasicBlock *BB,
Instruction *MaybeCall) { Instruction *MaybeCall) {
// Look for finally blocks that Clang has already outlined for us. // 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) // call void @"fin$parent"(iN 1, i8* %fp)
if (isFrameAddressCall(MaybeCall) && MaybeCall != BB->getTerminator()) if (isLocalAddressCall(MaybeCall) && MaybeCall != BB->getTerminator())
MaybeCall = MaybeCall->getNextNode(); MaybeCall = MaybeCall->getNextNode();
CallSite FinallyCall(MaybeCall); CallSite FinallyCall(MaybeCall);
if (!FinallyCall || FinallyCall.arg_size() != 2) if (!FinallyCall || FinallyCall.arg_size() != 2)
return CallSite(); return CallSite();
if (!match(FinallyCall.getArgument(0), m_SpecificInt(1))) if (!match(FinallyCall.getArgument(0), m_SpecificInt(1)))
return CallSite(); return CallSite();
if (!isFrameAddressCall(FinallyCall.getArgument(1))) if (!isLocalAddressCall(FinallyCall.getArgument(1)))
return CallSite(); return CallSite();
return FinallyCall; return FinallyCall;
} }

View File

@ -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"); "llvm.x86.seh.recoverfp must take a function as the first argument");
return recoverFramePointer(DAG, Fn, IncomingFPOp); 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);
}
} }
} }

View File

@ -14,7 +14,7 @@ declare i32 @puts(i8*)
declare void @may_crash() declare void @may_crash()
declare i32 @__C_specific_handler(...) declare i32 @__C_specific_handler(...)
declare i8* @llvm.localrecover(i8*, i8*, i32) #1 declare i8* @llvm.localrecover(i8*, i8*, i32) #1
declare i8* @llvm.frameaddress(i32) declare i8* @llvm.localaddress()
declare void @llvm.localescape(...) declare void @llvm.localescape(...)
declare dllimport void @EnterCriticalSection(%struct._RTL_CRITICAL_SECTION*) declare dllimport void @EnterCriticalSection(%struct._RTL_CRITICAL_SECTION*)
declare dllimport void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION*) declare dllimport void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION*)
@ -53,7 +53,7 @@ entry:
to label %invoke.cont unwind label %lpad to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry 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 %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* %tmp6 = bitcast i8* %tmp3 to %struct._RTL_CRITICAL_SECTION*
call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp6) call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp6)
@ -62,7 +62,7 @@ invoke.cont: ; preds = %entry
lpad: ; preds = %entry lpad: ; preds = %entry
%tmp7 = landingpad { i8*, i32 } %tmp7 = landingpad { i8*, i32 }
cleanup 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) %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* %tmp12 = bitcast i8* %tmp9 to %struct._RTL_CRITICAL_SECTION*
call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp12) call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp12)

View File

@ -49,12 +49,12 @@ entry:
to label %invoke.cont unwind label %lpad to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry 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 invoke void @"\01?fin$1@0@main@@"(i1 zeroext false, i8* %0) #4
to label %invoke.cont2 unwind label %lpad1 to label %invoke.cont2 unwind label %lpad1
invoke.cont2: ; preds = %invoke.cont 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) call void @"\01?fin$0@0@main@@"(i1 zeroext false, i8* %1)
ret i32 0 ret i32 0
@ -65,7 +65,7 @@ lpad: ; preds = %entry
store i8* %3, i8** %exn.slot store i8* %3, i8** %exn.slot
%4 = extractvalue { i8*, i32 } %2, 1 %4 = extractvalue { i8*, i32 } %2, 1
store i32 %4, i32* %ehselector.slot 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 invoke void @"\01?fin$1@0@main@@"(i1 zeroext true, i8* %5) #4
to label %invoke.cont3 unwind label %lpad1 to label %invoke.cont3 unwind label %lpad1
@ -82,7 +82,7 @@ invoke.cont3: ; preds = %lpad
br label %ehcleanup br label %ehcleanup
ehcleanup: ; preds = %invoke.cont3, %lpad1 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) call void @"\01?fin$0@0@main@@"(i1 zeroext true, i8* %9)
br label %eh.resume br label %eh.resume
@ -146,7 +146,7 @@ entry:
declare i32 @__C_specific_handler(...) declare i32 @__C_specific_handler(...)
; Function Attrs: nounwind readnone ; 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 #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" } 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" }

View File

@ -41,7 +41,7 @@ entry:
to label %invoke.cont unwind label %lpad to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry 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 invoke void @"\01?fin$0@0@use_both@@"(i1 zeroext false, i8* %0) #5
to label %invoke.cont2 unwind label %lpad1 to label %invoke.cont2 unwind label %lpad1
@ -56,7 +56,7 @@ lpad: ; preds = %entry
store i8* %2, i8** %exn.slot store i8* %2, i8** %exn.slot
%3 = extractvalue { i8*, i32 } %1, 1 %3 = extractvalue { i8*, i32 } %1, 1
store i32 %3, i32* %ehselector.slot 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 invoke void @"\01?fin$0@0@use_both@@"(i1 zeroext true, i8* %4) #5
to label %invoke.cont3 unwind label %lpad1 to label %invoke.cont3 unwind label %lpad1
@ -153,7 +153,7 @@ declare i32 @puts(i8*) #3
declare i32 @__C_specific_handler(...) declare i32 @__C_specific_handler(...)
; Function Attrs: nounwind readnone ; Function Attrs: nounwind readnone
declare i8* @llvm.frameaddress(i32) #4 declare i8* @llvm.localaddress() #4
; Function Attrs: nounwind readnone ; Function Attrs: nounwind readnone
declare i32 @llvm.eh.typeid.for(i8*) #4 declare i32 @llvm.eh.typeid.for(i8*) #4