mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-07 12:28:24 +00:00
Extract spill cost calculation to a new method, and use definePhysReg() to clear
out aliases when allocating. Clean up allocVirtReg(). Use calcSpillCost() to allow more aggressive hinting. Now the hint is always taken unless blocked by a reserved register. This leads to more coalescing, lower register pressure, and less spilling. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@103939 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -118,6 +118,11 @@ namespace {
|
|||||||
// not be erased.
|
// not be erased.
|
||||||
bool isBulkSpilling;
|
bool isBulkSpilling;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
spillClean = 1,
|
||||||
|
spillDirty = 100,
|
||||||
|
spillImpossible = ~0u
|
||||||
|
};
|
||||||
public:
|
public:
|
||||||
virtual const char *getPassName() const {
|
virtual const char *getPassName() const {
|
||||||
return "Fast Register Allocator";
|
return "Fast Register Allocator";
|
||||||
@@ -144,6 +149,7 @@ namespace {
|
|||||||
|
|
||||||
void usePhysReg(MachineOperand&);
|
void usePhysReg(MachineOperand&);
|
||||||
void definePhysReg(MachineInstr *MI, unsigned PhysReg, RegState NewState);
|
void definePhysReg(MachineInstr *MI, unsigned PhysReg, RegState NewState);
|
||||||
|
unsigned calcSpillCost(unsigned PhysReg) const;
|
||||||
void assignVirtToPhysReg(LiveRegEntry &LRE, unsigned PhysReg);
|
void assignVirtToPhysReg(LiveRegEntry &LRE, unsigned PhysReg);
|
||||||
void allocVirtReg(MachineInstr *MI, LiveRegEntry &LRE, unsigned Hint);
|
void allocVirtReg(MachineInstr *MI, LiveRegEntry &LRE, unsigned Hint);
|
||||||
LiveRegMap::iterator defineVirtReg(MachineInstr *MI, unsigned OpNum,
|
LiveRegMap::iterator defineVirtReg(MachineInstr *MI, unsigned OpNum,
|
||||||
@@ -369,6 +375,44 @@ void RAFast::definePhysReg(MachineInstr *MI, unsigned PhysReg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// calcSpillCost - Return the cost of spilling clearing out PhysReg and
|
||||||
|
// aliases so it is free for allocation.
|
||||||
|
// Returns 0 when PhysReg is free or disabled with all aliases disabled - it
|
||||||
|
// can be allocated directly.
|
||||||
|
// Returns spillImpossible when PhysReg or an alias can't be spilled.
|
||||||
|
unsigned RAFast::calcSpillCost(unsigned PhysReg) const {
|
||||||
|
switch (unsigned VirtReg = PhysRegState[PhysReg]) {
|
||||||
|
case regDisabled:
|
||||||
|
break;
|
||||||
|
case regFree:
|
||||||
|
return 0;
|
||||||
|
case regReserved:
|
||||||
|
return spillImpossible;
|
||||||
|
default:
|
||||||
|
return LiveVirtRegs.lookup(VirtReg).Dirty ? spillDirty : spillClean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a disabled register, add up const of aliases.
|
||||||
|
unsigned Cost = 0;
|
||||||
|
for (const unsigned *AS = TRI->getAliasSet(PhysReg);
|
||||||
|
unsigned Alias = *AS; ++AS) {
|
||||||
|
switch (unsigned VirtReg = PhysRegState[Alias]) {
|
||||||
|
case regDisabled:
|
||||||
|
break;
|
||||||
|
case regFree:
|
||||||
|
++Cost;
|
||||||
|
break;
|
||||||
|
case regReserved:
|
||||||
|
return spillImpossible;
|
||||||
|
default:
|
||||||
|
Cost += LiveVirtRegs.lookup(VirtReg).Dirty ? spillDirty : spillClean;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// assignVirtToPhysReg - This method updates local state so that we know
|
/// assignVirtToPhysReg - This method updates local state so that we know
|
||||||
/// that PhysReg is the proper container for VirtReg now. The physical
|
/// that PhysReg is the proper container for VirtReg now. The physical
|
||||||
/// register must not be used for anything else when this is called.
|
/// register must not be used for anything else when this is called.
|
||||||
@@ -383,15 +427,12 @@ void RAFast::assignVirtToPhysReg(LiveRegEntry &LRE, unsigned PhysReg) {
|
|||||||
|
|
||||||
/// allocVirtReg - Allocate a physical register for VirtReg.
|
/// allocVirtReg - Allocate a physical register for VirtReg.
|
||||||
void RAFast::allocVirtReg(MachineInstr *MI, LiveRegEntry &LRE, unsigned Hint) {
|
void RAFast::allocVirtReg(MachineInstr *MI, LiveRegEntry &LRE, unsigned Hint) {
|
||||||
const unsigned SpillCost = 100;
|
|
||||||
const unsigned VirtReg = LRE.first;
|
const unsigned VirtReg = LRE.first;
|
||||||
|
|
||||||
assert(TargetRegisterInfo::isVirtualRegister(VirtReg) &&
|
assert(TargetRegisterInfo::isVirtualRegister(VirtReg) &&
|
||||||
"Can only allocate virtual registers");
|
"Can only allocate virtual registers");
|
||||||
|
|
||||||
const TargetRegisterClass *RC = MRI->getRegClass(VirtReg);
|
const TargetRegisterClass *RC = MRI->getRegClass(VirtReg);
|
||||||
TargetRegisterClass::iterator AOB = RC->allocation_order_begin(*MF);
|
|
||||||
TargetRegisterClass::iterator AOE = RC->allocation_order_end(*MF);
|
|
||||||
|
|
||||||
// Ignore invalid hints.
|
// Ignore invalid hints.
|
||||||
if (Hint && (!TargetRegisterInfo::isPhysicalRegister(Hint) ||
|
if (Hint && (!TargetRegisterInfo::isPhysicalRegister(Hint) ||
|
||||||
@@ -403,107 +444,44 @@ void RAFast::allocVirtReg(MachineInstr *MI, LiveRegEntry &LRE, unsigned Hint) {
|
|||||||
if (Hint) {
|
if (Hint) {
|
||||||
assert(RC->contains(Hint) && !UsedInInstr.test(Hint) &&
|
assert(RC->contains(Hint) && !UsedInInstr.test(Hint) &&
|
||||||
Allocatable.test(Hint) && "Invalid hint should have been cleared");
|
Allocatable.test(Hint) && "Invalid hint should have been cleared");
|
||||||
switch(PhysRegState[Hint]) {
|
switch(calcSpillCost(Hint)) {
|
||||||
case regDisabled:
|
|
||||||
case regReserved:
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
spillVirtReg(MI, PhysRegState[Hint]);
|
definePhysReg(MI, Hint, regFree);
|
||||||
// Fall through.
|
// Fall through.
|
||||||
case regFree:
|
case 0:
|
||||||
return assignVirtToPhysReg(LRE, Hint);
|
return assignVirtToPhysReg(LRE, Hint);
|
||||||
|
case spillImpossible:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TargetRegisterClass::iterator AOB = RC->allocation_order_begin(*MF);
|
||||||
|
TargetRegisterClass::iterator AOE = RC->allocation_order_end(*MF);
|
||||||
|
|
||||||
// First try to find a completely free register.
|
// First try to find a completely free register.
|
||||||
unsigned BestCost = 0, BestReg = 0;
|
|
||||||
bool hasDisabled = false;
|
|
||||||
for (TargetRegisterClass::iterator I = AOB; I != AOE; ++I) {
|
for (TargetRegisterClass::iterator I = AOB; I != AOE; ++I) {
|
||||||
unsigned PhysReg = *I;
|
unsigned PhysReg = *I;
|
||||||
switch(PhysRegState[PhysReg]) {
|
if (PhysRegState[PhysReg] == regFree && !UsedInInstr.test(PhysReg))
|
||||||
case regDisabled:
|
return assignVirtToPhysReg(LRE, PhysReg);
|
||||||
hasDisabled = true;
|
|
||||||
case regReserved:
|
|
||||||
continue;
|
|
||||||
case regFree:
|
|
||||||
if (!UsedInInstr.test(PhysReg))
|
|
||||||
return assignVirtToPhysReg(LRE, PhysReg);
|
|
||||||
continue;
|
|
||||||
default:
|
|
||||||
// Grab the first spillable register we meet.
|
|
||||||
if (!BestReg && !UsedInInstr.test(PhysReg))
|
|
||||||
BestReg = PhysReg, BestCost = SpillCost;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG(dbgs() << "Allocating %reg" << VirtReg << " from " << RC->getName()
|
DEBUG(dbgs() << "Allocating %reg" << VirtReg << " from " << RC->getName()
|
||||||
<< " candidate=" << TRI->getName(BestReg) << "\n");
|
<< "\n");
|
||||||
|
|
||||||
// Try to extend the working set for RC if there were any disabled registers.
|
unsigned BestReg = 0, BestCost = spillImpossible;
|
||||||
if (hasDisabled && (!BestReg || BestCost >= SpillCost)) {
|
for (TargetRegisterClass::iterator I = AOB; I != AOE; ++I) {
|
||||||
for (TargetRegisterClass::iterator I = AOB; I != AOE; ++I) {
|
unsigned Cost = calcSpillCost(*I);
|
||||||
unsigned PhysReg = *I;
|
if (Cost < BestCost) {
|
||||||
if (PhysRegState[PhysReg] != regDisabled || UsedInInstr.test(PhysReg))
|
BestReg = *I;
|
||||||
continue;
|
BestCost = Cost;
|
||||||
|
if (Cost == 0) break;
|
||||||
// Calculate the cost of bringing PhysReg into the working set.
|
|
||||||
unsigned Cost=0;
|
|
||||||
bool Impossible = false;
|
|
||||||
for (const unsigned *AS = TRI->getAliasSet(PhysReg);
|
|
||||||
unsigned Alias = *AS; ++AS) {
|
|
||||||
if (UsedInInstr.test(Alias)) {
|
|
||||||
Impossible = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
switch (PhysRegState[Alias]) {
|
|
||||||
case regDisabled:
|
|
||||||
break;
|
|
||||||
case regReserved:
|
|
||||||
Impossible = true;
|
|
||||||
break;
|
|
||||||
case regFree:
|
|
||||||
Cost++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Cost += SpillCost;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Impossible) continue;
|
|
||||||
DEBUG(dbgs() << "- candidate " << TRI->getName(PhysReg)
|
|
||||||
<< " cost=" << Cost << "\n");
|
|
||||||
if (!BestReg || Cost < BestCost) {
|
|
||||||
BestReg = PhysReg;
|
|
||||||
BestCost = Cost;
|
|
||||||
if (Cost < SpillCost) break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BestReg) {
|
if (BestReg) {
|
||||||
// BestCost is 0 when all aliases are already disabled.
|
// BestCost is 0 when all aliases are already disabled.
|
||||||
if (BestCost) {
|
if (BestCost)
|
||||||
if (PhysRegState[BestReg] != regDisabled)
|
definePhysReg(MI, BestReg, regFree);
|
||||||
spillVirtReg(MI, PhysRegState[BestReg]);
|
|
||||||
else {
|
|
||||||
// Make sure all aliases are disabled.
|
|
||||||
for (const unsigned *AS = TRI->getAliasSet(BestReg);
|
|
||||||
unsigned Alias = *AS; ++AS) {
|
|
||||||
switch (PhysRegState[Alias]) {
|
|
||||||
case regDisabled:
|
|
||||||
continue;
|
|
||||||
case regFree:
|
|
||||||
PhysRegState[Alias] = regDisabled;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
spillVirtReg(MI, PhysRegState[Alias]);
|
|
||||||
PhysRegState[Alias] = regDisabled;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return assignVirtToPhysReg(LRE, BestReg);
|
return assignVirtToPhysReg(LRE, BestReg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user