[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