diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp --- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp +++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp @@ -126,10 +126,15 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) { SystemZMCInstLower Lower(MF->getContext(), *this); + const SystemZSubtarget *Subtarget = &MF->getSubtarget(); 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 @@ .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) diff --git a/llvm/lib/Target/SystemZ/SystemZCallingConv.td b/llvm/lib/Target/SystemZ/SystemZCallingConv.td --- a/llvm/lib/Target/SystemZ/SystemZCallingConv.td +++ b/llvm/lib/Target/SystemZ/SystemZCallingConv.td @@ -155,6 +155,12 @@ 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 //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td --- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +def IsTargetXPLINK64 : Predicate<"Subtarget->isTargetXPLINK64()">; def IsTargetELF : Predicate<"Subtarget->isTargetELF()">; //===----------------------------------------------------------------------===// @@ -275,6 +276,16 @@ 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 @@ } } -// 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 @@ 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)]>; diff --git a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.td b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.td --- a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.td +++ b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.td @@ -31,8 +31,10 @@ // 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 types, int size, - dag regList, bit allocatable = 1> { + dag regList, list altRegList = [regList], bit allocatable = 1> { def AsmOperand : AsmOperandClass { let Name = name; let ParserMethod = "parse"#name; @@ -41,6 +43,11 @@ let isAllocatable = allocatable in def Bit : RegisterClass<"SystemZ", types, size, regList> { let Size = size; + let AltOrders = altRegList; + let AltOrderSelect = [{ + const SystemZSubtarget &S = MF.getSubtarget(); + return S.isTargetXPLINK64(); + }]; } def "" : RegisterOperand(name#"Bit")> { let ParserMatchClass = !cast(name#"AsmOperand"); @@ -85,40 +92,58 @@ !cast("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 @@ [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 @@ def A#I : ACR32, 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 num, string n> : SystemZReg { @@ -320,5 +346,4 @@ def C#I : CREG64, DwarfRegNum<[!add(I, 32)]>; } defm CR64 : SystemZRegClass<"CR64", [i64], 64, - (add (sequence "C%u", 0, 15)), 0>; - + (add (sequence "C%u", 0, 15)), [], 0>; diff --git a/llvm/lib/Target/SystemZ/SystemZScheduleZ13.td b/llvm/lib/Target/SystemZ/SystemZScheduleZ13.td --- a/llvm/lib/Target/SystemZ/SystemZScheduleZ13.td +++ b/llvm/lib/Target/SystemZ/SystemZScheduleZ13.td @@ -167,8 +167,8 @@ // 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 diff --git a/llvm/lib/Target/SystemZ/SystemZScheduleZ14.td b/llvm/lib/Target/SystemZ/SystemZScheduleZ14.td --- a/llvm/lib/Target/SystemZ/SystemZScheduleZ14.td +++ b/llvm/lib/Target/SystemZ/SystemZScheduleZ14.td @@ -168,8 +168,8 @@ // 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 diff --git a/llvm/lib/Target/SystemZ/SystemZScheduleZ15.td b/llvm/lib/Target/SystemZ/SystemZScheduleZ15.td --- a/llvm/lib/Target/SystemZ/SystemZScheduleZ15.td +++ b/llvm/lib/Target/SystemZ/SystemZScheduleZ15.td @@ -168,8 +168,8 @@ // 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 diff --git a/llvm/lib/Target/SystemZ/SystemZScheduleZ196.td b/llvm/lib/Target/SystemZ/SystemZScheduleZ196.td --- a/llvm/lib/Target/SystemZ/SystemZScheduleZ196.td +++ b/llvm/lib/Target/SystemZ/SystemZScheduleZ196.td @@ -146,8 +146,8 @@ // 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 diff --git a/llvm/lib/Target/SystemZ/SystemZScheduleZEC12.td b/llvm/lib/Target/SystemZ/SystemZScheduleZEC12.td --- a/llvm/lib/Target/SystemZ/SystemZScheduleZEC12.td +++ b/llvm/lib/Target/SystemZ/SystemZScheduleZEC12.td @@ -151,8 +151,8 @@ // 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 diff --git a/llvm/lib/Target/SystemZ/SystemZSubtarget.h b/llvm/lib/Target/SystemZ/SystemZSubtarget.h --- a/llvm/lib/Target/SystemZ/SystemZSubtarget.h +++ b/llvm/lib/Target/SystemZ/SystemZSubtarget.h @@ -248,6 +248,15 @@ 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