forked from OSchip/llvm-project
[SystemZ/z/OS] Add XPLINK 64-bit calling convention to tablegen.
This commit adds the initial changes to the SystemZ target description for the XPLINK 64-bit calling convention on z/OS. Additions include: - a new predicate IsTargetXPLINK64 - different register allocation order - generaton of nopr after a call Reviewed-by: uweigand Differential Revision: https://reviews.llvm.org/D96887
This commit is contained in:
parent
3275b18f89
commit
b006f55544
|
@ -126,10 +126,15 @@ static MCInst lowerSubvectorStore(const MachineInstr *MI, unsigned Opcode) {
|
|||
|
||||
void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
|
||||
SystemZMCInstLower Lower(MF->getContext(), *this);
|
||||
const SystemZSubtarget *Subtarget = &MF->getSubtarget<SystemZSubtarget>();
|
||||
MCInst LoweredMI;
|
||||
switch (MI->getOpcode()) {
|
||||
case SystemZ::Return:
|
||||
LoweredMI = MCInstBuilder(SystemZ::BR).addReg(SystemZ::R14D);
|
||||
if (Subtarget->isTargetXPLINK64())
|
||||
LoweredMI =
|
||||
MCInstBuilder(SystemZ::B).addReg(SystemZ::R7D).addImm(2).addReg(0);
|
||||
else
|
||||
LoweredMI = MCInstBuilder(SystemZ::BR).addReg(SystemZ::R14D);
|
||||
break;
|
||||
|
||||
case SystemZ::CondReturn:
|
||||
|
@ -211,6 +216,26 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
|
|||
.addImm(0);
|
||||
break;
|
||||
|
||||
case SystemZ::CallBRASL_XPLINK64:
|
||||
EmitToStreamer(*OutStreamer,
|
||||
MCInstBuilder(SystemZ::BRASL)
|
||||
.addReg(SystemZ::R7D)
|
||||
.addExpr(Lower.getExpr(MI->getOperand(0),
|
||||
MCSymbolRefExpr::VK_PLT)));
|
||||
EmitToStreamer(
|
||||
*OutStreamer,
|
||||
MCInstBuilder(SystemZ::BCRAsm).addImm(0).addReg(SystemZ::R3D));
|
||||
return;
|
||||
|
||||
case SystemZ::CallBASR_XPLINK64:
|
||||
EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BASR)
|
||||
.addReg(SystemZ::R7D)
|
||||
.addReg(MI->getOperand(0).getReg()));
|
||||
EmitToStreamer(
|
||||
*OutStreamer,
|
||||
MCInstBuilder(SystemZ::BCRAsm).addImm(0).addReg(SystemZ::R0D));
|
||||
return;
|
||||
|
||||
case SystemZ::CallBRASL:
|
||||
LoweredMI = MCInstBuilder(SystemZ::BRASL)
|
||||
.addReg(SystemZ::R14D)
|
||||
|
|
|
@ -155,6 +155,12 @@ def CSR_SystemZ_AllRegs_Vector : CalleeSavedRegs<(add (sequence "R%dD", 2, 15),
|
|||
|
||||
def CSR_SystemZ_NoRegs : CalleeSavedRegs<(add)>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// z/OS XPLINK64 callee-saved registers
|
||||
//===----------------------------------------------------------------------===//
|
||||
def CSR_SystemZ_XPLINK64 : CalleeSavedRegs<(add (sequence "R%dD", 8, 15),
|
||||
(sequence "F%dD", 8, 15))>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// s390x return value calling convention
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def IsTargetXPLINK64 : Predicate<"Subtarget->isTargetXPLINK64()">;
|
||||
def IsTargetELF : Predicate<"Subtarget->isTargetELF()">;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -275,6 +276,16 @@ let isCall = 1, Defs = [CC] in {
|
|||
def BASR : CallRR <"basr", 0x0D>;
|
||||
}
|
||||
|
||||
// z/OS XPLINK
|
||||
let Predicates = [IsTargetXPLINK64] in {
|
||||
let isCall = 1, Defs = [R7D, CC], Uses = [FPC] in {
|
||||
def CallBRASL_XPLINK64 : Alias<8, (outs), (ins pcrel32:$I2, variable_ops),
|
||||
[(z_call pcrel32:$I2)]>;
|
||||
def CallBASR_XPLINK64 : Alias<4, (outs), (ins ADDR64:$R2, variable_ops),
|
||||
[(z_call ADDR64:$R2)]>;
|
||||
}
|
||||
}
|
||||
|
||||
// Regular calls.
|
||||
// z/Linux ELF
|
||||
let Predicates = [IsTargetELF] in {
|
||||
|
@ -295,7 +306,8 @@ let Predicates = [IsTargetELF] in {
|
|||
}
|
||||
}
|
||||
|
||||
// Sibling calls.
|
||||
// Sibling calls. Indirect sibling calls must be via R6 for XPLink,
|
||||
// R1 used for ELF
|
||||
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in {
|
||||
def CallJG : Alias<6, (outs), (ins pcrel32:$I2),
|
||||
[(z_sibcall pcrel32:$I2)]>;
|
||||
|
@ -323,7 +335,7 @@ let isCall = 1, isTerminator = 1, isReturn = 1 in {
|
|||
def CLGIBCall : Alias<6, (outs), (ins GR64:$R1, imm64zx8:$I2, cond4:$M3, ADDR64:$R4), []>;
|
||||
}
|
||||
|
||||
// A return instruction (br %r14).
|
||||
// A return instruction (br %r14) for ELF and (b 2 %r7) for XPLink.
|
||||
let isReturn = 1, isTerminator = 1, isBarrier = 1, hasCtrlDep = 1 in
|
||||
def Return : Alias<2, (outs), (ins), [(z_retflag)]>;
|
||||
|
||||
|
|
|
@ -31,8 +31,10 @@ def subreg_hl32 : ComposedSubRegIndex<subreg_h64, subreg_l32>;
|
|||
// Define a register class that contains values of types TYPES and an
|
||||
// associated operand called NAME. SIZE is the size and alignment
|
||||
// of the registers and REGLIST is the list of individual registers.
|
||||
// If the user provides an alternate order list of regs, it will be used for
|
||||
// XPLINK. Otherwise, by default, XPLINK will use the regList ordering as well
|
||||
multiclass SystemZRegClass<string name, list<ValueType> types, int size,
|
||||
dag regList, bit allocatable = 1> {
|
||||
dag regList, list<dag> altRegList = [regList], bit allocatable = 1> {
|
||||
def AsmOperand : AsmOperandClass {
|
||||
let Name = name;
|
||||
let ParserMethod = "parse"#name;
|
||||
|
@ -41,6 +43,11 @@ multiclass SystemZRegClass<string name, list<ValueType> types, int size,
|
|||
let isAllocatable = allocatable in
|
||||
def Bit : RegisterClass<"SystemZ", types, size, regList> {
|
||||
let Size = size;
|
||||
let AltOrders = altRegList;
|
||||
let AltOrderSelect = [{
|
||||
const SystemZSubtarget &S = MF.getSubtarget<SystemZSubtarget>();
|
||||
return S.isTargetXPLINK64();
|
||||
}];
|
||||
}
|
||||
def "" : RegisterOperand<!cast<RegisterClass>(name#"Bit")> {
|
||||
let ParserMatchClass = !cast<AsmOperandClass>(name#"AsmOperand");
|
||||
|
@ -85,40 +92,58 @@ foreach I = [0, 2, 4, 6, 8, 10, 12, 14] in {
|
|||
!cast<GPR64>("R"#I#"D")>;
|
||||
}
|
||||
|
||||
/// Allocate the callee-saved R6-R13 backwards. That way they can be saved
|
||||
/// together with R14 and R15 in one prolog instruction.
|
||||
/// zLinux: Allocate the callee-saved R6-R13 backwards. That way they can be
|
||||
/// saved together with R14 and R15 in one prolog instruction.
|
||||
/// XPLINK64: Allocate all registers in natural order
|
||||
defm GR32 : SystemZRegClass<"GR32", [i32], 32,
|
||||
(add (sequence "R%uL", 0, 5),
|
||||
(sequence "R%uL", 15, 6))>;
|
||||
(sequence "R%uL", 15, 6)),
|
||||
[(add (sequence "R%uL", 0, 15))]>;
|
||||
defm GRH32 : SystemZRegClass<"GRH32", [i32], 32,
|
||||
(add (sequence "R%uH", 0, 5),
|
||||
(sequence "R%uH", 15, 6))>;
|
||||
(sequence "R%uH", 15, 6)),
|
||||
[(add (sequence "R%uH", 0, 15))]>;
|
||||
defm GR64 : SystemZRegClass<"GR64", [i64], 64,
|
||||
(add (sequence "R%uD", 0, 5),
|
||||
(sequence "R%uD", 15, 6))>;
|
||||
(sequence "R%uD", 15, 6)),
|
||||
[(add (sequence "R%uD", 0, 15))]>;
|
||||
|
||||
// Combine the low and high GR32s into a single class. This can only be
|
||||
// used for virtual registers if the high-word facility is available.
|
||||
/// XPLINK64: Allocate all registers in natural order
|
||||
defm GRX32 : SystemZRegClass<"GRX32", [i32], 32,
|
||||
(add (sequence "R%uL", 0, 5),
|
||||
(sequence "R%uH", 0, 5),
|
||||
R15L, R15H, R14L, R14H, R13L, R13H,
|
||||
R12L, R12H, R11L, R11H, R10L, R10H,
|
||||
R9L, R9H, R8L, R8H, R7L, R7H, R6L, R6H)>;
|
||||
R9L, R9H, R8L, R8H, R7L, R7H, R6L, R6H),
|
||||
[(add
|
||||
R0L, R1L, R2L, R3L, R0H, R1H, R2H, R3H,
|
||||
R4L, R4H, R5L, R5H, R6L, R6H, R7L, R7H,
|
||||
R8L, R8H, R9L, R9H, R10L,R10H,R11L,R11H,
|
||||
R12L,R12H,R13L,R13H,R14L,R14H,R15L,R15H)
|
||||
]>;
|
||||
|
||||
// The architecture doesn't really have any i128 support, so model the
|
||||
// register pairs as untyped instead.
|
||||
// XPLINK64: Allocate all registers in natural order
|
||||
defm GR128 : SystemZRegClass<"GR128", [untyped], 128,
|
||||
(add R0Q, R2Q, R4Q, R12Q, R10Q, R8Q, R6Q, R14Q)>;
|
||||
(add R0Q, R2Q, R4Q, R12Q, R10Q, R8Q, R6Q, R14Q),
|
||||
[(add R0Q, R2Q, R4Q, R6Q, R8Q, R10Q, R12Q, R14Q)]>;
|
||||
|
||||
// Base and index registers. Everything except R0, which in an address
|
||||
// context evaluates as 0.
|
||||
defm ADDR32 : SystemZRegClass<"ADDR32", [i32], 32, (sub GR32Bit, R0L)>;
|
||||
defm ADDR64 : SystemZRegClass<"ADDR64", [i64], 64, (sub GR64Bit, R0D)>;
|
||||
// XPLINK64: Allocate all registers in natural order
|
||||
defm ADDR32 : SystemZRegClass<"ADDR32", [i32], 32, (sub GR32Bit, R0L),
|
||||
[(add (sequence "R%uL", 1, 15))]>;
|
||||
defm ADDR64 : SystemZRegClass<"ADDR64", [i64], 64, (sub GR64Bit, R0D),
|
||||
[(add (sequence "R%uD", 1, 15))]>;
|
||||
|
||||
// Not used directly, but needs to exist for ADDR32 and ADDR64 subregs
|
||||
// of a GR128.
|
||||
defm ADDR128 : SystemZRegClass<"ADDR128", [untyped], 128, (sub GR128Bit, R0Q)>;
|
||||
// XPLINK64: Allocate all registers in natural order
|
||||
defm ADDR128 : SystemZRegClass<"ADDR128", [untyped], 128, (sub GR128Bit, R0Q),
|
||||
[(add R2Q, R4Q, R6Q, R8Q, R10Q, R12Q, R14Q)]>;
|
||||
|
||||
// Any type register. Used for .insn directives when we don't know what the
|
||||
// register types could be.
|
||||
|
@ -126,7 +151,8 @@ defm AnyReg : SystemZRegClass<"AnyReg",
|
|||
[i64, f64, v8i8, v4i16, v2i32, v2f32], 64,
|
||||
(add (sequence "R%uD", 0, 15),
|
||||
(sequence "F%uD", 0, 15),
|
||||
(sequence "V%u", 0, 15)), 0/*allocatable*/>;
|
||||
(sequence "V%u", 0, 15)),
|
||||
[], 0/*allocatable*/>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Floating-point registers
|
||||
|
@ -310,7 +336,7 @@ foreach I = 0-15 in {
|
|||
def A#I : ACR32<I, "a"#I>, DwarfRegNum<[!add(I, 48)]>;
|
||||
}
|
||||
defm AR32 : SystemZRegClass<"AR32", [i32], 32,
|
||||
(add (sequence "A%u", 0, 15)), 0>;
|
||||
(add (sequence "A%u", 0, 15)), [], 0>;
|
||||
|
||||
// Control registers.
|
||||
class CREG64<bits<16> num, string n> : SystemZReg<n> {
|
||||
|
@ -320,5 +346,4 @@ foreach I = 0-15 in {
|
|||
def C#I : CREG64<I, "c"#I>, DwarfRegNum<[!add(I, 32)]>;
|
||||
}
|
||||
defm CR64 : SystemZRegClass<"CR64", [i64], 64,
|
||||
(add (sequence "C%u", 0, 15)), 0>;
|
||||
|
||||
(add (sequence "C%u", 0, 15)), [], 0>;
|
||||
|
|
|
@ -167,8 +167,8 @@ def : InstRW<[WLat1, FXb, LSU, NormalGr], (instregex "CL(G)?T(Asm.*)?$")>;
|
|||
|
||||
// Call
|
||||
def : InstRW<[WLat1, VBU, FXa2, GroupAlone], (instregex "(Call)?BRAS$")>;
|
||||
def : InstRW<[WLat1, FXa2, FXb, GroupAlone], (instregex "(Call)?BRASL$")>;
|
||||
def : InstRW<[WLat1, FXa2, FXb, GroupAlone], (instregex "(Call)?BAS(R)?$")>;
|
||||
def : InstRW<[WLat1, FXa2, FXb, GroupAlone], (instregex "(Call)?BRASL(_XPLINK64)?$")>;
|
||||
def : InstRW<[WLat1, FXa2, FXb, GroupAlone], (instregex "(Call)?BAS(R)?(_XPLINK64)?$")>;
|
||||
def : InstRW<[WLat1, FXa2, FXb, GroupAlone], (instregex "TLS_(G|L)DCALL$")>;
|
||||
|
||||
// Return
|
||||
|
|
|
@ -168,8 +168,8 @@ def : InstRW<[WLat1, FXb, LSU, NormalGr], (instregex "CL(G)?T(Asm.*)?$")>;
|
|||
|
||||
// Call
|
||||
def : InstRW<[WLat1, VBU, FXa2, GroupAlone], (instregex "(Call)?BRAS$")>;
|
||||
def : InstRW<[WLat1, FXa2, FXb, GroupAlone], (instregex "(Call)?BRASL$")>;
|
||||
def : InstRW<[WLat1, FXa2, FXb, GroupAlone], (instregex "(Call)?BAS(R)?$")>;
|
||||
def : InstRW<[WLat1, FXa2, FXb, GroupAlone], (instregex "(Call)?BRASL(_XPLINK64)?$")>;
|
||||
def : InstRW<[WLat1, FXa2, FXb, GroupAlone], (instregex "(Call)?BAS(R)?(_XPLINK64)?$")>;
|
||||
def : InstRW<[WLat1, FXa2, FXb, GroupAlone], (instregex "TLS_(G|L)DCALL$")>;
|
||||
|
||||
// Return
|
||||
|
|
|
@ -168,8 +168,8 @@ def : InstRW<[WLat1, FXb, LSU, NormalGr], (instregex "CL(G)?T(Asm.*)?$")>;
|
|||
|
||||
// Call
|
||||
def : InstRW<[WLat1, VBU, FXa2, GroupAlone], (instregex "(Call)?BRAS$")>;
|
||||
def : InstRW<[WLat1, FXa2, FXb, GroupAlone], (instregex "(Call)?BRASL$")>;
|
||||
def : InstRW<[WLat1, FXa2, FXb, GroupAlone], (instregex "(Call)?BAS(R)?$")>;
|
||||
def : InstRW<[WLat1, FXa2, FXb, GroupAlone], (instregex "(Call)?BRASL(_XPLINK64)?$")>;
|
||||
def : InstRW<[WLat1, FXa2, FXb, GroupAlone], (instregex "(Call)?BAS(R)?(_XPLINK64)?$")>;
|
||||
def : InstRW<[WLat1, FXa2, FXb, GroupAlone], (instregex "TLS_(G|L)DCALL$")>;
|
||||
|
||||
// Return
|
||||
|
|
|
@ -146,8 +146,8 @@ def : InstRW<[WLat1, FXU, NormalGr], (instregex "CL(F|G)IT(Asm.*)?$")>;
|
|||
|
||||
// Call
|
||||
def : InstRW<[WLat1, LSU, FXU2, GroupAlone], (instregex "(Call)?BRAS$")>;
|
||||
def : InstRW<[WLat1, LSU, FXU2, GroupAlone], (instregex "(Call)?BRASL$")>;
|
||||
def : InstRW<[WLat1, LSU, FXU2, GroupAlone], (instregex "(Call)?BAS(R)?$")>;
|
||||
def : InstRW<[WLat1, LSU, FXU2, GroupAlone], (instregex "(Call)?BRASL(_XPLINK64)?$")>;
|
||||
def : InstRW<[WLat1, LSU, FXU2, GroupAlone], (instregex "(Call)?BAS(R)?(_XPLINK64)?$")>;
|
||||
def : InstRW<[WLat1, LSU, FXU2, GroupAlone], (instregex "TLS_(G|L)DCALL$")>;
|
||||
|
||||
// Return
|
||||
|
|
|
@ -151,8 +151,8 @@ def : InstRW<[WLat1, FXU, LSU, NormalGr], (instregex "CL(G)?T(Asm.*)?$")>;
|
|||
|
||||
// Call
|
||||
def : InstRW<[WLat1, FXU2, VBU, GroupAlone], (instregex "(Call)?BRAS$")>;
|
||||
def : InstRW<[WLat1, FXU2, LSU, GroupAlone], (instregex "(Call)?BRASL$")>;
|
||||
def : InstRW<[WLat1, FXU2, LSU, GroupAlone], (instregex "(Call)?BAS(R)?$")>;
|
||||
def : InstRW<[WLat1, FXU2, LSU, GroupAlone], (instregex "(Call)?BRASL(_XPLINK64)?$")>;
|
||||
def : InstRW<[WLat1, FXU2, LSU, GroupAlone], (instregex "(Call)?BAS(R)?(_XPLINK64)?$")>;
|
||||
def : InstRW<[WLat1, FXU2, LSU, GroupAlone], (instregex "TLS_(G|L)DCALL$")>;
|
||||
|
||||
// Return
|
||||
|
|
|
@ -248,6 +248,15 @@ public:
|
|||
bool isPC32DBLSymbol(const GlobalValue *GV, CodeModel::Model CM) const;
|
||||
|
||||
bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); }
|
||||
|
||||
// Returns TRUE if we are generating GOFF object code
|
||||
bool isTargetGOFF() const { return TargetTriple.isOSBinFormatGOFF(); }
|
||||
|
||||
// Returns TRUE if we are using XPLINK64 linkage convention
|
||||
bool isTargetXPLINK64() const { return (isTargetGOFF() && isTargetzOS()); }
|
||||
|
||||
// Returns TRUE if we are generating code for a s390x machine running zOS
|
||||
bool isTargetzOS() const { return TargetTriple.isOSzOS(); }
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
|
|
Loading…
Reference in New Issue