Skip to content

Commit b088e20

Browse files
committed
[SystemZ] Support builtin_{frame,return}_address() with non-zero argument
When the code is built with -mbackchain, it is possible to retrieve the caller's frame and return addresses. GCC already can do this, add this support to Clang as well. Use RISCVTargetLowering and GCC's s390_return_addr_rtx() as inspiration. Add tests based on what GCC is emitting.
1 parent b427388 commit b088e20

File tree

5 files changed

+128
-4
lines changed

5 files changed

+128
-4
lines changed

llvm/lib/Target/SystemZ/SystemZISelLowering.cpp

+22-4
Original file line numberDiff line numberDiff line change
@@ -3620,9 +3620,17 @@ SDValue SystemZTargetLowering::lowerFRAMEADDR(SDValue Op,
36203620
int BackChainIdx = TFL->getOrCreateFramePointerSaveIndex(MF);
36213621
SDValue BackChain = DAG.getFrameIndex(BackChainIdx, PtrVT);
36223622

3623-
// FIXME The frontend should detect this case.
36243623
if (Depth > 0) {
3625-
report_fatal_error("Unsupported stack frame traversal count");
3624+
// FIXME The frontend should detect this case.
3625+
if (!MF.getFunction().hasFnAttribute("backchain"))
3626+
report_fatal_error("Unsupported stack frame traversal count");
3627+
3628+
SDValue Offset = DAG.getConstant(TFL->getBackchainOffset(MF), DL, PtrVT);
3629+
while (Depth--) {
3630+
BackChain = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), BackChain,
3631+
MachinePointerInfo());
3632+
BackChain = DAG.getNode(ISD::ADD, DL, PtrVT, BackChain, Offset);
3633+
}
36263634
}
36273635

36283636
return BackChain;
@@ -3641,9 +3649,19 @@ SDValue SystemZTargetLowering::lowerRETURNADDR(SDValue Op,
36413649
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
36423650
EVT PtrVT = getPointerTy(DAG.getDataLayout());
36433651

3644-
// FIXME The frontend should detect this case.
36453652
if (Depth > 0) {
3646-
report_fatal_error("Unsupported stack frame traversal count");
3653+
// FIXME The frontend should detect this case.
3654+
if (!MF.getFunction().hasFnAttribute("backchain"))
3655+
report_fatal_error("Unsupported stack frame traversal count");
3656+
3657+
SDValue FrameAddr = lowerFRAMEADDR(Op, DAG);
3658+
auto *TFL = Subtarget.getFrameLowering<SystemZELFFrameLowering>();
3659+
int Offset = (TFL->usePackedStack(MF) ? -2 : 14) *
3660+
getTargetMachine().getPointerSize(0);
3661+
SDValue Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, FrameAddr,
3662+
DAG.getConstant(Offset, DL, PtrVT));
3663+
return DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), Ptr,
3664+
MachinePointerInfo());
36473665
}
36483666

36493667
// Return R14D, which has the return address. Mark it an implicit live-in.

llvm/test/CodeGen/SystemZ/frameaddr-01.ll

+21
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,25 @@ entry:
2525
ret ptr %1
2626
}
2727

28+
; Check the caller's frame address.
29+
define ptr @fpcaller() nounwind "backchain" {
30+
entry:
31+
; CHECK-LABEL: fpcaller:
32+
; CHECK: lg %r2, 0(%r15)
33+
; CHECK: br %r14
34+
%0 = tail call ptr @llvm.frameaddress(i32 1)
35+
ret ptr %0
36+
}
37+
38+
; Check the caller's frame address.
39+
define ptr @fpcallercaller() nounwind "backchain" {
40+
entry:
41+
; CHECK-LABEL: fpcallercaller:
42+
; CHECK: lg %r1, 0(%r15)
43+
; CHECK: lg %r2, 0(%r1)
44+
; CHECK: br %r14
45+
%0 = tail call ptr @llvm.frameaddress(i32 2)
46+
ret ptr %0
47+
}
48+
2849
declare ptr @llvm.frameaddress(i32) nounwind readnone

