forked from OSchip/llvm-project
[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
This commit is contained in:
parent
9f57675e52
commit
ec4706be8e
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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 &) {
|
||||
|
|
|
@ -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>>
|
||||
|
|
Loading…
Reference in New Issue