summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/docs/LangRef.rst2
-rw-r--r--llvm/lib/Target/AArch64/AArch64ISelLowering.cpp16
-rw-r--r--llvm/test/CodeGen/AArch64/addr-of-ret-addr.ll51
3 files changed, 68 insertions, 1 deletions
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 39134fafd46..8ec51786739 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -10328,7 +10328,7 @@ 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.
+This intrinsic is only implemented for x86 and aarch64.
'``llvm.frameaddress``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index e6a036e64d8..c65af806d51 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -2865,6 +2865,8 @@ SDValue AArch64TargetLowering::LowerOperation(SDValue Op,
return LowerFRAMEADDR(Op, DAG);
case ISD::RETURNADDR:
return LowerRETURNADDR(Op, DAG);
+ case ISD::ADDROFRETURNADDR:
+ return LowerADDROFRETURNADDR(Op, DAG);
case ISD::INSERT_VECTOR_ELT:
return LowerINSERT_VECTOR_ELT(Op, DAG);
case ISD::EXTRACT_VECTOR_ELT:
@@ -5221,6 +5223,20 @@ unsigned AArch64TargetLowering::getRegisterByName(const char* RegName, EVT VT,
+ StringRef(RegName) + "\"."));
}
+SDValue AArch64TargetLowering::LowerADDROFRETURNADDR(SDValue Op,
+ SelectionDAG &DAG) const {
+ DAG.getMachineFunction().getFrameInfo().setFrameAddressIsTaken(true);
+
+ EVT VT = Op.getValueType();
+ SDLoc DL(Op);
+
+ SDValue FrameAddr =
+ DAG.getCopyFromReg(DAG.getEntryNode(), DL, AArch64::FP, VT);
+ SDValue Offset = DAG.getConstant(8, DL, getPointerTy(DAG.getDataLayout()));
+
+ return DAG.getNode(ISD::ADD, DL, VT, FrameAddr, Offset);
+}
+
SDValue AArch64TargetLowering::LowerRETURNADDR(SDValue Op,
SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
diff --git a/llvm/test/CodeGen/AArch64/addr-of-ret-addr.ll b/llvm/test/CodeGen/AArch64/addr-of-ret-addr.ll
new file mode 100644
index 00000000000..247b2825e15
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/addr-of-ret-addr.ll
@@ -0,0 +1,51 @@
+; RUN: llc < %s -disable-fp-elim -mtriple=arm64-windows | FileCheck %s
+
+; Test generated from C code:
+; #include <stdarg.h>
+; void *foo() {
+; return _AddressOfReturnAddress();
+; }
+; int bar(int x(va_list, void*), ...) {
+; va_list y;
+; va_start(y, x);
+; return x(y, _AddressOfReturnAddress()) + 1;
+; }
+
+declare void @llvm.va_start(i8*)
+declare i8* @llvm.addressofreturnaddress()
+
+define dso_local i8* @"foo"() {
+entry:
+ %0 = call i8* @llvm.addressofreturnaddress()
+ ret i8* %0
+
+; CHECK-LABEL: foo
+; CHECK: stp x29, x30, [sp, #-16]!
+; CHECK: mov x29, sp
+; CHECK: add x0, x29, #8
+; CHECK: ldp x29, x30, [sp], #16
+}
+
+define dso_local i32 @"bar"(i32 (i8*, i8*)* %x, ...) {
+entry:
+ %x.addr = alloca i32 (i8*, i8*)*, align 8
+ %y = alloca i8*, align 8
+ store i32 (i8*, i8*)* %x, i32 (i8*, i8*)** %x.addr, align 8
+ %y1 = bitcast i8** %y to i8*
+ call void @llvm.va_start(i8* %y1)
+ %0 = load i32 (i8*, i8*)*, i32 (i8*, i8*)** %x.addr, align 8
+ %1 = call i8* @llvm.addressofreturnaddress()
+ %2 = load i8*, i8** %y, align 8
+ %call = call i32 %0(i8* %2, i8* %1)
+ %add = add nsw i32 %call, 1
+ ret i32 %add
+
+; CHECK-LABEL: bar
+; CHECK: sub sp, sp, #96
+; CHECK: stp x29, x30, [sp, #16]
+; CHECK: add x29, sp, #16
+; CHECK: str x1, [x29, #24]
+; CHECK: add x1, x29, #8
+; CHECK: ldp x29, x30, [sp, #16]
+; CHECK: add sp, sp, #96
+}
OpenPOWER on IntegriCloud