diff --git a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp --- a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -3982,7 +3982,7 @@ switch (IntrinID) { default: break; - case Intrinsic::aarch64_crypto_sha1h: + case Intrinsic::aarch64_crypto_sha1h: { Register DstReg = I.getOperand(0).getReg(); Register SrcReg = I.getOperand(2).getReg(); @@ -4021,6 +4021,48 @@ I.eraseFromParent(); return true; } + case Intrinsic::frameaddress: + case Intrinsic::returnaddress: { + MachineFunction &MF = *I.getParent()->getParent(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + + Register DepthReg = I.getOperand(2).getReg(); + MachineInstr &DepthMI = *MRI.def_instr_begin(DepthReg); + assert(DepthMI.getOpcode() == TargetOpcode::G_CONSTANT && + "non-constant frameaddr operand"); + unsigned Depth = DepthMI.getOperand(1).getCImm()->getZExtValue(); + + Register DstReg = I.getOperand(0).getReg(); + RBI.constrainGenericRegister(DstReg, AArch64::GPR64RegClass, MRI); + + if (Depth == 0 && IntrinID == Intrinsic::returnaddress) { + MFI.setReturnAddressIsTaken(true); + MF.addLiveIn(AArch64::LR, &AArch64::GPR64RegClass); + I.getParent()->addLiveIn(AArch64::LR); + MIRBuilder.buildCopy({DstReg}, {AArch64::LR}); + I.eraseFromParent(); + return true; + } + + MFI.setFrameAddressIsTaken(true); + Register FrameAddr(AArch64::FP); + while (Depth--) { + Register NextFrame = MRI.createVirtualRegister(&AArch64::GPR64RegClass); + MIRBuilder.buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0); + FrameAddr = NextFrame; + } + + if (IntrinID == Intrinsic::frameaddress) + MIRBuilder.buildCopy({DstReg}, {FrameAddr}); + else { + MFI.setReturnAddressIsTaken(true); + MIRBuilder.buildInstr(AArch64::LDRXui, {DstReg}, {FrameAddr}).addImm(1); + } + + I.eraseFromParent(); + return true; + } + } return false; } diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-frameaddr.ll b/llvm/test/CodeGen/AArch64/GlobalISel/select-frameaddr.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-frameaddr.ll @@ -0,0 +1,20 @@ +; RUN: llc -mtriple=arm64-apple-ios -global-isel -o - %s | FileCheck %s + +define i8* @rt0(i32 %x) nounwind readnone { +entry: +; CHECK-LABEL: rt0: +; CHECK: mov x0, x29 + %0 = tail call i8* @llvm.frameaddress(i32 0) + ret i8* %0 +} + +define i8* @rt2() nounwind readnone { +entry: +; CHECK-LABEL: rt2: +; CHECK: ldr x[[reg:[0-9]+]], [x29] +; CHECK: ldr x0, [x[[reg]]] + %0 = tail call i8* @llvm.frameaddress(i32 2) + ret i8* %0 +} + +declare i8* @llvm.frameaddress(i32) nounwind readnone diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-returnaddr.ll b/llvm/test/CodeGen/AArch64/GlobalISel/select-returnaddr.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-returnaddr.ll @@ -0,0 +1,22 @@ +; RUN: llc -mtriple=arm64-apple-ios -global-isel -o - %s | FileCheck %s + +define i8* @rt0(i32 %x) nounwind readnone { +entry: +; CHECK-LABEL: rt0: +; CHECK-NOT: stp +; CHECK: mov x0, x30 + %0 = tail call i8* @llvm.returnaddress(i32 0) + ret i8* %0 +} + +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] + %0 = tail call i8* @llvm.returnaddress(i32 2) + ret i8* %0 +} + +declare i8* @llvm.returnaddress(i32) nounwind readnone