mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-21 02:59:15 +00:00
Prefer cheap registers for busy live ranges.
On the x86-64 and thumb2 targets, some registers are more expensive to encode than others in the same register class. Add a CostPerUse field to the TableGen register description, and make it available from TRI->getCostPerUse. This represents the cost of a REX prefix or a 32-bit instruction encoding required by choosing a high register. Teach the greedy register allocator to prefer cheap registers for busy live ranges (as indicated by spill weight). llvm-svn: 129864
This commit is contained in:
parent
1905cf10e3
commit
6501ea2557
@ -78,6 +78,13 @@ class Register<string n> {
|
||||
// -1 indicates that the gcc number is undefined and -2 that register number
|
||||
// is invalid for this mode/flavour.
|
||||
list<int> DwarfNumbers = [];
|
||||
|
||||
// CostPerUse - Additional cost of instructions using this register compared
|
||||
// to other registers in its class. The register allocator will try to
|
||||
// minimize the number of instructions using a register with a CostPerUse.
|
||||
// This is used by the x86-64 and ARM Thumb targets where some registers
|
||||
// require larger instruction encodings.
|
||||
int CostPerUse = 0;
|
||||
}
|
||||
|
||||
// RegisterWithSubRegs - This can be used to define instances of Register which
|
||||
|
@ -46,6 +46,7 @@ struct TargetRegisterDesc {
|
||||
const unsigned *Overlaps; // Overlapping registers, described above
|
||||
const unsigned *SubRegs; // Sub-register set, described above
|
||||
const unsigned *SuperRegs; // Super-register set, described above
|
||||
unsigned CostPerUse; // Extra cost of instructions using register.
|
||||
};
|
||||
|
||||
class TargetRegisterClass {
|
||||
@ -426,6 +427,12 @@ public:
|
||||
return get(RegNo).Name;
|
||||
}
|
||||
|
||||
/// getCostPerUse - Return the additional cost of using this register instead
|
||||
/// of other registers in its class.
|
||||
unsigned getCostPerUse(unsigned RegNo) const {
|
||||
return get(RegNo).CostPerUse;
|
||||
}
|
||||
|
||||
/// getNumRegs - Return the number of registers this target has (useful for
|
||||
/// sizing arrays holding per register information)
|
||||
unsigned getNumRegs() const {
|
||||
|
@ -278,6 +278,7 @@ void RegAllocBase::assign(LiveInterval &VirtReg, unsigned PhysReg) {
|
||||
<< " to " << PrintReg(PhysReg, TRI) << '\n');
|
||||
assert(!VRM->hasPhys(VirtReg.reg) && "Duplicate VirtReg assignment");
|
||||
VRM->assignVirt2Phys(VirtReg.reg, PhysReg);
|
||||
MRI->setPhysRegUsed(PhysReg);
|
||||
PhysReg2LiveUnion[PhysReg].unify(VirtReg);
|
||||
++NumAssigned;
|
||||
}
|
||||
|
@ -187,8 +187,10 @@ private:
|
||||
unsigned nextSplitPoint(unsigned);
|
||||
bool canEvictInterference(LiveInterval&, unsigned, float&);
|
||||
|
||||
unsigned tryAssign(LiveInterval&, AllocationOrder&,
|
||||
SmallVectorImpl<LiveInterval*>&);
|
||||
unsigned tryEvict(LiveInterval&, AllocationOrder&,
|
||||
SmallVectorImpl<LiveInterval*>&);
|
||||
SmallVectorImpl<LiveInterval*>&, unsigned = ~0u);
|
||||
unsigned tryRegionSplit(LiveInterval&, AllocationOrder&,
|
||||
SmallVectorImpl<LiveInterval*>&);
|
||||
unsigned tryLocalSplit(LiveInterval&, AllocationOrder&,
|
||||
@ -334,6 +336,37 @@ LiveInterval *RAGreedy::dequeue() {
|
||||
return LI;
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Direct Assignment
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// tryAssign - Try to assign VirtReg to an available register.
|
||||
unsigned RAGreedy::tryAssign(LiveInterval &VirtReg,
|
||||
AllocationOrder &Order,
|
||||
SmallVectorImpl<LiveInterval*> &NewVRegs) {
|
||||
Order.rewind();
|
||||
unsigned PhysReg;
|
||||
while ((PhysReg = Order.next()))
|
||||
if (!checkPhysRegInterference(VirtReg, PhysReg))
|
||||
break;
|
||||
if (!PhysReg || Order.isHint(PhysReg))
|
||||
return PhysReg;
|
||||
|
||||
// PhysReg is available. Try to evict interference from a cheaper alternative.
|
||||
unsigned Cost = TRI->getCostPerUse(PhysReg);
|
||||
|
||||
// Most registers have 0 additional cost.
|
||||
if (!Cost)
|
||||
return PhysReg;
|
||||
|
||||
DEBUG(dbgs() << PrintReg(PhysReg, TRI) << " is available at cost " << Cost
|
||||
<< '\n');
|
||||
unsigned CheapReg = tryEvict(VirtReg, Order, NewVRegs, Cost);
|
||||
return CheapReg ? CheapReg : PhysReg;
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Interference eviction
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -371,7 +404,8 @@ bool RAGreedy::canEvictInterference(LiveInterval &VirtReg, unsigned PhysReg,
|
||||
/// @return Physreg to assign VirtReg, or 0.
|
||||
unsigned RAGreedy::tryEvict(LiveInterval &VirtReg,
|
||||
AllocationOrder &Order,
|
||||
SmallVectorImpl<LiveInterval*> &NewVRegs){
|
||||
SmallVectorImpl<LiveInterval*> &NewVRegs,
|
||||
unsigned CostPerUseLimit) {
|
||||
NamedRegionTimer T("Evict", TimerGroupName, TimePassesIsEnabled);
|
||||
|
||||
// Keep track of the lightest single interference seen so far.
|
||||
@ -380,6 +414,12 @@ unsigned RAGreedy::tryEvict(LiveInterval &VirtReg,
|
||||
|
||||
Order.rewind();
|
||||
while (unsigned PhysReg = Order.next()) {
|
||||
if (TRI->getCostPerUse(PhysReg) >= CostPerUseLimit)
|
||||
continue;
|
||||
// The first use of a register in a function has cost 1.
|
||||
if (CostPerUseLimit == 1 && !MRI->isPhysRegUsed(PhysReg))
|
||||
continue;
|
||||
|
||||
float Weight = BestWeight;
|
||||
if (!canEvictInterference(VirtReg, PhysReg, Weight))
|
||||
continue;
|
||||
@ -1230,10 +1270,8 @@ unsigned RAGreedy::selectOrSplit(LiveInterval &VirtReg,
|
||||
SmallVectorImpl<LiveInterval*> &NewVRegs) {
|
||||
// First try assigning a free register.
|
||||
AllocationOrder Order(VirtReg.reg, *VRM, ReservedRegs);
|
||||
while (unsigned PhysReg = Order.next()) {
|
||||
if (!checkPhysRegInterference(VirtReg, PhysReg))
|
||||
return PhysReg;
|
||||
}
|
||||
if (unsigned PhysReg = tryAssign(VirtReg, Order, NewVRegs))
|
||||
return PhysReg;
|
||||
|
||||
if (unsigned PhysReg = tryEvict(VirtReg, Order, NewVRegs))
|
||||
return PhysReg;
|
||||
|
@ -70,6 +70,8 @@ def R4 : ARMReg< 4, "r4">, DwarfRegNum<[4]>;
|
||||
def R5 : ARMReg< 5, "r5">, DwarfRegNum<[5]>;
|
||||
def R6 : ARMReg< 6, "r6">, DwarfRegNum<[6]>;
|
||||
def R7 : ARMReg< 7, "r7">, DwarfRegNum<[7]>;
|
||||
// These require 32-bit instructions.
|
||||
let CostPerUse = 1 in {
|
||||
def R8 : ARMReg< 8, "r8">, DwarfRegNum<[8]>;
|
||||
def R9 : ARMReg< 9, "r9">, DwarfRegNum<[9]>;
|
||||
def R10 : ARMReg<10, "r10">, DwarfRegNum<[10]>;
|
||||
@ -78,6 +80,7 @@ def R12 : ARMReg<12, "r12">, DwarfRegNum<[12]>;
|
||||
def SP : ARMReg<13, "sp">, DwarfRegNum<[13]>;
|
||||
def LR : ARMReg<14, "lr">, DwarfRegNum<[14]>;
|
||||
def PC : ARMReg<15, "pc">, DwarfRegNum<[15]>;
|
||||
}
|
||||
|
||||
// Float registers
|
||||
def S0 : ARMFReg< 0, "s0">; def S1 : ARMFReg< 1, "s1">;
|
||||
|
@ -46,7 +46,8 @@ let Namespace = "X86" in {
|
||||
def CL : Register<"cl">, DwarfRegNum<[2, 1, 1]>;
|
||||
def BL : Register<"bl">, DwarfRegNum<[3, 3, 3]>;
|
||||
|
||||
// X86-64 only
|
||||
// X86-64 only, requires REX.
|
||||
let CostPerUse = 1 in {
|
||||
def SIL : Register<"sil">, DwarfRegNum<[4, 6, 6]>;
|
||||
def DIL : Register<"dil">, DwarfRegNum<[5, 7, 7]>;
|
||||
def BPL : Register<"bpl">, DwarfRegNum<[6, 4, 5]>;
|
||||
@ -59,6 +60,7 @@ let Namespace = "X86" in {
|
||||
def R13B : Register<"r13b">, DwarfRegNum<[13, -2, -2]>;
|
||||
def R14B : Register<"r14b">, DwarfRegNum<[14, -2, -2]>;
|
||||
def R15B : Register<"r15b">, DwarfRegNum<[15, -2, -2]>;
|
||||
}
|
||||
|
||||
// High registers. On x86-64, these cannot be used in any instruction
|
||||
// with a REX prefix.
|
||||
@ -82,8 +84,8 @@ let Namespace = "X86" in {
|
||||
}
|
||||
def IP : Register<"ip">, DwarfRegNum<[16]>;
|
||||
|
||||
// X86-64 only
|
||||
let SubRegIndices = [sub_8bit] in {
|
||||
// X86-64 only, requires REX.
|
||||
let SubRegIndices = [sub_8bit], CostPerUse = 1 in {
|
||||
def R8W : RegisterWithSubRegs<"r8w", [R8B]>, DwarfRegNum<[8, -2, -2]>;
|
||||
def R9W : RegisterWithSubRegs<"r9w", [R9B]>, DwarfRegNum<[9, -2, -2]>;
|
||||
def R10W : RegisterWithSubRegs<"r10w", [R10B]>, DwarfRegNum<[10, -2, -2]>;
|
||||
@ -105,7 +107,8 @@ let Namespace = "X86" in {
|
||||
def ESP : RegisterWithSubRegs<"esp", [SP]>, DwarfRegNum<[7, 5, 4]>;
|
||||
def EIP : RegisterWithSubRegs<"eip", [IP]>, DwarfRegNum<[16, 8, 8]>;
|
||||
|
||||
// X86-64 only
|
||||
// X86-64 only, requires REX
|
||||
let CostPerUse = 1 in {
|
||||
def R8D : RegisterWithSubRegs<"r8d", [R8W]>, DwarfRegNum<[8, -2, -2]>;
|
||||
def R9D : RegisterWithSubRegs<"r9d", [R9W]>, DwarfRegNum<[9, -2, -2]>;
|
||||
def R10D : RegisterWithSubRegs<"r10d", [R10W]>, DwarfRegNum<[10, -2, -2]>;
|
||||
@ -114,7 +117,7 @@ let Namespace = "X86" in {
|
||||
def R13D : RegisterWithSubRegs<"r13d", [R13W]>, DwarfRegNum<[13, -2, -2]>;
|
||||
def R14D : RegisterWithSubRegs<"r14d", [R14W]>, DwarfRegNum<[14, -2, -2]>;
|
||||
def R15D : RegisterWithSubRegs<"r15d", [R15W]>, DwarfRegNum<[15, -2, -2]>;
|
||||
}
|
||||
}}
|
||||
|
||||
// 64-bit registers, X86-64 only
|
||||
let SubRegIndices = [sub_32bit] in {
|
||||
@ -127,6 +130,8 @@ let Namespace = "X86" in {
|
||||
def RBP : RegisterWithSubRegs<"rbp", [EBP]>, DwarfRegNum<[6, -2, -2]>;
|
||||
def RSP : RegisterWithSubRegs<"rsp", [ESP]>, DwarfRegNum<[7, -2, -2]>;
|
||||
|
||||
// These also require REX.
|
||||
let CostPerUse = 1 in {
|
||||
def R8 : RegisterWithSubRegs<"r8", [R8D]>, DwarfRegNum<[8, -2, -2]>;
|
||||
def R9 : RegisterWithSubRegs<"r9", [R9D]>, DwarfRegNum<[9, -2, -2]>;
|
||||
def R10 : RegisterWithSubRegs<"r10", [R10D]>, DwarfRegNum<[10, -2, -2]>;
|
||||
@ -136,7 +141,7 @@ let Namespace = "X86" in {
|
||||
def R14 : RegisterWithSubRegs<"r14", [R14D]>, DwarfRegNum<[14, -2, -2]>;
|
||||
def R15 : RegisterWithSubRegs<"r15", [R15D]>, DwarfRegNum<[15, -2, -2]>;
|
||||
def RIP : RegisterWithSubRegs<"rip", [EIP]>, DwarfRegNum<[16, -2, -2]>;
|
||||
}
|
||||
}}
|
||||
|
||||
// MMX Registers. These are actually aliased to ST0 .. ST7
|
||||
def MM0 : Register<"mm0">, DwarfRegNum<[41, 29, 29]>;
|
||||
@ -170,6 +175,7 @@ let Namespace = "X86" in {
|
||||
def XMM7: Register<"xmm7">, DwarfRegNum<[24, 28, 28]>;
|
||||
|
||||
// X86-64 only
|
||||
let CostPerUse = 1 in {
|
||||
def XMM8: Register<"xmm8">, DwarfRegNum<[25, -2, -2]>;
|
||||
def XMM9: Register<"xmm9">, DwarfRegNum<[26, -2, -2]>;
|
||||
def XMM10: Register<"xmm10">, DwarfRegNum<[27, -2, -2]>;
|
||||
@ -178,7 +184,7 @@ let Namespace = "X86" in {
|
||||
def XMM13: Register<"xmm13">, DwarfRegNum<[30, -2, -2]>;
|
||||
def XMM14: Register<"xmm14">, DwarfRegNum<[31, -2, -2]>;
|
||||
def XMM15: Register<"xmm15">, DwarfRegNum<[32, -2, -2]>;
|
||||
}
|
||||
}}
|
||||
|
||||
// YMM Registers, used by AVX instructions
|
||||
let SubRegIndices = [sub_xmm] in {
|
||||
|
@ -31,6 +31,7 @@ namespace llvm {
|
||||
const std::string &getName() const;
|
||||
unsigned DeclaredSpillSize, DeclaredSpillAlignment;
|
||||
unsigned EnumValue;
|
||||
unsigned CostPerUse;
|
||||
CodeGenRegister(Record *R);
|
||||
};
|
||||
|
||||
|
@ -172,6 +172,7 @@ void CodeGenTarget::ReadRegisters() const {
|
||||
CodeGenRegister::CodeGenRegister(Record *R) : TheDef(R) {
|
||||
DeclaredSpillSize = R->getValueAsInt("SpillSize");
|
||||
DeclaredSpillAlignment = R->getValueAsInt("SpillAlignment");
|
||||
CostPerUse = R->getValueAsInt("CostPerUse");
|
||||
}
|
||||
|
||||
const std::string &CodeGenRegister::getName() const {
|
||||
|
@ -841,7 +841,7 @@ void RegisterInfoEmitter::run(raw_ostream &OS) {
|
||||
}
|
||||
|
||||
OS<<"\n const TargetRegisterDesc RegisterDescriptors[] = { // Descriptors\n";
|
||||
OS << " { \"NOREG\",\t0,\t0,\t0 },\n";
|
||||
OS << " { \"NOREG\",\t0,\t0,\t0,\t0 },\n";
|
||||
|
||||
// Now that register alias and sub-registers sets have been emitted, emit the
|
||||
// register descriptors now.
|
||||
@ -854,9 +854,10 @@ void RegisterInfoEmitter::run(raw_ostream &OS) {
|
||||
else
|
||||
OS << "Empty_SubRegsSet,\t";
|
||||
if (!RegisterSuperRegs[Reg.TheDef].empty())
|
||||
OS << Reg.getName() << "_SuperRegsSet },\n";
|
||||
OS << Reg.getName() << "_SuperRegsSet,\t";
|
||||
else
|
||||
OS << "Empty_SuperRegsSet },\n";
|
||||
OS << "Empty_SuperRegsSet,\t";
|
||||
OS << Reg.CostPerUse << " },\n";
|
||||
}
|
||||
OS << " };\n"; // End of register descriptors...
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user