[llvm] ec4706b - [SystemZ] [z/OS] Add XPLINK64 Calling Convention to SystemZ

Kai Nacke via llvm-commits llvm-commits at lists.llvm.org
Tue May 18 13:53:02 PDT 2021


Author: Neumann Hon
Date: 2021-05-18T16:52:47-04:00
New Revision: ec4706be8e72d171b36fb19e0dba1e7be5929c4c

URL: https://github.com/llvm/llvm-project/commit/ec4706be8e72d171b36fb19e0dba1e7be5929c4c
DIFF: https://github.com/llvm/llvm-project/commit/ec4706be8e72d171b36fb19e0dba1e7be5929c4c.diff

LOG: [SystemZ] [z/OS] Add XPLINK64 Calling Convention to SystemZ

This patch adds the XPLINK64 calling convention to the SystemZ
backend. It specifies and implements the argument passing and
return value conventions.

Reviewed By: uweigand

Differential Revision: https://reviews.llvm.org/D101010

Added: 
    

Modified: 
    llvm/lib/Target/SystemZ/SystemZCallingConv.cpp
    llvm/lib/Target/SystemZ/SystemZCallingConv.h
    llvm/lib/Target/SystemZ/SystemZCallingConv.td

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/SystemZ/SystemZCallingConv.cpp b/llvm/lib/Target/SystemZ/SystemZCallingConv.cpp
index 8ceb38799ce1..86eb8365d527 100644
--- a/llvm/lib/Target/SystemZ/SystemZCallingConv.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZCallingConv.cpp
@@ -18,3 +18,13 @@ const MCPhysReg SystemZ::ELFArgGPRs[SystemZ::ELFNumArgGPRs] = {
 const MCPhysReg SystemZ::ELFArgFPRs[SystemZ::ELFNumArgFPRs] = {
   SystemZ::F0D, SystemZ::F2D, SystemZ::F4D, SystemZ::F6D
 };
+
+// The XPLINK64 ABI-defined param passing general purpose registers
+const MCPhysReg SystemZ::XPLINK64ArgGPRs[SystemZ::XPLINK64NumArgGPRs] = {
+    SystemZ::R1D, SystemZ::R2D, SystemZ::R3D
+};
+
+// The XPLINK64 ABI-defined param passing floating point registers
+const MCPhysReg SystemZ::XPLINK64ArgFPRs[SystemZ::XPLINK64NumArgFPRs] = {
+    SystemZ::F0D, SystemZ::F2D, SystemZ::F4D, SystemZ::F6D
+};

diff  --git a/llvm/lib/Target/SystemZ/SystemZCallingConv.h b/llvm/lib/Target/SystemZ/SystemZCallingConv.h
index 84a884a30b9b..96c1080d5237 100644
--- a/llvm/lib/Target/SystemZ/SystemZCallingConv.h
+++ b/llvm/lib/Target/SystemZ/SystemZCallingConv.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZCALLINGCONV_H
 #define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZCALLINGCONV_H
 
+#include "SystemZSubtarget.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/CodeGen/CallingConvLower.h"
 #include "llvm/MC/MCRegisterInfo.h"
@@ -20,6 +21,12 @@ namespace SystemZ {
 
   const unsigned ELFNumArgFPRs = 4;
   extern const MCPhysReg ELFArgFPRs[ELFNumArgFPRs];
+
+  const unsigned XPLINK64NumArgGPRs = 3;
+  extern const MCPhysReg XPLINK64ArgGPRs[XPLINK64NumArgGPRs];
+
+  const unsigned XPLINK64NumArgFPRs = 4;
+  extern const MCPhysReg XPLINK64ArgFPRs[XPLINK64NumArgFPRs];
 } // end namespace SystemZ
 
 class SystemZCCState : public CCState {
@@ -107,7 +114,16 @@ inline bool CC_SystemZ_I128Indirect(unsigned &ValNo, MVT &ValVT,
   // OK, we've collected all parts in the pending list.  Allocate
   // the location (register or stack slot) for the indirect pointer.
   // (This duplicates the usual i64 calling convention rules.)
-  unsigned Reg = State.AllocateReg(SystemZ::ELFArgGPRs);
+  unsigned Reg;
+  const SystemZSubtarget &Subtarget =
+      State.getMachineFunction().getSubtarget<SystemZSubtarget>();
+  if (Subtarget.isTargetELF())
+    Reg = State.AllocateReg(SystemZ::ELFArgGPRs);
+  else if (Subtarget.isTargetXPLINK64())
+    Reg = State.AllocateReg(SystemZ::XPLINK64ArgGPRs);
+  else
+    llvm_unreachable("Unknown Calling Convention!");
+
   unsigned Offset = Reg ? 0 : State.AllocateStack(8, Align(8));
 
   // Use that same location for all the pending parts.
@@ -124,6 +140,80 @@ inline bool CC_SystemZ_I128Indirect(unsigned &ValNo, MVT &ValVT,
   return true;
 }
 
+inline bool CC_XPLINK64_Shadow_Reg(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
+                                   CCValAssign::LocInfo &LocInfo,
+                                   ISD::ArgFlagsTy &ArgFlags, CCState &State) {
+  if (LocVT == MVT::f32 || LocVT == MVT::f64) {
+    State.AllocateReg(SystemZ::XPLINK64ArgGPRs);
+  }
+  if (LocVT == MVT::f128 || LocVT.is128BitVector()) {
+    // Shadow next two GPRs, if available.
+    State.AllocateReg(SystemZ::XPLINK64ArgGPRs);
+    State.AllocateReg(SystemZ::XPLINK64ArgGPRs);
+
+    // Quad precision floating point needs to
+    // go inside pre-defined FPR pair.
+    if (LocVT == MVT::f128) {
+      for (unsigned I = 0; I < SystemZ::XPLINK64NumArgFPRs; I += 2)
+        if (State.isAllocated(SystemZ::XPLINK64ArgFPRs[I]))
+          State.AllocateReg(SystemZ::XPLINK64ArgFPRs[I + 1]);
+    }
+  }
+  return false;
+}
+
+inline bool CC_XPLINK64_Allocate128BitVararg(unsigned &ValNo, MVT &ValVT,
+                                             MVT &LocVT,
+                                             CCValAssign::LocInfo &LocInfo,
+                                             ISD::ArgFlagsTy &ArgFlags,
+                                             CCState &State) {
+  if (LocVT.getSizeInBits() < 128)
+    return false;
+
+  if (static_cast<SystemZCCState *>(&State)->IsFixed(ValNo))
+    return false;
+
+  // For any C or C++ program, this should always be
+  // false, since it is illegal to have a function
+  // where the first argument is variadic. Therefore
+  // the first fixed argument should already have
+  // allocated GPR1 either through shadowing it or
+  // using it for parameter passing.
+  State.AllocateReg(SystemZ::R1D);
+
+  bool AllocGPR2 = State.AllocateReg(SystemZ::R2D);
+  bool AllocGPR3 = State.AllocateReg(SystemZ::R3D);
+
+  // If GPR2 and GPR3 are available, then we may pass vararg in R2Q.
+  if (AllocGPR2 && AllocGPR3) {
+    State.addLoc(
+        CCValAssign::getReg(ValNo, ValVT, SystemZ::R2Q, LocVT, LocInfo));
+    return true;
+  }
+
+  // If only GPR3 is available, we allocate on stack but need to
+  // set custom handling to copy hi bits into GPR3.
+  if (!AllocGPR2 && AllocGPR3) {
+    auto Offset = State.AllocateStack(16, Align(8));
+    State.addLoc(
+        CCValAssign::getCustomMem(ValNo, ValVT, Offset, LocVT, LocInfo));
+    return true;
+  }
+
+  return false;
+}
+
+inline bool RetCC_SystemZ_Error(unsigned &, MVT &, MVT &,
+                                CCValAssign::LocInfo &, ISD::ArgFlagsTy &,
+                                CCState &) {
+  llvm_unreachable("Return value calling convention currently unsupported.");
+}
+
+inline bool CC_SystemZ_Error(unsigned &, MVT &, MVT &, CCValAssign::LocInfo &,
+                             ISD::ArgFlagsTy &, CCState &) {
+  llvm_unreachable("Argument calling convention currently unsupported.");
+}
+
 inline bool CC_SystemZ_GHC_Error(unsigned &, MVT &, MVT &,
                                  CCValAssign::LocInfo &, ISD::ArgFlagsTy &,
                                  CCState &) {

diff  --git a/llvm/lib/Target/SystemZ/SystemZCallingConv.td b/llvm/lib/Target/SystemZ/SystemZCallingConv.td
index 29010ab8bd1c..45e22b07be30 100644
--- a/llvm/lib/Target/SystemZ/SystemZCallingConv.td
+++ b/llvm/lib/Target/SystemZ/SystemZCallingConv.td
@@ -20,6 +20,10 @@ class CCIfSubtarget<string F, CCAction A>
 class CCIfFixed<CCAction A>
     : CCIf<"static_cast<SystemZCCState *>(&State)->IsFixed(ValNo)", A>;
 
+// Match if this specific argument is not a fixed (i.e. vararg) argument.
+class CCIfNotFixed<CCAction A>
+    : CCIf<"!(static_cast<SystemZCCState *>(&State)->IsFixed(ValNo))", A>;
+
 // Match if this specific argument was widened from a short vector type.
 class CCIfShortVector<CCAction A>
     : CCIf<"static_cast<SystemZCCState *>(&State)->IsShortVector(ValNo)", A>;
@@ -161,11 +165,133 @@ def CSR_SystemZ_NoRegs : CalleeSavedRegs<(add)>;
 def CSR_SystemZ_XPLINK64 : CalleeSavedRegs<(add (sequence "R%dD", 8, 15),
                                                 (sequence "F%dD", 8, 15))>;
 
+def CSR_SystemZ_XPLINK64_Vector : CalleeSavedRegs<(add (sequence "R%dD", 8, 15),
+                                                       (sequence "F%dD", 15, 8),
+                                                       (sequence "V%d", 23, 16))>;
+
+//===----------------------------------------------------------------------===//
+// z/OS XPLINK64 return value calling convention
+//===----------------------------------------------------------------------===//
+def RetCC_SystemZ_XPLINK64 : CallingConv<[
+  // XPLINK64 ABI compliant code widens integral types smaller than i64
+  // to i64.
+  CCIfType<[i32], CCPromoteToType<i64>>,
+
+  // Structs of size 1-24 bytes are returned in R1D, R2D, and R3D.
+  CCIfType<[i64], CCIfInReg<CCAssignToReg<[R1D, R2D, R3D]>>>,
+  // An i64 is returned in R3D. R2D and R1D provided for ABI non-compliant
+  // code.
+  CCIfType<[i64], CCAssignToReg<[R3D, R2D, R1D]>>,
+
+  // ABI compliant code returns floating point values in FPR0, FPR2, FPR4
+  // and FPR6, using as many registers as required.
+  // All floating point return-value registers are call-clobbered.
+  CCIfType<[f32], CCAssignToReg<[F0S, F2S, F4S, F6S]>>,
+  CCIfType<[f64], CCAssignToReg<[F0D, F2D, F4D, F6D]>>,
+
+  // ABI compliant code returns f128 in F0D and F2D, hence F0Q.
+  // F4D and F6D, hence F4Q are used for complex long double types.
+  CCIfType<[f128], CCAssignToReg<[F0Q,F4Q]>>,
+
+  // ABI compliant code returns vectors in VR24 but other registers
+  // are provided for code that does not care about the ABI.
+  CCIfSubtarget<"hasVector()",
+    CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
+             CCAssignToReg<[V24, V25, V26, V27, V28, V29, V30, V31]>>>
+]>;
+
+//===----------------------------------------------------------------------===//
+// z/OS XPLINK64 argument calling conventions
+//===----------------------------------------------------------------------===//
+// XPLink uses a logical argument list consisting of contiguous register-size
+// words (8 bytes in 64-Bit mode) where some arguments are passed in registers
+// and some in storage.
+// Even though 3 GPRs, 4 FPRs, and 8 VRs may be used,
+// space must be reserved for all the args on stack.
+// The first three register-sized words of the parameter area are passed in
+// GPRs 1-3. FP values and vector-type arguments are instead passed in FPRs
+// and VRs respectively, but if a FP value or vector argument occupies one of
+// the first three register-sized words of the parameter area, the corresponding
+// GPR's value is not used to pass arguments.
+//
+// The XPLINK64 Calling Convention is fully specified in Chapter 22 of the z/OS
+// Language Environment Vendor Interfaces. Appendix B of the same document contains
+// examples.
+
+def CC_SystemZ_XPLINK64 : CallingConv<[
+  // XPLINK64 ABI compliant code widens integral types smaller than i64
+  // to i64 before placing the parameters either on the stack or in registers.
+  CCIfType<[i32], CCIfExtend<CCPromoteToType<i64>>>,
+
+  // A SwiftSelf is passed in callee-saved R10.
+  CCIfSwiftSelf<CCIfType<[i64], CCAssignToReg<[R10D]>>>,
+
+  // A SwiftError is passed in R0.
+  CCIfSwiftError<CCIfType<[i64], CCAssignToReg<[R0D]>>>,
+
+  // First i128 values. These are already split into two i64 here,
+  // so we have to use a custom handler and assign into registers, if possible
+  // We need to deal with this first
+  CCIfType<[i64], CCCustom<"CC_SystemZ_I128Indirect">>,
+  // The first 3 integer arguments are passed in registers R1D-R3D.
+  // The rest will be passed in the user area. The address offset of the user
+  // area can be found in register R4D.
+  CCIfType<[i32], CCAssignToReg<[R1L, R2L, R3L]>>,
+  CCIfType<[i64], CCAssignToReg<[R1D, R2D, R3D]>>,
+
+  // The first 8 named vector arguments are passed in V24-V31.  Sub-128 vectors
+  // are passed in the same way, but they're widened to one of these types
+  // during type legalization.
+  CCIfSubtarget<"hasVector()",
+    CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
+             CCIfFixed<CCCustom<"CC_XPLINK64_Shadow_Reg">>>>,
+  CCIfSubtarget<"hasVector()",
+    CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
+             CCIfFixed<CCAssignToReg<[V24, V25, V26, V27,
+                                      V28, V29, V30, V31]>>>>,
+
+  // The first 4 named  float and double arguments are passed in registers FPR0-FPR6.
+  // The rest will be passed in the user area.
+  CCIfType<[f32, f64], CCIfFixed<CCCustom<"CC_XPLINK64_Shadow_Reg">>>,
+  CCIfType<[f32], CCIfFixed<CCAssignToReg<[F0S, F2S, F4S, F6S]>>>,
+  CCIfType<[f64], CCIfFixed<CCAssignToReg<[F0D, F2D, F4D, F6D]>>>,
+  // The first 2 long double arguments are passed in register FPR0/FPR2
+  // and FPR4/FPR6. The rest will be passed in the user area.
+  CCIfType<[f128], CCIfFixed<CCCustom<"CC_XPLINK64_Shadow_Reg">>>,
+  CCIfType<[f128], CCIfFixed<CCAssignToReg<[F0Q, F4Q]>>>,
+
+  // Non fixed floats are passed in GPRs
+  // Promote f32 to f64, if it needs to be passed in GPRs.
+  CCIfType<[f32], CCIfNotFixed<CCPromoteToType<f64>>>,
+  // Assign f64 varargs to their proper GPRs.
+  CCIfType<[f64], CCIfNotFixed<CCAssignToReg<[R1D, R2D, R3D]>>>,
+  // long double, can only be passed in GPR2 and GPR3, if available,
+  // hence R2Q
+  CCIfType<[f128], CCIfNotFixed<CCCustom<"CC_XPLINK64_Allocate128BitVararg">>>,
+
+  // Non fixed vector arguments are treated in the same way as long
+  // doubles.
+  CCIfSubtarget<"hasVector()",
+    CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
+      CCIfNotFixed<CCCustom<"CC_XPLINK64_Allocate128BitVararg">>>>,
+
+  // Other arguments are passed in 8-byte-aligned 8-byte stack slots.
+  CCIfType<[i32, i64, f32, f64], CCAssignToStack<8, 8>>,
+  // Other f128 arguments are passed in 8-byte-aligned 16-byte stack slots.
+  CCIfType<[f128], CCAssignToStack<16, 8>>,
+  // Vector arguments are passed in 8-byte-alinged 16-byte stack slots too.
+  CCIfSubtarget<"hasVector()",
+    CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
+             CCAssignToStack<16, 8>>>
+]>;
+
 //===----------------------------------------------------------------------===//
 // s390x return value calling convention
 //===----------------------------------------------------------------------===//
 
 def RetCC_SystemZ : CallingConv<[
+  // zOS XPLINK64
+  CCIfSubtarget<"isTargetXPLINK64()", CCDelegateTo<RetCC_SystemZ_XPLINK64>>,
 
   // ELF Linux SystemZ
   CCIfSubtarget<"isTargetELF()", CCDelegateTo<RetCC_SystemZ_ELF>>
@@ -176,6 +302,8 @@ def RetCC_SystemZ : CallingConv<[
 // s390x argument calling conventions
 //===----------------------------------------------------------------------===//
 def CC_SystemZ : CallingConv<[
+  // zOS XPLINK64
+  CCIfSubtarget<"isTargetXPLINK64()", CCDelegateTo<CC_SystemZ_XPLINK64>>,
 
   // ELF Linux SystemZ
   CCIfSubtarget<"isTargetELF()", CCDelegateTo<CC_SystemZ_ELF>>


        


More information about the llvm-commits mailing list