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/SystemZISelLowering.cpp =================================================================== --- lib/Target/SystemZ/SystemZISelLowering.cpp +++ lib/Target/SystemZ/SystemZISelLowering.cpp @@ -5507,6 +5507,15 @@ return Reg; } +// EXPERIMENTAL +static cl::opt LOCRCONSTRAIN("locr-constrain", cl::Hidden, cl::init(false)); + +#include "llvm/ADT/Statistic.h" +STATISTIC(GR32Constrains, "Number of GR32 LOCRs"); +STATISTIC(GR32Constrains_hi, "Number of GR32 LOCRs_hi"); +STATISTIC(GR32X, "Number of GR32X LOCRs"); +STATISTIC(GR32__, "Number of !RC LOCRs"); + // Implement EmitInstrWithCustomInserter for pseudo Select* instruction MI. MachineBasicBlock * SystemZTargetLowering::emitSelect(MachineInstr &MI, @@ -5528,6 +5537,31 @@ .addReg(FalseReg).addReg(TrueReg) .addImm(CCValid).addImm(CCMask); MI.eraseFromParent(); + + if (LOCROpcode == SystemZ::LOCRMux && LOCRCONSTRAIN) { + // Try to help regalloc by constraining GRX32 as called for. + const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); + MachineRegisterInfo *MRI = &MBB->getParent()->getRegInfo(); + // Find smallest common reg class of dest/true/false regs. + const TargetRegisterClass *RC = + TRI->getCommonSubClass(MRI->getRegClass(FalseReg), + MRI->getRegClass(TrueReg)); + RC = TRI->getCommonSubClass(RC, MRI->getRegClass(DestReg)); + if (RC && RC != &SystemZ::GRX32BitRegClass) { + MRI->setRegClass(DestReg, RC); + MRI->setRegClass(FalseReg, RC); + MRI->setRegClass(TrueReg, RC); + if (SystemZ::GR32BitRegClass.hasSubClassEq(RC)) + GR32Constrains++; + else if (RC == &SystemZ::GRH32BitRegClass) + GR32Constrains_hi++; + } + if (RC && RC == &SystemZ::GRX32BitRegClass) + GR32X++; + if (!RC) + GR32__++; + } + return MBB; } Index: lib/Target/SystemZ/SystemZInstrInfo.cpp =================================================================== --- lib/Target/SystemZ/SystemZInstrInfo.cpp +++ lib/Target/SystemZ/SystemZInstrInfo.cpp @@ -195,6 +195,13 @@ MI.setDesc(get(Opcode)); } +#include "llvm/Support/CommandLine.h" +#define DEBUG_TYPE "systemz-II" +#include "llvm/ADT/Statistic.h" +STATISTIC(LOCRs_lo, "Number of LOCRs_lo"); +STATISTIC(LOCRs_hi, "Number of LOCRs_hi"); +STATISTIC(RISBs, "Number of RISBs"); + // 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 +212,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 Index: lib/Target/SystemZ/SystemZRegisterInfo.h =================================================================== --- lib/Target/SystemZ/SystemZRegisterInfo.h +++ lib/Target/SystemZ/SystemZRegisterInfo.h @@ -42,6 +42,16 @@ return &SystemZ::ADDR64BitRegClass; } + bool getRegAllocationHints(unsigned VirtReg, + ArrayRef Order, + SmallVectorImpl &Hints, + const MachineFunction &MF, + const VirtRegMap *VRM, + const LiveRegMatrix *Matrix) const override; + + void updateRegAllocHint(unsigned Reg, unsigned NewReg, + MachineFunction &MF) 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 @@ -12,6 +12,7 @@ #include "SystemZSubtarget.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 +23,147 @@ SystemZRegisterInfo::SystemZRegisterInfo() : SystemZGenRegisterInfo(SystemZ::R14D) {} +// EXPERIMENTAL +static cl::opt LOCRHINTS("locr-hints", cl::Hidden, cl::init(true)); +static cl::opt HARDHINTS("hardhints", cl::Hidden, cl::init(false)); +static cl::opt UPDATEHINT("updatehint", cl::Hidden, cl::init(false)); +static cl::opt MOREMUX("moremux", cl::Hidden, cl::init(false)); + +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; + } + + return RC; +} + +static const TargetRegisterClass* +getConstrainedRC32(unsigned Reg, + const VirtRegMap *VRM, + const MachineRegisterInfo *MRI, + const TargetRegisterInfo *TRI) { + assert (MRI->getRegClass(Reg) == &SystemZ::GRX32BitRegClass); + for (auto &Use : MRI->use_instructions(Reg)) + if (Use.getOpcode() == SystemZ::LOCRMux) { + MachineOperand &TrueMO = Use.getOperand(1); + MachineOperand &FalseMO = Use.getOperand(2); + const TargetRegisterClass *RC = + TRI->getCommonSubClass(getRC32(FalseMO, VRM, MRI), + getRC32(TrueMO, VRM, MRI)); + if (RC && RC != &SystemZ::GRX32BitRegClass) + return RC; + } // LOCRMux + return nullptr; +} + +bool +SystemZRegisterInfo::getRegAllocationHints(unsigned VirtReg, + ArrayRef Order, + SmallVectorImpl &Hints, + const MachineFunction &MF, + const VirtRegMap *VRM, + const LiveRegMatrix *Matrix) const { + if (!LOCRHINTS) { + TargetRegisterInfo::getRegAllocationHints(VirtReg, Order, Hints, MF, VRM); + return false; + } + + const MachineRegisterInfo &MRI = MF.getRegInfo(); + const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); + if (MRI.getRegClass(VirtReg) == &SystemZ::GRX32BitRegClass) { + const TargetRegisterClass *RC = getConstrainedRC32(VirtReg, VRM, &MRI, TRI); + if (RC) { + // Add all regs in the allocation order of VirtReg that are part of + // RC32 as hints. + for (MCPhysReg Reg : Order) + if (RC->contains(Reg) && !MRI.isReserved(Reg)) + Hints.push_back(Reg); + return HARDHINTS; + } + + // (Nearly all cases handled by now) + + // VirtReg didn't have any instructions that constrained it. Look further + // on other regs of any mux-instructions of VirtReg. + if (MOREMUX) { + std::set MuxRegs; + for (auto &Use : MRI.use_instructions(VirtReg)) + if (Use.getOpcode() == SystemZ::LOCRMux) { + if (Use.getOperand(1).getReg() == VirtReg) + MuxRegs.insert(&Use.getOperand(2)); + else + MuxRegs.insert(&Use.getOperand(1)); + } + for (auto *MO : MuxRegs) { + const TargetRegisterClass *RC = + getConstrainedRC32(MO->getReg(), VRM, &MRI, TRI); + if (RC) { + // Add all regs in the allocation order of VirtReg that are part of + // RC32 as hints. + for (MCPhysReg Reg : Order) + if (RC->contains(Reg) && !MRI.isReserved(Reg)) + Hints.push_back(Reg); + return HARDHINTS; + } + } + } + + // (Currently all cases seems handled with MOREMUX, even though no real + // recursion is made.) + + } // GRX32 + + TargetRegisterInfo::getRegAllocationHints(VirtReg, Order, Hints, MF, VRM); + return false; +} + +void SystemZRegisterInfo::updateRegAllocHint(unsigned Reg, unsigned NewReg, + MachineFunction &MF) const { + if (!UPDATEHINT) + return; + + MachineRegisterInfo *MRI = &MF.getRegInfo(); + if (!TargetRegisterInfo::isVirtualRegister(Reg) || + !TargetRegisterInfo::isVirtualRegister(NewReg)) + return; + const TargetRegisterClass *OldRC = MRI->getRegClass(Reg); + const TargetRegisterClass *NewRC = MRI->getRegClass(NewReg); + if (! (OldRC == &SystemZ::GRX32BitRegClass && + SystemZ::GRX32BitRegClass.hasSubClass(NewRC))) { + assert (OldRC != &SystemZ::GRX32BitRegClass || + (NewRC != &SystemZ::GR32BitRegClass && NewRC != &SystemZ::GRH32BitRegClass && + NewRC != &SystemZ::ADDR32BitRegClass)); + return; + } + + // EXPERIMENTAL: We don't want to hint a single phys-reg, but we instead + // want to constrain another virtual registers reg-class if used with + // NewReg in a certain type of instructions. + for (auto &Use : MRI->use_instructions(NewReg)) + if (Use.getOpcode() == SystemZ::LOCRMux) { + unsigned OtherReg = (Use.getOperand(1).getReg() == NewReg ? + Use.getOperand(2).getReg() : Use.getOperand(1).getReg()); + if (MRI->getRegClass(OtherReg) == &SystemZ::GRX32BitRegClass) + MRI->setRegClass(OtherReg, NewRC); + } +} + const MCPhysReg * SystemZRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { if (MF->getSubtarget().getTargetLowering()->supportSwiftError() &&