Index: include/llvm/Target/TargetRegisterInfo.h =================================================================== --- include/llvm/Target/TargetRegisterInfo.h +++ include/llvm/Target/TargetRegisterInfo.h @@ -767,7 +767,8 @@ /// Get a list of 'hint' registers that the register allocator should try /// first when allocating a physical register for the virtual register /// VirtReg. These registers are effectively moved to the front of the - /// allocation order. + /// allocation order. If true is returned, regalloc will try to only use + /// hints to the greatest extent possible even if it means spilling. /// /// The Order argument is the allocation order for VirtReg's register class /// as returned from RegisterClassInfo::getOrder(). The hint registers must @@ -778,7 +779,7 @@ /// HintType == 0. Targets that override this function should defer to the /// default implementation if they have no reason to change the allocation /// order for VirtReg. There may be target-independent hints. - virtual void getRegAllocationHints(unsigned VirtReg, + virtual bool getRegAllocationHints(unsigned VirtReg, ArrayRef Order, SmallVectorImpl &Hints, const MachineFunction &MF, Index: lib/CodeGen/AllocationOrder.h =================================================================== --- lib/CodeGen/AllocationOrder.h +++ lib/CodeGen/AllocationOrder.h @@ -32,7 +32,11 @@ ArrayRef Order; int Pos; + // If HardHints is true, *only* Hints will be returned. + bool HardHints; + public: + /// Create a new AllocationOrder for VirtReg. /// @param VirtReg Virtual register to allocate for. /// @param VRM Virtual register map for function. @@ -51,6 +55,8 @@ unsigned next(unsigned Limit = 0) { if (Pos < 0) return Hints.end()[Pos++]; + if (HardHints) + return 0; if (!Limit) Limit = Order.size(); while (Pos < int(Limit)) { @@ -68,6 +74,8 @@ unsigned nextWithDups(unsigned Limit) { if (Pos < 0) return Hints.end()[Pos++]; + if (HardHints) + return 0; if (Pos < int(Limit)) return Order[Pos++]; return 0; Index: lib/CodeGen/AllocationOrder.cpp =================================================================== --- lib/CodeGen/AllocationOrder.cpp +++ lib/CodeGen/AllocationOrder.cpp @@ -31,11 +31,12 @@ const VirtRegMap &VRM, const RegisterClassInfo &RegClassInfo, const LiveRegMatrix *Matrix) - : Pos(0) { + : Pos(0), HardHints(false) { const MachineFunction &MF = VRM.getMachineFunction(); const TargetRegisterInfo *TRI = &VRM.getTargetRegInfo(); Order = RegClassInfo.getOrder(MF.getRegInfo().getRegClass(VirtReg)); - TRI->getRegAllocationHints(VirtReg, Order, Hints, MF, &VRM, Matrix); + if (TRI->getRegAllocationHints(VirtReg, Order, Hints, MF, &VRM, Matrix)) + HardHints = true; rewind(); DEBUG({ Index: lib/CodeGen/TargetRegisterInfo.cpp =================================================================== --- lib/CodeGen/TargetRegisterInfo.cpp +++ lib/CodeGen/TargetRegisterInfo.cpp @@ -357,7 +357,7 @@ } // Compute target-independent register allocator hints to help eliminate copies. -void +bool TargetRegisterInfo::getRegAllocationHints(unsigned VirtReg, ArrayRef Order, SmallVectorImpl &Hints, @@ -379,17 +379,18 @@ // Check that Phys is a valid hint in VirtReg's register class. if (!isPhysicalRegister(Phys)) - return; + return false; if (MRI.isReserved(Phys)) - return; + return false; // Check that Phys is in the allocation order. We shouldn't heed hints // from VirtReg's register class if they aren't in the allocation order. The // target probably has a reason for removing the register. if (!is_contained(Order, Phys)) - return; + return false; // All clear, tell the register allocator to prefer this register. Hints.push_back(Phys); + return false; } bool TargetRegisterInfo::canRealignStack(const MachineFunction &MF) const { Index: lib/Target/ARM/ARMBaseRegisterInfo.h =================================================================== --- lib/Target/ARM/ARMBaseRegisterInfo.h +++ lib/Target/ARM/ARMBaseRegisterInfo.h @@ -143,7 +143,7 @@ unsigned getRegPressureLimit(const TargetRegisterClass *RC, MachineFunction &MF) const override; - void getRegAllocationHints(unsigned VirtReg, + bool getRegAllocationHints(unsigned VirtReg, ArrayRef Order, SmallVectorImpl &Hints, const MachineFunction &MF, Index: lib/Target/ARM/ARMBaseRegisterInfo.cpp =================================================================== --- lib/Target/ARM/ARMBaseRegisterInfo.cpp +++ lib/Target/ARM/ARMBaseRegisterInfo.cpp @@ -274,7 +274,7 @@ } // Resolve the RegPairEven / RegPairOdd register allocator hints. -void +bool ARMBaseRegisterInfo::getRegAllocationHints(unsigned VirtReg, ArrayRef Order, SmallVectorImpl &Hints, @@ -294,7 +294,7 @@ break; default: TargetRegisterInfo::getRegAllocationHints(VirtReg, Order, Hints, MF, VRM); - return; + return false; } // This register should preferably be even (Odd == 0) or odd (Odd == 1). @@ -302,7 +302,7 @@ // the paired register as the first hint. unsigned Paired = Hint.second; if (Paired == 0) - return; + return false; unsigned PairedPhys = 0; if (TargetRegisterInfo::isPhysicalRegister(Paired)) { @@ -325,6 +325,7 @@ continue; Hints.push_back(Reg); } + return false; } void Index: lib/Target/SystemZ/SystemZInstrInfo.cpp =================================================================== --- lib/Target/SystemZ/SystemZInstrInfo.cpp +++ lib/Target/SystemZ/SystemZInstrInfo.cpp @@ -16,6 +16,7 @@ #include "SystemZ.h" #include "SystemZInstrBuilder.h" #include "SystemZSubtarget.h" +#include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/LiveInterval.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "llvm/CodeGen/LiveVariables.h" @@ -30,6 +31,7 @@ #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/Support/BranchProbability.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Target/TargetInstrInfo.h" @@ -45,6 +47,9 @@ #define GET_INSTRMAP_INFO #include "SystemZGenInstrInfo.inc" +#define DEBUG_TYPE "systemz-II" +STATISTIC(RISBs, "Number of RISBs jump/sequences (lower is better)"); + // Return a mask with Count low bits set. static uint64_t allOnes(unsigned int Count) { return Count == 0 ? 0 : (uint64_t(1) << (Count - 1) << 1) - 1; @@ -195,6 +200,10 @@ MI.setDesc(get(Opcode)); } +// EXPERIMENTAL +STATISTIC(LOCRs_lo, "Number of LOCRs_lo"); +STATISTIC(LOCRs_hi, "Number of LOCRs_hi"); + // MI is a load-register-on-condition pseudo instruction. Replace it with // LowOpcode if source and destination are both low GR32s and HighOpcode if // source and destination are both high GR32s. @@ -205,10 +214,16 @@ bool DestIsHigh = isHighReg(DestReg); bool SrcIsHigh = isHighReg(SrcReg); - if (!DestIsHigh && !SrcIsHigh) + if (!DestIsHigh && !SrcIsHigh) { MI.setDesc(get(LowOpcode)); - else if (DestIsHigh && SrcIsHigh) + LOCRs_lo++; + } + else if (DestIsHigh && SrcIsHigh) { MI.setDesc(get(HighOpcode)); + LOCRs_hi++; + } + else + RISBs++; // If we were unable to implement the pseudo with a single instruction, we // need to convert it back into a branch sequence. This cannot be done here @@ -844,10 +859,15 @@ return false; } +// EXPERIMENTAL +STATISTIC(PHYSCOPYS, "Number of copyPhysReg calls (lower is better)"); + void SystemZInstrInfo::copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, bool KillSrc) const { + PHYSCOPYS++; + // Split 128-bit GPR moves into two 64-bit moves. Add implicit uses of the // super register in case one of the subregs is undefined. // This handles ADDR128 too. Index: lib/Target/SystemZ/SystemZRegisterInfo.h =================================================================== --- lib/Target/SystemZ/SystemZRegisterInfo.h +++ lib/Target/SystemZ/SystemZRegisterInfo.h @@ -42,6 +42,13 @@ return &SystemZ::ADDR64BitRegClass; } + bool getRegAllocationHints(unsigned VirtReg, + ArrayRef Order, + SmallVectorImpl &Hints, + const MachineFunction &MF, + const VirtRegMap *VRM, + const LiveRegMatrix *Matrix) const override; + // Override TargetRegisterInfo.h. bool requiresRegisterScavenging(const MachineFunction &MF) const override { return true; Index: lib/Target/SystemZ/SystemZRegisterInfo.cpp =================================================================== --- lib/Target/SystemZ/SystemZRegisterInfo.cpp +++ lib/Target/SystemZ/SystemZRegisterInfo.cpp @@ -10,8 +10,10 @@ #include "SystemZRegisterInfo.h" #include "SystemZInstrInfo.h" #include "SystemZSubtarget.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/VirtRegMap.h" #include "llvm/Target/TargetFrameLowering.h" using namespace llvm; @@ -22,6 +24,120 @@ SystemZRegisterInfo::SystemZRegisterInfo() : SystemZGenRegisterInfo(SystemZ::R14D) {} +// Given that MO is a GRX32 operand, return either the GR32 or GRH32 regclass +// that MO will eventually belong to. If the regclass is GRX32 and MO has not +// been allocated yet, nullptr is returned. +static const TargetRegisterClass *getRC32(MachineOperand &MO, + const VirtRegMap *VRM, + const MachineRegisterInfo *MRI) { + const TargetRegisterClass *RC = MRI->getRegClass(MO.getReg()); + + if (SystemZ::GR32BitRegClass.hasSubClassEq(RC) || + MO.getSubReg() == SystemZ::subreg_l32) + return &SystemZ::GR32BitRegClass; + if (RC == &SystemZ::GRH32BitRegClass || + MO.getSubReg() == SystemZ::subreg_h32) + return &SystemZ::GRH32BitRegClass; + + if (VRM && VRM->hasPhys(MO.getReg())) { + unsigned PhysReg = VRM->getPhys(MO.getReg()); + if (SystemZ::GR32BitRegClass.contains(PhysReg)) + return &SystemZ::GR32BitRegClass; + assert (SystemZ::GRH32BitRegClass.contains(PhysReg) && + "Phys reg not in GR32 or GRH32?"); + return &SystemZ::GRH32BitRegClass; + } + + assert (RC == &SystemZ::GRX32BitRegClass); + return RC; +} + +static const TargetRegisterClass* +getConstrainedRC32_LOCRMux(MachineInstr *LOCRMuxMI, + const VirtRegMap *VRM, + const MachineRegisterInfo *MRI, + const TargetRegisterInfo *TRI) { + assert (LOCRMuxMI->getOpcode() == SystemZ::LOCRMux && + "Should only be called with LOCRMux"); + + MachineOperand &TrueMO = LOCRMuxMI->getOperand(1); + MachineOperand &FalseMO = LOCRMuxMI->getOperand(2); + const TargetRegisterClass *RC = + TRI->getCommonSubClass(getRC32(FalseMO, VRM, MRI), + getRC32(TrueMO, VRM, MRI)); + if (RC && RC != &SystemZ::GRX32BitRegClass) + return RC; + + return nullptr; +} + +static const TargetRegisterClass* +getHintRC_LOCRMux(unsigned Reg, + const VirtRegMap *VRM, + const MachineRegisterInfo *MRI, + const TargetRegisterInfo *TRI, + bool &UsedByLOCRMux, + SmallVector &Worklist) { + assert (MRI->getRegClass(Reg) == &SystemZ::GRX32BitRegClass); + + for (auto &Use : MRI->use_instructions(Reg)) + if (Use.getOpcode() == SystemZ::LOCRMux) { + UsedByLOCRMux = true; + if (const TargetRegisterClass *ConstrainedRC32 = + getConstrainedRC32_LOCRMux(&Use, VRM, MRI, TRI)) + return ConstrainedRC32; + unsigned TrueReg = Use.getOperand(1).getReg(); + unsigned FalseReg = Use.getOperand(2).getReg(); + unsigned OtherReg = (TrueReg == Reg ? FalseReg : TrueReg); + if (MRI->getRegClass(OtherReg) == &SystemZ::GRX32BitRegClass) + Worklist.push_back(OtherReg); + } + + return nullptr; +} + +bool +SystemZRegisterInfo::getRegAllocationHints(unsigned VirtReg, + ArrayRef Order, + SmallVectorImpl &Hints, + const MachineFunction &MF, + const VirtRegMap *VRM, + const LiveRegMatrix *Matrix) const { + const MachineRegisterInfo *MRI = &MF.getRegInfo(); + const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); + if (MRI->getRegClass(VirtReg) == &SystemZ::GRX32BitRegClass) { + const TargetRegisterClass *ConstrainedRC32 = nullptr; + bool UsedByLOCRMux = false; + SmallVector Worklist; + SmallSet DoneRegs; + Worklist.push_back(VirtReg); + while (Worklist.size()) { + unsigned Reg = Worklist.pop_back_val(); + if (!DoneRegs.insert(Reg).second) + continue; + if ((ConstrainedRC32 = + getHintRC_LOCRMux(Reg, VRM, MRI, TRI, UsedByLOCRMux, Worklist))) + break; + } + + // Force allocation of high-part, since the low-parts are commonly + // demanded by other instructions. + if (UsedByLOCRMux && ConstrainedRC32 == nullptr) + ConstrainedRC32 = &SystemZ::GRH32BitRegClass; + + if (ConstrainedRC32 != nullptr) { + for (MCPhysReg Reg : Order) + if (ConstrainedRC32->contains(Reg) && !MRI->isReserved(Reg)) + Hints.push_back(Reg); + // Return true to make these hints the only regs available to RA. + return true; + } + } // GRX32 + + TargetRegisterInfo::getRegAllocationHints(VirtReg, Order, Hints, MF, VRM); + return false; +} + const MCPhysReg * SystemZRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { if (MF->getSubtarget().getTargetLowering()->supportSwiftError() && Index: lib/Target/SystemZ/SystemZRegisterInfo.td =================================================================== --- lib/Target/SystemZ/SystemZRegisterInfo.td +++ lib/Target/SystemZ/SystemZRegisterInfo.td @@ -102,8 +102,11 @@ // 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. defm GRX32 : SystemZRegClass<"GRX32", [i32], 32, - (add (sequence "R%uL", 0, 5), - (sequence "R%uH", 0, 5), + // (add (sequence "R%uL", 0, 5), + // (sequence "R%uH", 0, 5), +// Mix the allocation order to get more high-parts used for LOCRMux + (add R0L, R0H, R1L, R1H, R2L, R2H, + R3L, R3H, R4L, R4H, R5L, R5H, R15L, R15H, R14L, R14H, R13L, R13H, R12L, R12H, R11L, R11H, R10L, R10H, R9L, R9H, R8L, R8H, R7L, R7H, R6L, R6H)>;