Skip to content

Commit 22f9429

Browse files
committed
[SystemZ] Add GHC calling convention
This is a special calling convention to be used by the GHC compiler. Author: Stefan Schulze Frielinghaus Differential Revision: https://reviews.llvm.org/D69024
1 parent 499c90a commit 22f9429

12 files changed

+261
-0
lines changed

llvm/lib/Target/SystemZ/SystemZCallingConv.h

+7
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,13 @@ inline bool CC_SystemZ_I128Indirect(unsigned &ValNo, MVT &ValVT,
124124
return true;
125125
}
126126

127+
inline bool CC_SystemZ_GHC_Error(unsigned &, MVT &, MVT &,
128+
CCValAssign::LocInfo &, ISD::ArgFlagsTy &,
129+
CCState &) {
130+
report_fatal_error("No registers left in GHC calling convention");
131+
return false;
132+
}
133+
127134
} // end namespace llvm
128135

129136
#endif

llvm/lib/Target/SystemZ/SystemZCallingConv.td

+27
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,35 @@ def RetCC_SystemZ : CallingConv<[
5757
CCAssignToReg<[V24, V26, V28, V30, V25, V27, V29, V31]>>>
5858
]>;
5959

60+
//===----------------------------------------------------------------------===//
61+
// z/Linux argument calling conventions for GHC
62+
//===----------------------------------------------------------------------===//
63+
def CC_SystemZ_GHC : CallingConv<[
64+
// Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, R6, R7, R8, SpLim
65+
CCIfType<[i64], CCAssignToReg<[R7D, R8D, R10D, R11D, R12D, R13D,
66+
R6D, R2D, R3D, R4D, R5D, R9D]>>,
67+
68+
// Pass in STG registers: F1, ..., F6
69+
CCIfType<[f32], CCAssignToReg<[F8S, F9S, F10S, F11S, F0S, F1S]>>,
70+
71+
// Pass in STG registers: D1, ..., D6
72+
CCIfType<[f64], CCAssignToReg<[F12D, F13D, F14D, F15D, F2D, F3D]>>,
73+
74+
// Pass in STG registers: XMM1, ..., XMM6
75+
CCIfSubtarget<"hasVector()",
76+
CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
77+
CCIfFixed<CCAssignToReg<[V16, V17, V18, V19, V20, V21]>>>>,
78+
79+
// Fail otherwise
80+
CCCustom<"CC_SystemZ_GHC_Error">
81+
]>;
82+
6083
//===----------------------------------------------------------------------===//
6184
// z/Linux argument calling conventions
6285
//===----------------------------------------------------------------------===//
6386
def CC_SystemZ : CallingConv<[
87+
CCIfCC<"CallingConv::GHC", CCDelegateTo<CC_SystemZ_GHC>>,
88+
6489
// Promote i32 to i64 if it has an explicit extension type.
6590
// The convention is that true integer arguments that are smaller
6691
// than 64 bits should be marked as extended, but structures that
@@ -128,3 +153,5 @@ def CSR_SystemZ_AllRegs : CalleeSavedRegs<(add (sequence "R%dD", 2, 15),
128153
def CSR_SystemZ_AllRegs_Vector : CalleeSavedRegs<(add (sequence "R%dD", 2, 15),
129154
(sequence "V%d", 0, 31))>;
130155

156+
def CSR_SystemZ_NoRegs : CalleeSavedRegs<(add)>;
157+

llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,23 @@ void SystemZFrameLowering::emitPrologue(MachineFunction &MF,
351351
const std::vector<CalleeSavedInfo> &CSI = MFFrame.getCalleeSavedInfo();
352352
bool HasFP = hasFP(MF);
353353

354+
// In GHC calling convention C stack space, including the ABI-defined
355+
// 160-byte base area, is (de)allocated by GHC itself. This stack space may
356+
// be used by LLVM as spill slots for the tail recursive GHC functions. Thus
357+
// do not allocate stack space here, too.
358+
if (MF.getFunction().getCallingConv() == CallingConv::GHC) {
359+
if (MFFrame.getStackSize() > 2048 * sizeof(long)) {
360+
report_fatal_error(
361+
"Pre allocated stack space for GHC function is too small");
362+
}
363+
if (HasFP) {
364+
report_fatal_error(
365+
"In GHC calling convention a frame pointer is not supported");
366+
}
367+
MFFrame.setStackSize(MFFrame.getStackSize() + SystemZMC::CallFrameSize);
368+
return;
369+
}
370+
354371
// Debug location must be unknown since the first debug location is used
355372
// to determine the end of the prologue.
356373
DebugLoc DL;
@@ -478,6 +495,10 @@ void SystemZFrameLowering::emitEpilogue(MachineFunction &MF,
478495
SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>();
479496
MachineFrameInfo &MFFrame = MF.getFrameInfo();
480497

498+
// See SystemZFrameLowering::emitPrologue
499+
if (MF.getFunction().getCallingConv() == CallingConv::GHC)
500+
return;
501+
481502
// Skip the return instruction.
482503
assert(MBBI->isReturn() && "Can only insert epilogue into returning blocks");
483504

llvm/lib/Target/SystemZ/SystemZISelLowering.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -1675,6 +1675,9 @@ SystemZTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
16751675
if (RetLocs.empty())
16761676
return DAG.getNode(SystemZISD::RET_FLAG, DL, MVT::Other, Chain);
16771677

1678+
if (CallConv == CallingConv::GHC)
1679+
report_fatal_error("GHC functions return void only");
1680+
16781681
// Copy the result values into the output registers.
16791682
SDValue Glue;
16801683
SmallVector<SDValue, 4> RetOps;
@@ -2874,6 +2877,10 @@ SDValue SystemZTargetLowering::lowerTLSGetOffset(GlobalAddressSDNode *Node,
28742877
SDValue Chain = DAG.getEntryNode();
28752878
SDValue Glue;
28762879

2880+
if (DAG.getMachineFunction().getFunction().getCallingConv() ==
2881+
CallingConv::GHC)
2882+
report_fatal_error("In GHC calling convention TLS is not supported");
2883+
28772884
// __tls_get_offset takes the GOT offset in %r2 and the GOT in %r12.
28782885
SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(PtrVT);
28792886
Chain = DAG.getCopyToReg(Chain, DL, SystemZ::R12D, GOT, Glue);
@@ -2940,6 +2947,10 @@ SDValue SystemZTargetLowering::lowerGlobalTLSAddress(GlobalAddressSDNode *Node,
29402947
EVT PtrVT = getPointerTy(DAG.getDataLayout());
29412948
TLSModel::Model model = DAG.getTarget().getTLSModel(GV);
29422949

2950+
if (DAG.getMachineFunction().getFunction().getCallingConv() ==
2951+
CallingConv::GHC)
2952+
report_fatal_error("In GHC calling convention TLS is not supported");
2953+
29432954
SDValue TP = lowerThreadPointer(DL, DAG);
29442955

29452956
// Get the offset of GA from the thread pointer, based on the TLS model.
@@ -3870,6 +3881,9 @@ SDValue SystemZTargetLowering::lowerSTACKSAVE(SDValue Op,
38703881
SelectionDAG &DAG) const {
38713882
MachineFunction &MF = DAG.getMachineFunction();
38723883
MF.getInfo<SystemZMachineFunctionInfo>()->setManipulatesSP(true);
3884+
if (MF.getFunction().getCallingConv() == CallingConv::GHC)
3885+
report_fatal_error("Variable-sized stack allocations are not supported "
3886+
"in GHC calling convention");
38733887
return DAG.getCopyFromReg(Op.getOperand(0), SDLoc(Op),
38743888
SystemZ::R15D, Op.getValueType());
38753889
}
@@ -3880,6 +3894,10 @@ SDValue SystemZTargetLowering::lowerSTACKRESTORE(SDValue Op,
38803894
MF.getInfo<SystemZMachineFunctionInfo>()->setManipulatesSP(true);
38813895
bool StoreBackchain = MF.getFunction().hasFnAttribute("backchain");
38823896

3897+
if (MF.getFunction().getCallingConv() == CallingConv::GHC)
3898+
report_fatal_error("Variable-sized stack allocations are not supported "
3899+
"in GHC calling convention");
3900+
38833901
SDValue Chain = Op.getOperand(0);
38843902
SDValue NewSP = Op.getOperand(1);
38853903
SDValue Backchain;

llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ SystemZRegisterInfo::getRegAllocationHints(unsigned VirtReg,
195195
const MCPhysReg *
196196
SystemZRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
197197
const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
198+
if (MF->getFunction().getCallingConv() == CallingConv::GHC)
199+
return CSR_SystemZ_NoRegs_SaveList;
198200
if (MF->getFunction().getCallingConv() == CallingConv::AnyReg)
199201
return Subtarget.hasVector()? CSR_SystemZ_AllRegs_Vector_SaveList
200202
: CSR_SystemZ_AllRegs_SaveList;
@@ -209,6 +211,8 @@ const uint32_t *
209211
SystemZRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
210212
CallingConv::ID CC) const {
211213
const SystemZSubtarget &Subtarget = MF.getSubtarget<SystemZSubtarget>();
214+
if (CC == CallingConv::GHC)
215+
return CSR_SystemZ_NoRegs_RegMask;
212216
if (CC == CallingConv::AnyReg)
213217
return Subtarget.hasVector()? CSR_SystemZ_AllRegs_Vector_RegMask
214218
: CSR_SystemZ_AllRegs_RegMask;
+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
; Check that the GHC calling convention works (s390x)
2+
;
3+
; RUN: llc -mtriple=s390x-ibm-linux < %s | FileCheck %s
4+
5+
@base = external global i64 ; assigned to register: r7
6+
@sp = external global i64 ; assigned to register: r8
7+
@hp = external global i64 ; assigned to register: r10
8+
@r1 = external global i64 ; assigned to register: r11
9+
@r2 = external global i64 ; assigned to register: r12
10+
@r3 = external global i64 ; assigned to register: r13
11+
@r4 = external global i64 ; assigned to register: r6
12+
@r5 = external global i64 ; assigned to register: r2
13+
@r6 = external global i64 ; assigned to register: r3
14+
@r7 = external global i64 ; assigned to register: r4
15+
@r8 = external global i64 ; assigned to register: r5
16+
@splim = external global i64 ; assigned to register: r9
17+
18+
@f1 = external global float ; assigned to register: s8
19+
@f2 = external global float ; assigned to register: s9
20+
@f3 = external global float ; assigned to register: s10
21+
@f4 = external global float ; assigned to register: s11
22+
@f5 = external global float ; assigned to register: s0
23+
@f6 = external global float ; assigned to register: s1
24+
25+
@d1 = external global double ; assigned to register: d12
26+
@d2 = external global double ; assigned to register: d13
27+
@d3 = external global double ; assigned to register: d14
28+
@d4 = external global double ; assigned to register: d15
29+
@d5 = external global double ; assigned to register: d2
30+
@d6 = external global double ; assigned to register: d3
31+
32+
define ghccc void @foo() nounwind {
33+
entry:
34+
; CHECK: larl {{%r[0-9]+}}, d6
35+
; CHECK-NEXT: ld %f3, 0({{%r[0-9]+}})
36+
; CHECK-NEXT: larl {{%r[0-9]+}}, d5
37+
; CHECK-NEXT: ld %f2, 0({{%r[0-9]+}})
38+
; CHECK-NEXT: larl {{%r[0-9]+}}, d4
39+
; CHECK-NEXT: ld %f15, 0({{%r[0-9]+}})
40+
; CHECK-NEXT: larl {{%r[0-9]+}}, d3
41+
; CHECK-NEXT: ld %f14, 0({{%r[0-9]+}})
42+
; CHECK-NEXT: larl {{%r[0-9]+}}, d2
43+
; CHECK-NEXT: ld %f13, 0({{%r[0-9]+}})
44+
; CHECK-NEXT: larl {{%r[0-9]+}}, d1
45+
; CHECK-NEXT: ld %f12, 0({{%r[0-9]+}})
46+
; CHECK-NEXT: larl {{%r[0-9]+}}, f6
47+
; CHECK-NEXT: le %f1, 0({{%r[0-9]+}})
48+
; CHECK-NEXT: larl {{%r[0-9]+}}, f5
49+
; CHECK-NEXT: le %f0, 0({{%r[0-9]+}})
50+
; CHECK-NEXT: larl {{%r[0-9]+}}, f4
51+
; CHECK-NEXT: le %f11, 0({{%r[0-9]+}})
52+
; CHECK-NEXT: larl {{%r[0-9]+}}, f3
53+
; CHECK-NEXT: le %f10, 0({{%r[0-9]+}})
54+
; CHECK-NEXT: larl {{%r[0-9]+}}, f2
55+
; CHECK-NEXT: le %f9, 0({{%r[0-9]+}})
56+
; CHECK-NEXT: larl {{%r[0-9]+}}, f1
57+
; CHECK-NEXT: le %f8, 0({{%r[0-9]+}})
58+
; CHECK-NEXT: lgrl %r9, splim
59+
; CHECK-NEXT: lgrl %r5, r8
60+
; CHECK-NEXT: lgrl %r4, r7
61+
; CHECK-NEXT: lgrl %r3, r6
62+
; CHECK-NEXT: lgrl %r2, r5
63+
; CHECK-NEXT: lgrl %r6, r4
64+
; CHECK-NEXT: lgrl %r13, r3
65+
; CHECK-NEXT: lgrl %r12, r2
66+
; CHECK-NEXT: lgrl %r11, r1
67+
; CHECK-NEXT: lgrl %r10, hp
68+
; CHECK-NEXT: lgrl %r8, sp
69+
; CHECK-NEXT: lgrl %r7, base
70+
%0 = load double, double* @d6
71+
%1 = load double, double* @d5
72+
%2 = load double, double* @d4
73+
%3 = load double, double* @d3
74+
%4 = load double, double* @d2
75+
%5 = load double, double* @d1
76+
%6 = load float, float* @f6
77+
%7 = load float, float* @f5
78+
%8 = load float, float* @f4
79+
%9 = load float, float* @f3
80+
%10 = load float, float* @f2
81+
%11 = load float, float* @f1
82+
%12 = load i64, i64* @splim
83+
%13 = load i64, i64* @r8
84+
%14 = load i64, i64* @r7
85+
%15 = load i64, i64* @r6
86+
%16 = load i64, i64* @r5
87+
%17 = load i64, i64* @r4
88+
%18 = load i64, i64* @r3
89+
%19 = load i64, i64* @r2
90+
%20 = load i64, i64* @r1
91+
%21 = load i64, i64* @hp
92+
%22 = load i64, i64* @sp
93+
%23 = load i64, i64* @base
94+
; CHECK: brasl %r14, bar
95+
tail call ghccc void @bar(i64 %23, i64 %22, i64 %21, i64 %20, i64 %19, i64 %18, i64 %17, i64 %16, i64 %15, i64 %14, i64 %13, i64 %12,
96+
float %11, float %10, float %9, float %8, float %7, float %6,
97+
double %5, double %4, double %3, double %2, double %1, double %0) nounwind
98+
ret void
99+
}
100+
101+
declare ghccc void @bar(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64,
102+
float, float, float, float, float, float,
103+
double, double, double, double, double, double)
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
; Check that the GHC calling convention works (s390x)
2+
; Check that no more than 12 integer arguments are passed
3+
;
4+
; RUN: not llc -mtriple=s390x-ibm-linux < %s 2>&1 | FileCheck %s
5+
6+
define ghccc void @foo() nounwind {
7+
entry:
8+
tail call ghccc void (...) @bar(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, i64 9, i64 10, i64 11, i64 12, i64 13);
9+
ret void
10+
}
11+
12+
declare ghccc void @bar(...)
13+
14+
; CHECK: LLVM ERROR: No registers left in GHC calling convention
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
; Check that the GHC calling convention works (s390x)
2+
; In GHC calling convention the only allowed return type is void
3+
;
4+
; RUN: not llc -mtriple=s390x-ibm-linux < %s 2>&1 | FileCheck %s
5+
6+
define ghccc i64 @foo() nounwind {
7+
entry:
8+
ret i64 42
9+
}
10+
11+
; CHECK: LLVM ERROR: GHC functions return void only
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
; Check that the GHC calling convention works (s390x)
2+
; Thread local storage is not supported in GHC calling convention
3+
;
4+
; RUN: not llc -mtriple=s390x-ibm-linux < %s 2>&1 | FileCheck %s
5+
6+
@x = thread_local global i32 0
7+
8+
define ghccc void @foo() nounwind {
9+
entry:
10+
call void @bar(i32 *@x)
11+
ret void
12+
}
13+
14+
declare void @bar(i32*)
15+
16+
; CHECK: LLVM ERROR: In GHC calling convention TLS is not supported
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
; Check that the GHC calling convention works (s390x)
2+
; Variable-sized stack allocations are not supported in GHC calling convention
3+
;
4+
; RUN: not llc -mtriple=s390x-ibm-linux < %s 2>&1 | FileCheck %s
5+
6+
define ghccc void @foo() nounwind {
7+
entry:
8+
%0 = call i8* @llvm.stacksave()
9+
call void @llvm.stackrestore(i8* %0)
10+
ret void
11+
}
12+
13+
declare i8* @llvm.stacksave()
14+
declare void @llvm.stackrestore(i8*)
15+
16+
; CHECK: LLVM ERROR: Variable-sized stack allocations are not supported in GHC calling convention
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
; Check that the GHC calling convention works (s390x)
2+
; At most 2048*sizeof(long)=16384 bytes of stack space may be used
3+
;
4+
; RUN: not llc -mtriple=s390x-ibm-linux < %s 2>&1 | FileCheck %s
5+
6+
define ghccc void @foo() nounwind {
7+
entry:
8+
alloca [16385 x i8], align 1
9+
ret void
10+
}
11+
12+
; CHECK: LLVM ERROR: Pre allocated stack space for GHC function is too small
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
; Check that the GHC calling convention works (s390x)
2+
; In GHC calling convention a frame pointer is not supported
3+
;
4+
; RUN: not llc -mtriple=s390x-ibm-linux < %s 2>&1 | FileCheck %s
5+
6+
define ghccc void @foo(i64 %0) nounwind {
7+
entry:
8+
alloca i64, i64 %0
9+
ret void
10+
}
11+
12+
; CHECK: LLVM ERROR: In GHC calling convention a frame pointer is not supported

0 commit comments

Comments
 (0)