[llvm] 22f9429 - [SystemZ] Add GHC calling convention
Ulrich Weigand via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 4 04:47:15 PST 2019
Author: Ulrich Weigand
Date: 2019-11-04T13:45:51+01:00
New Revision: 22f9429149a8faed1f5770aca89e68409ae2cc4f
URL: https://github.com/llvm/llvm-project/commit/22f9429149a8faed1f5770aca89e68409ae2cc4f
DIFF: https://github.com/llvm/llvm-project/commit/22f9429149a8faed1f5770aca89e68409ae2cc4f.diff
LOG: [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
Added:
llvm/test/CodeGen/SystemZ/ghc-cc-01.ll
llvm/test/CodeGen/SystemZ/ghc-cc-02.ll
llvm/test/CodeGen/SystemZ/ghc-cc-03.ll
llvm/test/CodeGen/SystemZ/ghc-cc-04.ll
llvm/test/CodeGen/SystemZ/ghc-cc-05.ll
llvm/test/CodeGen/SystemZ/ghc-cc-06.ll
llvm/test/CodeGen/SystemZ/ghc-cc-07.ll
Modified:
llvm/lib/Target/SystemZ/SystemZCallingConv.h
llvm/lib/Target/SystemZ/SystemZCallingConv.td
llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp
llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/SystemZ/SystemZCallingConv.h b/llvm/lib/Target/SystemZ/SystemZCallingConv.h
index 82f29b6361f1..4432adc6a269 100644
--- a/llvm/lib/Target/SystemZ/SystemZCallingConv.h
+++ b/llvm/lib/Target/SystemZ/SystemZCallingConv.h
@@ -124,6 +124,13 @@ inline bool CC_SystemZ_I128Indirect(unsigned &ValNo, MVT &ValVT,
return true;
}
+inline bool CC_SystemZ_GHC_Error(unsigned &, MVT &, MVT &,
+ CCValAssign::LocInfo &, ISD::ArgFlagsTy &,
+ CCState &) {
+ report_fatal_error("No registers left in GHC calling convention");
+ return false;
+}
+
} // end namespace llvm
#endif
diff --git a/llvm/lib/Target/SystemZ/SystemZCallingConv.td b/llvm/lib/Target/SystemZ/SystemZCallingConv.td
index bbd51546ac9f..b1b7ad47671f 100644
--- a/llvm/lib/Target/SystemZ/SystemZCallingConv.td
+++ b/llvm/lib/Target/SystemZ/SystemZCallingConv.td
@@ -57,10 +57,35 @@ def RetCC_SystemZ : CallingConv<[
CCAssignToReg<[V24, V26, V28, V30, V25, V27, V29, V31]>>>
]>;
+//===----------------------------------------------------------------------===//
+// z/Linux argument calling conventions for GHC
+//===----------------------------------------------------------------------===//
+def CC_SystemZ_GHC : CallingConv<[
+ // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, R6, R7, R8, SpLim
+ CCIfType<[i64], CCAssignToReg<[R7D, R8D, R10D, R11D, R12D, R13D,
+ R6D, R2D, R3D, R4D, R5D, R9D]>>,
+
+ // Pass in STG registers: F1, ..., F6
+ CCIfType<[f32], CCAssignToReg<[F8S, F9S, F10S, F11S, F0S, F1S]>>,
+
+ // Pass in STG registers: D1, ..., D6
+ CCIfType<[f64], CCAssignToReg<[F12D, F13D, F14D, F15D, F2D, F3D]>>,
+
+ // Pass in STG registers: XMM1, ..., XMM6
+ CCIfSubtarget<"hasVector()",
+ CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
+ CCIfFixed<CCAssignToReg<[V16, V17, V18, V19, V20, V21]>>>>,
+
+ // Fail otherwise
+ CCCustom<"CC_SystemZ_GHC_Error">
+]>;
+
//===----------------------------------------------------------------------===//
// z/Linux argument calling conventions
//===----------------------------------------------------------------------===//
def CC_SystemZ : CallingConv<[
+ CCIfCC<"CallingConv::GHC", CCDelegateTo<CC_SystemZ_GHC>>,
+
// Promote i32 to i64 if it has an explicit extension type.
// The convention is that true integer arguments that are smaller
// 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),
def CSR_SystemZ_AllRegs_Vector : CalleeSavedRegs<(add (sequence "R%dD", 2, 15),
(sequence "V%d", 0, 31))>;
+def CSR_SystemZ_NoRegs : CalleeSavedRegs<(add)>;
+
diff --git a/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp b/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp
index 0b8b6880accc..d183eb5b3eb9 100644
--- a/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp
@@ -351,6 +351,23 @@ void SystemZFrameLowering::emitPrologue(MachineFunction &MF,
const std::vector<CalleeSavedInfo> &CSI = MFFrame.getCalleeSavedInfo();
bool HasFP = hasFP(MF);
+ // In GHC calling convention C stack space, including the ABI-defined
+ // 160-byte base area, is (de)allocated by GHC itself. This stack space may
+ // be used by LLVM as spill slots for the tail recursive GHC functions. Thus
+ // do not allocate stack space here, too.
+ if (MF.getFunction().getCallingConv() == CallingConv::GHC) {
+ if (MFFrame.getStackSize() > 2048 * sizeof(long)) {
+ report_fatal_error(
+ "Pre allocated stack space for GHC function is too small");
+ }
+ if (HasFP) {
+ report_fatal_error(
+ "In GHC calling convention a frame pointer is not supported");
+ }
+ MFFrame.setStackSize(MFFrame.getStackSize() + SystemZMC::CallFrameSize);
+ return;
+ }
+
// Debug location must be unknown since the first debug location is used
// to determine the end of the prologue.
DebugLoc DL;
@@ -478,6 +495,10 @@ void SystemZFrameLowering::emitEpilogue(MachineFunction &MF,
SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>();
MachineFrameInfo &MFFrame = MF.getFrameInfo();
+ // See SystemZFrameLowering::emitPrologue
+ if (MF.getFunction().getCallingConv() == CallingConv::GHC)
+ return;
+
// Skip the return instruction.
assert(MBBI->isReturn() && "Can only insert epilogue into returning blocks");
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 8e71d8342562..daef108b6f0b 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -1675,6 +1675,9 @@ SystemZTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
if (RetLocs.empty())
return DAG.getNode(SystemZISD::RET_FLAG, DL, MVT::Other, Chain);
+ if (CallConv == CallingConv::GHC)
+ report_fatal_error("GHC functions return void only");
+
// Copy the result values into the output registers.
SDValue Glue;
SmallVector<SDValue, 4> RetOps;
@@ -2874,6 +2877,10 @@ SDValue SystemZTargetLowering::lowerTLSGetOffset(GlobalAddressSDNode *Node,
SDValue Chain = DAG.getEntryNode();
SDValue Glue;
+ if (DAG.getMachineFunction().getFunction().getCallingConv() ==
+ CallingConv::GHC)
+ report_fatal_error("In GHC calling convention TLS is not supported");
+
// __tls_get_offset takes the GOT offset in %r2 and the GOT in %r12.
SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(PtrVT);
Chain = DAG.getCopyToReg(Chain, DL, SystemZ::R12D, GOT, Glue);
@@ -2940,6 +2947,10 @@ SDValue SystemZTargetLowering::lowerGlobalTLSAddress(GlobalAddressSDNode *Node,
EVT PtrVT = getPointerTy(DAG.getDataLayout());
TLSModel::Model model = DAG.getTarget().getTLSModel(GV);
+ if (DAG.getMachineFunction().getFunction().getCallingConv() ==
+ CallingConv::GHC)
+ report_fatal_error("In GHC calling convention TLS is not supported");
+
SDValue TP = lowerThreadPointer(DL, DAG);
// Get the offset of GA from the thread pointer, based on the TLS model.
@@ -3870,6 +3881,9 @@ SDValue SystemZTargetLowering::lowerSTACKSAVE(SDValue Op,
SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
MF.getInfo<SystemZMachineFunctionInfo>()->setManipulatesSP(true);
+ if (MF.getFunction().getCallingConv() == CallingConv::GHC)
+ report_fatal_error("Variable-sized stack allocations are not supported "
+ "in GHC calling convention");
return DAG.getCopyFromReg(Op.getOperand(0), SDLoc(Op),
SystemZ::R15D, Op.getValueType());
}
@@ -3880,6 +3894,10 @@ SDValue SystemZTargetLowering::lowerSTACKRESTORE(SDValue Op,
MF.getInfo<SystemZMachineFunctionInfo>()->setManipulatesSP(true);
bool StoreBackchain = MF.getFunction().hasFnAttribute("backchain");
+ if (MF.getFunction().getCallingConv() == CallingConv::GHC)
+ report_fatal_error("Variable-sized stack allocations are not supported "
+ "in GHC calling convention");
+
SDValue Chain = Op.getOperand(0);
SDValue NewSP = Op.getOperand(1);
SDValue Backchain;
diff --git a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
index 39ace5594b7f..cbcfc07f2b16 100644
--- a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
@@ -195,6 +195,8 @@ SystemZRegisterInfo::getRegAllocationHints(unsigned VirtReg,
const MCPhysReg *
SystemZRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
+ if (MF->getFunction().getCallingConv() == CallingConv::GHC)
+ return CSR_SystemZ_NoRegs_SaveList;
if (MF->getFunction().getCallingConv() == CallingConv::AnyReg)
return Subtarget.hasVector()? CSR_SystemZ_AllRegs_Vector_SaveList
: CSR_SystemZ_AllRegs_SaveList;
@@ -209,6 +211,8 @@ const uint32_t *
SystemZRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID CC) const {
const SystemZSubtarget &Subtarget = MF.getSubtarget<SystemZSubtarget>();
+ if (CC == CallingConv::GHC)
+ return CSR_SystemZ_NoRegs_RegMask;
if (CC == CallingConv::AnyReg)
return Subtarget.hasVector()? CSR_SystemZ_AllRegs_Vector_RegMask
: CSR_SystemZ_AllRegs_RegMask;
diff --git a/llvm/test/CodeGen/SystemZ/ghc-cc-01.ll b/llvm/test/CodeGen/SystemZ/ghc-cc-01.ll
new file mode 100644
index 000000000000..dc8052d8f058
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/ghc-cc-01.ll
@@ -0,0 +1,103 @@
+; Check that the GHC calling convention works (s390x)
+;
+; RUN: llc -mtriple=s390x-ibm-linux < %s | FileCheck %s
+
+ at base = external global i64 ; assigned to register: r7
+ at sp = external global i64 ; assigned to register: r8
+ at hp = external global i64 ; assigned to register: r10
+ at r1 = external global i64 ; assigned to register: r11
+ at r2 = external global i64 ; assigned to register: r12
+ at r3 = external global i64 ; assigned to register: r13
+ at r4 = external global i64 ; assigned to register: r6
+ at r5 = external global i64 ; assigned to register: r2
+ at r6 = external global i64 ; assigned to register: r3
+ at r7 = external global i64 ; assigned to register: r4
+ at r8 = external global i64 ; assigned to register: r5
+ at splim = external global i64 ; assigned to register: r9
+
+ at f1 = external global float ; assigned to register: s8
+ at f2 = external global float ; assigned to register: s9
+ at f3 = external global float ; assigned to register: s10
+ at f4 = external global float ; assigned to register: s11
+ at f5 = external global float ; assigned to register: s0
+ at f6 = external global float ; assigned to register: s1
+
+ at d1 = external global double ; assigned to register: d12
+ at d2 = external global double ; assigned to register: d13
+ at d3 = external global double ; assigned to register: d14
+ at d4 = external global double ; assigned to register: d15
+ at d5 = external global double ; assigned to register: d2
+ at d6 = external global double ; assigned to register: d3
+
+define ghccc void @foo() nounwind {
+entry:
+ ; CHECK: larl {{%r[0-9]+}}, d6
+ ; CHECK-NEXT: ld %f3, 0({{%r[0-9]+}})
+ ; CHECK-NEXT: larl {{%r[0-9]+}}, d5
+ ; CHECK-NEXT: ld %f2, 0({{%r[0-9]+}})
+ ; CHECK-NEXT: larl {{%r[0-9]+}}, d4
+ ; CHECK-NEXT: ld %f15, 0({{%r[0-9]+}})
+ ; CHECK-NEXT: larl {{%r[0-9]+}}, d3
+ ; CHECK-NEXT: ld %f14, 0({{%r[0-9]+}})
+ ; CHECK-NEXT: larl {{%r[0-9]+}}, d2
+ ; CHECK-NEXT: ld %f13, 0({{%r[0-9]+}})
+ ; CHECK-NEXT: larl {{%r[0-9]+}}, d1
+ ; CHECK-NEXT: ld %f12, 0({{%r[0-9]+}})
+ ; CHECK-NEXT: larl {{%r[0-9]+}}, f6
+ ; CHECK-NEXT: le %f1, 0({{%r[0-9]+}})
+ ; CHECK-NEXT: larl {{%r[0-9]+}}, f5
+ ; CHECK-NEXT: le %f0, 0({{%r[0-9]+}})
+ ; CHECK-NEXT: larl {{%r[0-9]+}}, f4
+ ; CHECK-NEXT: le %f11, 0({{%r[0-9]+}})
+ ; CHECK-NEXT: larl {{%r[0-9]+}}, f3
+ ; CHECK-NEXT: le %f10, 0({{%r[0-9]+}})
+ ; CHECK-NEXT: larl {{%r[0-9]+}}, f2
+ ; CHECK-NEXT: le %f9, 0({{%r[0-9]+}})
+ ; CHECK-NEXT: larl {{%r[0-9]+}}, f1
+ ; CHECK-NEXT: le %f8, 0({{%r[0-9]+}})
+ ; CHECK-NEXT: lgrl %r9, splim
+ ; CHECK-NEXT: lgrl %r5, r8
+ ; CHECK-NEXT: lgrl %r4, r7
+ ; CHECK-NEXT: lgrl %r3, r6
+ ; CHECK-NEXT: lgrl %r2, r5
+ ; CHECK-NEXT: lgrl %r6, r4
+ ; CHECK-NEXT: lgrl %r13, r3
+ ; CHECK-NEXT: lgrl %r12, r2
+ ; CHECK-NEXT: lgrl %r11, r1
+ ; CHECK-NEXT: lgrl %r10, hp
+ ; CHECK-NEXT: lgrl %r8, sp
+ ; CHECK-NEXT: lgrl %r7, base
+ %0 = load double, double* @d6
+ %1 = load double, double* @d5
+ %2 = load double, double* @d4
+ %3 = load double, double* @d3
+ %4 = load double, double* @d2
+ %5 = load double, double* @d1
+ %6 = load float, float* @f6
+ %7 = load float, float* @f5
+ %8 = load float, float* @f4
+ %9 = load float, float* @f3
+ %10 = load float, float* @f2
+ %11 = load float, float* @f1
+ %12 = load i64, i64* @splim
+ %13 = load i64, i64* @r8
+ %14 = load i64, i64* @r7
+ %15 = load i64, i64* @r6
+ %16 = load i64, i64* @r5
+ %17 = load i64, i64* @r4
+ %18 = load i64, i64* @r3
+ %19 = load i64, i64* @r2
+ %20 = load i64, i64* @r1
+ %21 = load i64, i64* @hp
+ %22 = load i64, i64* @sp
+ %23 = load i64, i64* @base
+ ; CHECK: brasl %r14, bar
+ 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,
+ float %11, float %10, float %9, float %8, float %7, float %6,
+ double %5, double %4, double %3, double %2, double %1, double %0) nounwind
+ ret void
+}
+
+declare ghccc void @bar(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64,
+ float, float, float, float, float, float,
+ double, double, double, double, double, double)
diff --git a/llvm/test/CodeGen/SystemZ/ghc-cc-02.ll b/llvm/test/CodeGen/SystemZ/ghc-cc-02.ll
new file mode 100644
index 000000000000..1d13429d2084
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/ghc-cc-02.ll
@@ -0,0 +1,14 @@
+; Check that the GHC calling convention works (s390x)
+; Check that no more than 12 integer arguments are passed
+;
+; RUN: not llc -mtriple=s390x-ibm-linux < %s 2>&1 | FileCheck %s
+
+define ghccc void @foo() nounwind {
+entry:
+ 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);
+ ret void
+}
+
+declare ghccc void @bar(...)
+
+; CHECK: LLVM ERROR: No registers left in GHC calling convention
diff --git a/llvm/test/CodeGen/SystemZ/ghc-cc-03.ll b/llvm/test/CodeGen/SystemZ/ghc-cc-03.ll
new file mode 100644
index 000000000000..1db7a3ff3dbb
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/ghc-cc-03.ll
@@ -0,0 +1,11 @@
+; Check that the GHC calling convention works (s390x)
+; In GHC calling convention the only allowed return type is void
+;
+; RUN: not llc -mtriple=s390x-ibm-linux < %s 2>&1 | FileCheck %s
+
+define ghccc i64 @foo() nounwind {
+entry:
+ ret i64 42
+}
+
+; CHECK: LLVM ERROR: GHC functions return void only
diff --git a/llvm/test/CodeGen/SystemZ/ghc-cc-04.ll b/llvm/test/CodeGen/SystemZ/ghc-cc-04.ll
new file mode 100644
index 000000000000..0dbe5472207a
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/ghc-cc-04.ll
@@ -0,0 +1,16 @@
+; Check that the GHC calling convention works (s390x)
+; Thread local storage is not supported in GHC calling convention
+;
+; RUN: not llc -mtriple=s390x-ibm-linux < %s 2>&1 | FileCheck %s
+
+ at x = thread_local global i32 0
+
+define ghccc void @foo() nounwind {
+entry:
+ call void @bar(i32 *@x)
+ ret void
+}
+
+declare void @bar(i32*)
+
+; CHECK: LLVM ERROR: In GHC calling convention TLS is not supported
diff --git a/llvm/test/CodeGen/SystemZ/ghc-cc-05.ll b/llvm/test/CodeGen/SystemZ/ghc-cc-05.ll
new file mode 100644
index 000000000000..be2cc67807bf
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/ghc-cc-05.ll
@@ -0,0 +1,16 @@
+; Check that the GHC calling convention works (s390x)
+; Variable-sized stack allocations are not supported in GHC calling convention
+;
+; RUN: not llc -mtriple=s390x-ibm-linux < %s 2>&1 | FileCheck %s
+
+define ghccc void @foo() nounwind {
+entry:
+ %0 = call i8* @llvm.stacksave()
+ call void @llvm.stackrestore(i8* %0)
+ ret void
+}
+
+declare i8* @llvm.stacksave()
+declare void @llvm.stackrestore(i8*)
+
+; CHECK: LLVM ERROR: Variable-sized stack allocations are not supported in GHC calling convention
diff --git a/llvm/test/CodeGen/SystemZ/ghc-cc-06.ll b/llvm/test/CodeGen/SystemZ/ghc-cc-06.ll
new file mode 100644
index 000000000000..04df248c29f8
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/ghc-cc-06.ll
@@ -0,0 +1,12 @@
+; Check that the GHC calling convention works (s390x)
+; At most 2048*sizeof(long)=16384 bytes of stack space may be used
+;
+; RUN: not llc -mtriple=s390x-ibm-linux < %s 2>&1 | FileCheck %s
+
+define ghccc void @foo() nounwind {
+entry:
+ alloca [16385 x i8], align 1
+ ret void
+}
+
+; CHECK: LLVM ERROR: Pre allocated stack space for GHC function is too small
diff --git a/llvm/test/CodeGen/SystemZ/ghc-cc-07.ll b/llvm/test/CodeGen/SystemZ/ghc-cc-07.ll
new file mode 100644
index 000000000000..e9bb3b5e18a3
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/ghc-cc-07.ll
@@ -0,0 +1,12 @@
+; Check that the GHC calling convention works (s390x)
+; In GHC calling convention a frame pointer is not supported
+;
+; RUN: not llc -mtriple=s390x-ibm-linux < %s 2>&1 | FileCheck %s
+
+define ghccc void @foo(i64 %0) nounwind {
+entry:
+ alloca i64, i64 %0
+ ret void
+}
+
+; CHECK: LLVM ERROR: In GHC calling convention a frame pointer is not supported
More information about the llvm-commits
mailing list