Create llvm.addressofreturnaddress intrinsic

Summary: We need a new LLVM intrinsic to implement MS _AddressOfReturnAddress builtin on 64-bit Windows.

Reviewers: majnemer, rnk

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D25293

llvm-svn: 284061
This commit is contained in:
Albert Gutowski 2016-10-12 22:13:19 +00:00
parent e56bde4149
commit 14303dbdfa
12 changed files with 89 additions and 3 deletions

View File

@ -9294,6 +9294,32 @@ Note that calling this intrinsic does not prevent function inlining or
other aggressive transformations, so the value returned may not be that
of the obvious source-language caller.
'``llvm.addressofreturnaddress``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Syntax:
"""""""
::
declare i8 *@llvm.addressofreturnaddress()
Overview:
"""""""""
The '``llvm.addressofreturnaddress``' intrinsic returns a target-specific
pointer to the place in the stack frame where the return address of the
current function is stored.
Semantics:
""""""""""
Note that calling this intrinsic does not prevent function inlining or
other aggressive transformations, so the value returned may not be that
of the obvious source-language caller.
This intrinsic is only implemented for x86.
'``llvm.frameaddress``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -70,7 +70,7 @@ namespace ISD {
/// of the frame or return address to return. An index of zero corresponds
/// to the current function's frame or return address, an index of one to
/// the parent's frame or return address, and so on.
FRAMEADDR, RETURNADDR,
FRAMEADDR, RETURNADDR, ADDROFRETURNADDR,
/// LOCAL_RECOVER - Represents the llvm.localrecover intrinsic.
/// Materializes the offset from the local object pointer of another

View File

@ -290,6 +290,7 @@ def int_gcwrite : Intrinsic<[],
//===--------------------- Code Generator Intrinsics ----------------------===//
//
def int_returnaddress : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty], [IntrNoMem]>;
def int_addressofreturnaddress : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>;
def int_frameaddress : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty], [IntrNoMem]>;
def int_read_register : Intrinsic<[llvm_anyint_ty], [llvm_metadata_ty],
[IntrReadMem], "llvm.read_register">;

View File

