/// the parent's frame or return address, and so on.
FRAMEADDR,
RETURNADDR,
+
+ /// ADDROFRETURNADDR - Represents the llvm.addressofreturnaddress intrinsic.
+ /// This node takes no operand, returns a target-specific pointer to the
+ /// place in the stack frame where the return address of the current
+ /// function is stored.
ADDROFRETURNADDR,
+
+ /// SPONENTRY - Represents the llvm.sponentry intrinsic. Takes no argument
+ /// and returns the stack pointer value at the entry of the current
+ /// function calling this intrinsic.
SPONENTRY,
/// LOCAL_RECOVER - Represents the llvm.localrecover intrinsic.
EVT VT = Op.getValueType();
SDLoc DL(Op);
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
+ SDValue ReturnAddress;
if (Depth) {
SDValue FrameAddr = LowerFRAMEADDR(Op, DAG);
SDValue Offset = DAG.getConstant(8, DL, getPointerTy(DAG.getDataLayout()));
- return DAG.getLoad(VT, DL, DAG.getEntryNode(),
- DAG.getNode(ISD::ADD, DL, VT, FrameAddr, Offset),
- MachinePointerInfo());
+ ReturnAddress = DAG.getLoad(
+ VT, DL, DAG.getEntryNode(),
+ DAG.getNode(ISD::ADD, DL, VT, FrameAddr, Offset), MachinePointerInfo());
+ } else {
+ // Return LR, which contains the return address. Mark it an implicit
+ // live-in.
+ unsigned Reg = MF.addLiveIn(AArch64::LR, &AArch64::GPR64RegClass);
+ ReturnAddress = DAG.getCopyFromReg(DAG.getEntryNode(), DL, Reg, VT);
+ }
+
+ // The XPACLRI instruction assembles to a hint-space instruction before
+ // Armv8.3-A therefore this instruction can be safely used for any pre
+ // Armv8.3-A architectures. On Armv8.3-A and onwards XPACI is available so use
+ // that instead.
+ SDNode *St;
+ if (Subtarget->hasV8_3aOps()) {
+ St = DAG.getMachineNode(AArch64::XPACI, DL, VT, ReturnAddress);
+ } else {
+ // XPACLRI operates on LR therefore we must move the operand accordingly.
+ SDValue Chain =
+ DAG.getCopyToReg(DAG.getEntryNode(), DL, AArch64::LR, ReturnAddress);
+ St = DAG.getMachineNode(AArch64::XPACLRI, DL, VT, Chain);
}
-
- // Return LR, which contains the return address. Mark it an implicit live-in.
- unsigned Reg = MF.addLiveIn(AArch64::LR, &AArch64::GPR64RegClass);
- return DAG.getCopyFromReg(DAG.getEntryNode(), DL, Reg, VT);
+ return SDValue(St, 0);
}
/// LowerShiftRightParts - Lower SRA_PARTS, which returns two
--- /dev/null
+; RUN: llc < %s -mtriple=arm64-eabi -asm-verbose=false -mattr=v8.2a | FileCheck %s
+; RUN: llc < %s -mtriple=arm64-eabi -asm-verbose=false -mattr=v8.3a | FileCheck %s --check-prefix=CHECKV83
+
+; Armv8.3-A Pointer Authetication requires a special intsruction to strip the
+; pointer authentication code from the pointer.
+; The XPACLRI instruction assembles to a hint-space instruction before Armv8.3-A
+; therefore this instruction can be safely used for any pre Armv8.3-A architectures.
+; On Armv8.3-A and onwards XPACI is available so use that instead.
+
+define i8* @ra0() nounwind readnone {
+entry:
+; CHECK-LABEL: ra0:
+; CHECK-NEXT: str x30, [sp, #-16]!
+; CHECK-NEXT: hint #7
+; CHECK-NEXT: mov x0, x30
+; CHECK-NEXT: ldr x30, [sp], #16
+; CHECK-NEXT: ret
+; CHECKV83: str x30, [sp, #-16]!
+; CHECKV83-NEXT: xpaci x30
+; CHECKV83-NEXT: mov x0, x30
+; CHECKV83-NEXT: ldr x30, [sp], #16
+; CHECKV83-NEXT: ret
+ %0 = tail call i8* @llvm.returnaddress(i32 0)
+ ret i8* %0
+}
+
+define i8* @ra1() nounwind readnone #0 {
+entry:
+; CHECK-LABEL: ra1:
+; CHECK: hint #25
+; CHECK-NEXT: str x30, [sp, #-16]!
+; CHECK-NEXT: hint #7
+; CHECK-NEXT: mov x0, x30
+; CHECK-NEXT: ldr x30, [sp], #16
+; CHECK-NEXT: hint #29
+; CHECK-NEXT: ret
+; CHECKV83: paciasp
+; CHECKV83-NEXT: str x30, [sp, #-16]!
+; CHECKV83-NEXT: xpaci x30
+; CHECKV83-NEXT: mov x0, x30
+; CHECKV83-NEXT: ldr x30, [sp], #16
+; CHECKV83-NEXT: retaa
+ %0 = tail call i8* @llvm.returnaddress(i32 0)
+ ret i8* %0
+}
+
+attributes #0 = { "sign-return-address"="all" }
+
+declare i8* @llvm.returnaddress(i32) nounwind readnone
define i8* @rt0(i32 %x) nounwind readnone {
entry:
; CHECK-LABEL: rt0:
+; CHECK: hint #7
; CHECK: mov x0, x30
; CHECK: ret
%0 = tail call i8* @llvm.returnaddress(i32 0)
; CHECK: mov x29, sp
; CHECK: ldr x[[REG:[0-9]+]], [x29]
; CHECK: ldr x[[REG2:[0-9]+]], [x[[REG]]]
-; CHECK: ldr x0, [x[[REG2]], #8]
+; CHECK: ldr x30, [x[[REG2]], #8]
+; CHECK: hint #7
+; CHECK: mov x0, x30
; CHECK: ldp x29, x30, [sp], #16
; CHECK: ret
%0 = tail call i8* @llvm.returnaddress(i32 2)
define i8* @test_deep_returnaddr() {
; CHECK-LABEL: test_deep_returnaddr:
; CHECK: ldr x[[FRAME_REC:[0-9]+]], [x29]
-; CHECK-OPT: ldr x0, [x[[FRAME_REC]], #8]
+; CHECK-OPT: ldr x30, [x[[FRAME_REC]], #8]
+; CHECK-OPT: hint #7
+; CHECK-OPT: mov x0, x30
; CHECK-FAST: ldr [[TMP:x[0-9]+]], [x[[FRAME_REC]], #8]
; CHECK-FAST: and x0, [[TMP]], #0xffffffff
%val = call i8* @llvm.returnaddress(i32 1)
define i8* @rt0(i32 %x) nounwind readnone {
entry:
; CHECK-LABEL: rt0:
+; CHECK: hint #7
; CHECK: mov x0, x30
%0 = tail call i8* @llvm.returnaddress(i32 0)
ret i8* %0
; CHECK-LABEL: rt2:
; CHECK: ldr x[[reg:[0-9]+]], [x29]
; CHECK: ldr x[[reg]], [x[[reg]]]
-; CHECK: ldr x0, [x[[reg]], #8]
+; CHECK: ldr x30, [x[[reg]], #8]
+; CHECK: hint #7
+; CHECK: mov x0, x30
%0 = tail call i8* @llvm.returnaddress(i32 2)
ret i8* %0
}