diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp --- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp @@ -4881,21 +4881,22 @@ RBI.constrainGenericRegister(DstReg, AArch64::GPR64RegClass, MRI); if (Depth == 0 && IntrinID == Intrinsic::returnaddress) { - if (MFReturnAddr) { - MIRBuilder.buildCopy({DstReg}, MFReturnAddr); - I.eraseFromParent(); - return true; + if (!MFReturnAddr) { + // Insert the copy from LR/X30 into the entry block, before it can be + // clobbered by anything. + MFI.setReturnAddressIsTaken(true); + MFReturnAddr = getFunctionLiveInPhysReg(MF, TII, AArch64::LR, + AArch64::GPR64RegClass); } - MFI.setReturnAddressIsTaken(true); - - // Insert the copy from LR/X30 into the entry block, before it can be - // clobbered by anything. - Register LiveInLR = getFunctionLiveInPhysReg(MF, TII, AArch64::LR, - AArch64::GPR64spRegClass); - MIRBuilder.buildCopy(DstReg, LiveInLR); + if (STI.hasV8_3aOps()) { + MIRBuilder.buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr}); + } else { + MIRBuilder.buildCopy({Register(AArch64::LR)}, {MFReturnAddr}); + MIRBuilder.buildInstr(AArch64::XPACLRI); + MIRBuilder.buildCopy({DstReg}, {Register(AArch64::LR)}); + } - MFReturnAddr = LiveInLR; I.eraseFromParent(); return true; } @@ -4915,7 +4916,16 @@ MIRBuilder.buildCopy({DstReg}, {FrameAddr}); else { MFI.setReturnAddressIsTaken(true); - MIRBuilder.buildInstr(AArch64::LDRXui, {DstReg}, {FrameAddr}).addImm(1); + + if (STI.hasV8_3aOps()) { + Register TmpReg = MRI.createVirtualRegister(&AArch64::GPR64RegClass); + MIRBuilder.buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1); + MIRBuilder.buildInstr(AArch64::XPACI, {DstReg}, {TmpReg}); + } else { + MIRBuilder.buildInstr(AArch64::LDRXui, {Register(AArch64::LR)}, {FrameAddr}).addImm(1); + MIRBuilder.buildInstr(AArch64::XPACLRI); + MIRBuilder.buildCopy({DstReg}, {Register(AArch64::LR)}); + } } I.eraseFromParent(); diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/builtin-return-address-pacret.ll b/llvm/test/CodeGen/AArch64/GlobalISel/builtin-return-address-pacret.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/builtin-return-address-pacret.ll @@ -0,0 +1,103 @@ +;; RUN: llc -mtriple aarch64 -global-isel -O0 %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NOP +;; RUN: llc -mtriple aarch64 -mattr=+v8.3a -global-isel -O0 %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-V83 +declare void @g0() #1 +declare void @g1(i8*) #1 +declare void @g2(i32, i8*) #1 + +declare i8* @llvm.returnaddress(i32 immarg) #2 + +define i8* @f0() #0 { +entry: + %0 = call i8* @llvm.returnaddress(i32 0) + call void @g1(i8* %0) + %1 = call i8* @llvm.returnaddress(i32 1) + call void @g2(i32 1, i8* %1) + %2 = call i8* @llvm.returnaddress(i32 2) + ret i8* %2 +} +;; CHECK-LABEL: f0: +;; CHECK-NOT: {{(mov|ldr)}} x30 +;; CHECK-NOP: hint #7 +;; CHECK-V83: xpaci x30 +;; CHECK: bl g1 +;; CHECK: ldr x[[T0:[0-9]+]], [x29] +;; CHECK-NOP-NEXT: ldr x30, [x[[T0]], #8] +;; CHECK-NOP-NEXT: hint #7 +;; CHECK-V83-NEXT: ldr x[[T0]], [x[[T0]], #8] +;; CHECK-V83-NEXT: xpaci x[[T0]] +;; CHECK: bl g2 +;; CHECK: ldr x[[T1:[0-9]+]], [x29] +;; CHECK-NEXT: ldr x[[T1]], [x[[T1]]] +;; CHECK-NOP-NEXT: ldr x30, [x[[T1]], #8] +;; CHECK-NOP-NEXT: hint #7 +;; CHECK-NOP-NEXT: mov x0, x30 +;; CHECK-V83-NEXT: ldr x[[T1]], [x[[T1]], #8] +;; CHECK-V83-NEXT: xpaci x[[T1]] +;; CHECK-V83-NEXT: mov x0, x[[T1]] + +define i8* @f1() #0 { +entry: + %0 = call i8* @llvm.returnaddress(i32 1) + call void @g1(i8* %0) + %1 = call i8* @llvm.returnaddress(i32 2) + call void @g2(i32 1, i8* %1) + %2 = call i8* @llvm.returnaddress(i32 0) + ret i8* %2 +} +;; CHECK-LABEL: f1: +;; CHECK-DAG: ldr x[[T0:[0-9]+]], [x29] +;; CHECK-NOP-DAG: str x30, [sp, #[[OFF:[0-9]+]] +;; CHECK-NOP: ldr x30, [x[[T0]], #8] +;; CHECK-NOP-NEXT: hint #7 +;; CHECK-V83: ldr x[[T0]], [x[[T0]], #8] +;; CHECK-V83-NEXT: xpaci x[[T0]] +;; CHECK-V83: str x30, [sp, #[[OFF:[0-9]+]] +;; CHECK: bl g1 +;; CHECK: ldr x[[T1:[0-9]+]], [x29] +;; CHECK-NEXT: ldr x[[T1]], [x[[T1]]] +;; CHECK-NOP-NEXT: ldr x30, [x[[T1]], #8] +;; CHECK-NOP-NEXT: hint #7 +;; CHECK-V83-NEXT: ldr x[[T1]], [x[[T1]], #8] +;; CHECK-V83-NEXT: xpaci x[[T1]] +;; CHECK: bl g2 +;; CHECK: ldr x[[T2:[0-9]+]], [sp, #[[OFF]]] +;; CHECK-NOP-NEXT: mov x30, x[[T2]] +;; CHECK-NOP-NEXT: hint #7 +;; CHECK-NOP-NEXT: mov x0, x30 +;; CHECK-V83-NEXT: xpaci x[[T2]] +;; CHECK-V83-NEXT: mov x0, x[[T2]] +;; CHECK-NOT: x0 +;; CHECK: ret + +define i8* @f2() #0 { +entry: + call void bitcast (void ()* @g0 to void ()*)() + %0 = call i8* @llvm.returnaddress(i32 0) + ret i8* %0 +} +;; CHECK-LABEL: f2 +;; CHECK: bl g0 +;; CHECK: ldr x[[T0:[0-9]+]], [sp, +;; CHECK-NOP-NEXT: mov x30, x[[T2]] +;; CHECK-NOP-NEXT: hint #7 +;; CHECK-NOP-NEXT: mov x0, x30 +;; CHECK-V83-NEXT: xpaci x[[T2]] +;; CHECK-V83-NEXT: mov x0, x[[T2]] +;; CHECK-NOT: x0 +;; CHECK: ret + +define i8* @f3() #0 { +entry: + %0 = call i8* @llvm.returnaddress(i32 0) + ret i8* %0 +} +;; CHECK-LABEL: f3: +;; CHECK: str x30, [sp, +;; CHECK-NOP-NEXT: hint #7 +;; CHECK-V83-NEXT: xpaci x30 +;; CHECK-NEXT: mov x0, x30 +;; CHECK-NOT: x0 +;; CHECK: ret +attributes #0 = { nounwind } +attributes #1 = { nounwind } +attributes #2 = { nounwind readnone } diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-returnaddr.ll b/llvm/test/CodeGen/AArch64/GlobalISel/select-returnaddr.ll --- a/llvm/test/CodeGen/AArch64/GlobalISel/select-returnaddr.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-returnaddr.ll @@ -3,8 +3,8 @@ define i8* @rt0(i32 %x) nounwind readnone { entry: ; CHECK-LABEL: rt0: -; CHECK-NOT: stp -; CHECK: mov x0, x30 +; CHECK: hint #7 +; CHECK-NEXT: mov x0, x30 %0 = tail call i8* @llvm.returnaddress(i32 0) ret i8* %0 } @@ -12,12 +12,15 @@ define i8* @rt0_call_clobber(i32 %x) nounwind readnone { entry: ; CHECK-LABEL: rt0_call_clobber: -; CHECK: stp x20, x19, [sp, #-32]! -; CHECK: stp x29, x30, [sp, #16] -; CHECK: mov x19, x30 -; CHECK: bl _foo -; CHECK: ldp x29, x30, [sp, #16] -; CHECK: mov x0, x19 +; CHECK: stp x20, x19, [sp, #-32]! +; CHECK: stp x29, x30, [sp, #16] +; CHECK: mov x19, x30 +; CHECK: bl _foo +; CHECK: mov x30, x19 +; CHECK-NEXT: hint #7 +; CHECK-NEXT: mov x0, x30 +; CHECK-NOT: x0 +; CHECK: ret %ret = call i32 @foo() %0 = tail call i8* @llvm.returnaddress(i32 0) ret i8* %0 @@ -26,9 +29,13 @@ define i8* @rt2() nounwind readnone { entry: ; CHECK-LABEL: rt2: -; CHECK: ldr x[[reg:[0-9]+]], [x29] -; CHECK: ldr x[[reg]], [x[[reg]]] -; CHECK: ldr x0, [x[[reg]], #8] +; CHECK: ldr x[[reg:[0-9]+]], [x29] +; CHECK: ldr x[[reg]], [x[[reg]]] +; CHECK: ldr x30, [x[[reg]], #8] +; CHECK: hint #7 +; CHECK: mov x0, x30 +; CHECK-NOT: x0 +; CHECK: ret %0 = tail call i8* @llvm.returnaddress(i32 2) ret i8* %0 } diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-returnaddress-liveins.mir b/llvm/test/CodeGen/AArch64/GlobalISel/select-returnaddress-liveins.mir --- a/llvm/test/CodeGen/AArch64/GlobalISel/select-returnaddress-liveins.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-returnaddress-liveins.mir @@ -18,9 +18,11 @@ ; CHECK: bb.0: ; CHECK: successors: %bb.1(0x80000000) ; CHECK: liveins: $w0, $x0, $lr - ; CHECK: [[COPY:%[0-9]+]]:gpr64sp = COPY $lr + ; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $lr ; CHECK: bb.1: - ; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY [[COPY]] + ; CHECK: $lr = COPY [[COPY]] + ; CHECK: XPACLRI implicit-def $lr, implicit $lr + ; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY $lr ; CHECK: $x0 = COPY [[COPY1]] ; CHECK: RET_ReallyLR implicit $x0 ; LR should be added as a livein to the entry block. @@ -45,9 +47,11 @@ ; CHECK: bb.0: ; CHECK: successors: %bb.1(0x80000000) ; CHECK: liveins: $w0, $x0, $lr - ; CHECK: [[COPY:%[0-9]+]]:gpr64sp = COPY $lr + ; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $lr ; CHECK: bb.1: - ; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY [[COPY]] + ; CHECK: $lr = COPY [[COPY]] + ; CHECK: XPACLRI implicit-def $lr, implicit $lr + ; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY $lr ; CHECK: $x0 = COPY [[COPY1]] ; CHECK: RET_ReallyLR implicit $x0 ; We should not have LR listed as a livein twice. @@ -74,11 +78,15 @@ ; CHECK: bb.0: ; CHECK: successors: %bb.1(0x80000000) ; CHECK: liveins: $w0, $x0, $lr - ; CHECK: [[COPY:%[0-9]+]]:gpr64sp = COPY $lr - ; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY [[COPY]] + ; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $lr + ; CHECK: $lr = COPY [[COPY]] + ; CHECK: XPACLRI implicit-def $lr, implicit $lr + ; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY $lr ; CHECK: bb.1: ; CHECK: $x0 = COPY [[COPY1]] - ; CHECK: [[COPY2:%[0-9]+]]:gpr64 = COPY [[COPY]] + ; CHECK: $lr = COPY [[COPY]] + ; CHECK: XPACLRI implicit-def $lr, implicit $lr + ; CHECK: [[COPY2:%[0-9]+]]:gpr64 = COPY $lr ; CHECK: RET_ReallyLR implicit [[COPY2]] bb.0: liveins: $w0, $x0, $lr