@ -184,6 +184,7 @@ static bool isInertIntrinsic(unsigned ID) {
// TODO: Make this into a covered switch.
switch (ID) {
case Intrinsic::returnaddress:
case Intrinsic::addressofreturnaddress:
case Intrinsic::frameaddress:
case Intrinsic::stacksave:
case Intrinsic::stackrestore:

View File

@ -436,8 +436,14 @@ void IntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
errs() << "WARNING: this target does not support the llvm."
<< (Callee->getIntrinsicID() == Intrinsic::returnaddress ?
"return" : "frame") << "address intrinsic.\n";
CI->replaceAllUsesWith(ConstantPointerNull::get(
cast<PointerType>(CI->getType())));
CI->replaceAllUsesWith(
ConstantPointerNull::get(cast<PointerType>(CI->getType())));
break;
case Intrinsic::addressofreturnaddress:
errs() << "WARNING: this target does not support the "
"llvm.addressofreturnaddress intrinsic.\n";
CI->replaceAllUsesWith(
ConstantPointerNull::get(cast<PointerType>(CI->getType())));
break;
case Intrinsic::prefetch:

View File

@ -1019,6 +1019,7 @@ void SelectionDAGLegalize::LegalizeOp(SDNode *Node) {
case ISD::ADJUST_TRAMPOLINE:
case ISD::FRAMEADDR:
case ISD::RETURNADDR:
case ISD::ADDROFRETURNADDR:
// These operations lie about being legal: when they claim to be legal,
// they should actually be custom-lowered.
Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0));

View File

@ -4770,6 +4770,10 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
TLI.getPointerTy(DAG.getDataLayout()),
getValue(I.getArgOperand(0))));
return nullptr;
case Intrinsic::addressofreturnaddress:
setValue(&I, DAG.getNode(ISD::ADDROFRETURNADDR, sdl,
TLI.getPointerTy(DAG.getDataLayout())));
return nullptr;
case Intrinsic::frameaddress:
setValue(&I, DAG.getNode(ISD::FRAMEADDR, sdl,
TLI.getPointerTy(DAG.getDataLayout()),

View File

@ -100,6 +100,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
case ISD::JumpTable: return "JumpTable";
case ISD::GLOBAL_OFFSET_TABLE: return "GLOBAL_OFFSET_TABLE";
case ISD::RETURNADDR: return "RETURNADDR";
case ISD::ADDROFRETURNADDR: return "ADDROFRETURNADDR";
case ISD::FRAMEADDR: return "FRAMEADDR";
case ISD::LOCAL_RECOVER: return "LOCAL_RECOVER";
case ISD::READ_REGISTER: return "READ_REGISTER";

View File

@ -18931,6 +18931,12 @@ SDValue X86TargetLowering::LowerRETURNADDR(SDValue Op,
MachinePointerInfo());
}
SDValue X86TargetLowering::LowerADDROFRETURNADDR(SDValue Op,
SelectionDAG &DAG) const {
DAG.getMachineFunction().getFrameInfo().setReturnAddressIsTaken(true);
return getReturnAddressFrameIndex(DAG);
}
SDValue X86TargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo &MFI = MF.getFrameInfo();
@ -22056,6 +22062,7 @@ SDValue X86TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::INTRINSIC_VOID:
case ISD::INTRINSIC_W_CHAIN: return LowerINTRINSIC_W_CHAIN(Op, Subtarget, DAG);
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
case ISD::ADDROFRETURNADDR: return LowerADDROFRETURNADDR(Op, DAG);
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
case ISD::FRAME_TO_ARGS_OFFSET:
return LowerFRAME_TO_ARGS_OFFSET(Op, DAG);

View File

@ -1130,6 +1130,7 @@ namespace llvm {
SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerADDROFRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const;

View File

@ -0,0 +1,19 @@
; RUN: llc < %s -disable-fp-elim -march=x86 | FileCheck %s --check-prefix=CHECK-X86
; RUN: llc < %s -disable-fp-elim -march=x86-64 | FileCheck %s --check-prefix=CHECK-X64
define i8* @f() nounwind readnone optsize {
entry:
%0 = tail call i8* @llvm.addressofreturnaddress() ; <i8*> [#uses=1]
ret i8* %0
; CHECK-X86-LABEL: _f:
; CHECK-X86: pushl %ebp
; CHECK-X86: movl %esp, %ebp
; CHECK-X86: leal 4(%ebp), %eax
; CHECK-X64-LABEL: f:
; CHECK-X64: pushq %rbp
; CHECK-X64: movq %rsp, %rbp
; CHECK-X64: leaq 8(%rbp), %rax
}
declare i8* @llvm.addressofreturnaddress() nounwind readnone

View File

@ -184,7 +184,26 @@ define i64 @f10(i64* %foo, i64 %bar, i64 %baz) {
; CHECK-NEXT: popq %rbp
}
define i8* @f11() "no-frame-pointer-elim"="true" {
; CHECK-LABEL: f11:
; CHECK: pushq %rbp
; CHECK: movq %rsp, %rbp
; CHECK: .seh_setframe 5, 0
; CHECK: leaq 8(%rbp), %rax
%aora = call i8* @llvm.addressofreturnaddress()
ret i8* %aora
}
define i8* @f12() {
; CHECK-LABEL: f12:
; CHECK-NOT: push
; CHECK: movq %rsp, %rax
%aora = call i8* @llvm.addressofreturnaddress()
ret i8* %aora
}
declare i8* @llvm.returnaddress(i32) nounwind readnone
declare i8* @llvm.addressofreturnaddress() nounwind readnone
declare i64 @llvm.x86.flags.read.u64()
declare void @llvm.va_start(i8*) nounwind