Index: include/llvm/Target/TargetRegisterInfo.h =================================================================== --- include/llvm/Target/TargetRegisterInfo.h +++ include/llvm/Target/TargetRegisterInfo.h @@ -778,7 +778,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 @@ -789,7 +790,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 @@ -360,7 +360,7 @@ } // Compute target-independent register allocator hints to help eliminate copies. -void +bool TargetRegisterInfo::getRegAllocationHints(unsigned VirtReg, ArrayRef Order, SmallVectorImpl &Hints, @@ -382,17 +382,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 @@ -145,7 +145,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 @@ -280,7 +280,7 @@ } // Resolve the RegPairEven / RegPairOdd register allocator hints. -void +bool ARMBaseRegisterInfo::getRegAllocationHints(unsigned VirtReg, ArrayRef Order, SmallVectorImpl &Hints, @@ -300,7 +300,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). @@ -308,7 +308,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)) { @@ -331,6 +331,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" @@ -45,6 +46,9 @@ #define GET_INSTRMAP_INFO #include "SystemZGenInstrInfo.inc" +#define DEBUG_TYPE "systemz-II" +STATISTIC(LOCRMuxJumps, "Number of LOCRMux 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; @@ -209,6 +213,8 @@ MI.setDesc(get(LowOpcode)); else if (DestIsHigh && SrcIsHigh) MI.setDesc(get(HighOpcode)); + else + LOCRMuxJumps++; // 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 @@ -44,6 +44,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 @@ -11,8 +11,10 @@ #include "SystemZInstrInfo.h" #include "SystemZSubtarget.h" #include "llvm/CodeGen/LiveIntervalAnalysis.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; @@ -23,6 +25,84 @@ SystemZRegisterInfo::SystemZRegisterInfo() : SystemZGenRegisterInfo(SystemZ::R14D) {} +// Given that MO is a GRX32 operand, return either GR32 or GRH32 if MO +// somehow belongs in it. Otherwise, return GRX32. +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; +} + +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) { + SmallVector Worklist; + SmallSet DoneRegs; + Worklist.push_back(VirtReg); + while (Worklist.size()) { + unsigned Reg = Worklist.pop_back_val(); + if (!DoneRegs.insert(Reg).second) + continue; + + for (auto &Use : MRI->use_instructions(Reg)) + // For LOCRMux, see if the other operand is already a high or low + // register, and in that case give the correpsonding hints for + // VirtReg. LOCR instructions need both operands in either high or + // low parts. + 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) { + for (MCPhysReg Reg : Order) + if (RC->contains(Reg) && !MRI->isReserved(Reg)) + Hints.push_back(Reg); + // Return true to make these hints the only regs available to + // RA. This may mean extra spilling but since the alternative is + // a jump sequence expansion of the LOCRMux, it is preferred. + return true; + } + + // Add the other operand of the LOCRMux to the worklist. + unsigned OtherReg = + (TrueMO.getReg() == Reg ? FalseMO.getReg() : TrueMO.getReg()); + if (MRI->getRegClass(OtherReg) == &SystemZ::GRX32BitRegClass) + Worklist.push_back(OtherReg); + } + } + } + + return TargetRegisterInfo::getRegAllocationHints(VirtReg, Order, Hints, MF, VRM); +} + const MCPhysReg * SystemZRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { if (MF->getSubtarget().getTargetLowering()->supportSwiftError() && Index: test/CodeGen/SystemZ/cond-move-04.mir =================================================================== --- /dev/null +++ test/CodeGen/SystemZ/cond-move-04.mir @@ -0,0 +1,75 @@ +# RUN: llc -mtriple=s390x-linux-gnu -mcpu=z13 -start-before=greedy %s -o - \ +# RUN: | FileCheck %s +# +# Test that regalloc manages (via regalloc hints) to avoid a LOCRMux jump +# sequence expansion. + +--- | + + declare i8* @foo(i8*, i32 signext, i32 signext) local_unnamed_addr + + define i8* @fun(i8* returned) { + br label %2 + + ;