llvm/test/CodeGen/SystemZ/frameaddr-02.ll

+23
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,29 @@ entry:
2727
ret ptr %1
2828
}
2929

30+
; Check the caller's frame address.
31+
define ptr @fpcaller() #0 {
32+
entry:
33+
; CHECK-LABEL: fpcaller:
34+
; CHECK: lghi %r2, 152
35+
; CHECK: ag %r2, 152(%r15)
36+
; CHECK: br %r14
37+
%0 = tail call ptr @llvm.frameaddress(i32 1)
38+
ret ptr %0
39+
}
40+
41+
; Check the caller's caller's frame address.
42+
define ptr @fpcallercaller() #0 {
43+
entry:
44+
; CHECK-LABEL: fpcallercaller:
45+
; CHECK: lg %r1, 152(%r15)
46+
; CHECK: lghi %r2, 152
47+
; CHECK: ag %r2, 152(%r1)
48+
; CHECK: br %r14
49+
%0 = tail call ptr @llvm.frameaddress(i32 2)
50+
ret ptr %0
51+
}
52+
3053
; Without back chain
3154

3255
attributes #1 = { nounwind "packed-stack" }

llvm/test/CodeGen/SystemZ/ret-addr-01.ll

+23
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,27 @@ entry:
1212
ret ptr %0
1313
}
1414

15+
; Check the caller's return address.
16+
define ptr @rtcaller() nounwind "backchain" {
17+
entry:
18+
; CHECK-LABEL: rtcaller:
19+
; CHECK: lg %r1, 0(%r15)
20+
; CHECK lg %r2, 112(%r1)
21+
; CHECK: br %r14
22+
%0 = tail call ptr @llvm.returnaddress(i32 1)
23+
ret ptr %0
24+
}
25+
26+
; Check the caller's caller's return address.
27+
define ptr @rtcallercaller() nounwind "backchain" {
28+
entry:
29+
; CHECK-LABEL: rtcallercaller:
30+
; CHECK: lg %r1, 0(%r15)
31+
; CHECK: lg %r1, 0(%r1)
32+
; CHECK lg %r2, 112(%r1)
33+
; CHECK: br %r14
34+
%0 = tail call ptr @llvm.returnaddress(i32 2)
35+
ret ptr %0
36+
}
37+
1538
declare ptr @llvm.returnaddress(i32) nounwind readnone
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
; Test support for the llvm.returnaddress intrinsic with packed-stack.
2+
3+
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
4+
5+
; The current function's return address is in the link register.
6+
attributes #0 = { nounwind "packed-stack" "backchain" "use-soft-float"="true" }
7+
define ptr @rt0() #0 {
8+
entry:
9+
; CHECK-LABEL: rt0:
10+
; CHECK: lgr %r2, %r14
11+
; CHECK: br %r14
12+
%0 = tail call ptr @llvm.returnaddress(i32 0)
13+
ret ptr %0
14+
}
15+
16+
; Check the caller's return address.
17+
define ptr @rtcaller() #0 {
18+
entry:
19+
; CHECK-LABEL: rtcaller:
20+
; CHECK: lg %r1, 152(%r15)
21+
; CHECK lg %r2, 136(%r1)
22+
; CHECK: br %r14
23+
%0 = tail call ptr @llvm.returnaddress(i32 1)
24+
ret ptr %0
25+
}
26+
27+
; Check the caller's caller's return address.
28+
define ptr @rtcallercaller() #0 {
29+
entry:
30+
; CHECK-LABEL: rtcallercaller:
31+
; CHECK: lg %r1, 152(%r15)
32+
; CHECK: lg %r1, 152(%r1)
33+
; CHECK lg %r2, 136(%r1)
34+
; CHECK: br %r14
35+
%0 = tail call ptr @llvm.returnaddress(i32 2)
36+
ret ptr %0
37+
}
38+
39+
declare ptr @llvm.returnaddress(i32) nounwind readnone

0 commit comments

Comments
 (0)