diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index f88bd9b45aee60..3db777f904df0a 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -3620,9 +3620,17 @@ SDValue SystemZTargetLowering::lowerFRAMEADDR(SDValue Op, int BackChainIdx = TFL->getOrCreateFramePointerSaveIndex(MF); SDValue BackChain = DAG.getFrameIndex(BackChainIdx, PtrVT); - // FIXME The frontend should detect this case. if (Depth > 0) { - report_fatal_error("Unsupported stack frame traversal count"); + // FIXME The frontend should detect this case. + if (!MF.getFunction().hasFnAttribute("backchain")) + report_fatal_error("Unsupported stack frame traversal count"); + + SDValue Offset = DAG.getConstant(TFL->getBackchainOffset(MF), DL, PtrVT); + while (Depth--) { + BackChain = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), BackChain, + MachinePointerInfo()); + BackChain = DAG.getNode(ISD::ADD, DL, PtrVT, BackChain, Offset); + } } return BackChain; @@ -3641,9 +3649,19 @@ SDValue SystemZTargetLowering::lowerRETURNADDR(SDValue Op, unsigned Depth = cast(Op.getOperand(0))->getZExtValue(); EVT PtrVT = getPointerTy(DAG.getDataLayout()); - // FIXME The frontend should detect this case. if (Depth > 0) { - report_fatal_error("Unsupported stack frame traversal count"); + // FIXME The frontend should detect this case. + if (!MF.getFunction().hasFnAttribute("backchain")) + report_fatal_error("Unsupported stack frame traversal count"); + + SDValue FrameAddr = lowerFRAMEADDR(Op, DAG); + auto *TFL = Subtarget.getFrameLowering(); + int Offset = (TFL->usePackedStack(MF) ? -2 : 14) * + getTargetMachine().getPointerSize(0); + SDValue Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, FrameAddr, + DAG.getConstant(Offset, DL, PtrVT)); + return DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), Ptr, + MachinePointerInfo()); } // Return R14D, which has the return address. Mark it an implicit live-in. diff --git a/llvm/test/CodeGen/SystemZ/frameaddr-01.ll b/llvm/test/CodeGen/SystemZ/frameaddr-01.ll index db3d7b33f94cae..e8521883f08873 100644 --- a/llvm/test/CodeGen/SystemZ/frameaddr-01.ll +++ b/llvm/test/CodeGen/SystemZ/frameaddr-01.ll @@ -25,4 +25,25 @@ entry: ret ptr %1 } +; Check the caller's frame address. +define ptr @fpcaller() nounwind "backchain" { +entry: +; CHECK-LABEL: fpcaller: +; CHECK: lg %r2, 0(%r15) +; CHECK: br %r14 + %0 = tail call ptr @llvm.frameaddress(i32 1) + ret ptr %0 +} + +; Check the caller's frame address. +define ptr @fpcallercaller() nounwind "backchain" { +entry: +; CHECK-LABEL: fpcallercaller: +; CHECK: lg %r1, 0(%r15) +; CHECK: lg %r2, 0(%r1) +; CHECK: br %r14 + %0 = tail call ptr @llvm.frameaddress(i32 2) + ret ptr %0 +} + declare ptr @llvm.frameaddress(i32) nounwind readnone diff --git a/llvm/test/CodeGen/SystemZ/frameaddr-02.ll b/llvm/test/CodeGen/SystemZ/frameaddr-02.ll index a5e7e701c30e2d..d3977928d41b87 100644 --- a/llvm/test/CodeGen/SystemZ/frameaddr-02.ll +++ b/llvm/test/CodeGen/SystemZ/frameaddr-02.ll @@ -27,6 +27,29 @@ entry: ret ptr %1 } +; Check the caller's frame address. +define ptr @fpcaller() #0 { +entry: +; CHECK-LABEL: fpcaller: +; CHECK: lghi %r2, 152 +; CHECK: ag %r2, 152(%r15) +; CHECK: br %r14 + %0 = tail call ptr @llvm.frameaddress(i32 1) + ret ptr %0 +} + +; Check the caller's caller's frame address. +define ptr @fpcallercaller() #0 { +entry: +; CHECK-LABEL: fpcallercaller: +; CHECK: lg %r1, 152(%r15) +; CHECK: lghi %r2, 152 +; CHECK: ag %r2, 152(%r1) +; CHECK: br %r14 + %0 = tail call ptr @llvm.frameaddress(i32 2) + ret ptr %0 +} + ; Without back chain attributes #1 = { nounwind "packed-stack" } diff --git a/llvm/test/CodeGen/SystemZ/ret-addr-01.ll b/llvm/test/CodeGen/SystemZ/ret-addr-01.ll index 8111d2a72456d5..e3644feb0b49b7 100644 --- a/llvm/test/CodeGen/SystemZ/ret-addr-01.ll +++ b/llvm/test/CodeGen/SystemZ/ret-addr-01.ll @@ -12,4 +12,27 @@ entry: ret ptr %0 } +; Check the caller's return address. +define ptr @rtcaller() nounwind "backchain" { +entry: +; CHECK-LABEL: rtcaller: +; CHECK: lg %r1, 0(%r15) +; CHECK lg %r2, 112(%r1) +; CHECK: br %r14 + %0 = tail call ptr @llvm.returnaddress(i32 1) + ret ptr %0 +} + +; Check the caller's caller's return address. +define ptr @rtcallercaller() nounwind "backchain" { +entry: +; CHECK-LABEL: rtcallercaller: +; CHECK: lg %r1, 0(%r15) +; CHECK: lg %r1, 0(%r1) +; CHECK lg %r2, 112(%r1) +; CHECK: br %r14 + %0 = tail call ptr @llvm.returnaddress(i32 2) + ret ptr %0 +} + declare ptr @llvm.returnaddress(i32) nounwind readnone diff --git a/llvm/test/CodeGen/SystemZ/ret-addr-02.ll b/llvm/test/CodeGen/SystemZ/ret-addr-02.ll new file mode 100644 index 00000000000000..5c1e56d56c0284 --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/ret-addr-02.ll @@ -0,0 +1,39 @@ +; Test support for the llvm.returnaddress intrinsic with packed-stack. + +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s + +; The current function's return address is in the link register. +attributes #0 = { nounwind "packed-stack" "backchain" "use-soft-float"="true" } +define ptr @rt0() #0 { +entry: +; CHECK-LABEL: rt0: +; CHECK: lgr %r2, %r14 +; CHECK: br %r14 + %0 = tail call ptr @llvm.returnaddress(i32 0) + ret ptr %0 +} + +; Check the caller's return address. +define ptr @rtcaller() #0 { +entry: +; CHECK-LABEL: rtcaller: +; CHECK: lg %r1, 152(%r15) +; CHECK lg %r2, 136(%r1) +; CHECK: br %r14 + %0 = tail call ptr @llvm.returnaddress(i32 1) + ret ptr %0 +} + +; Check the caller's caller's return address. +define ptr @rtcallercaller() #0 { +entry: +; CHECK-LABEL: rtcallercaller: +; CHECK: lg %r1, 152(%r15) +; CHECK: lg %r1, 152(%r1) +; CHECK lg %r2, 136(%r1) +; CHECK: br %r14 + %0 = tail call ptr @llvm.returnaddress(i32 2) + ret ptr %0 +} + +declare ptr @llvm.returnaddress(i32) nounwind readnone