summaryrefslogtreecommitdiff
path: root/lib/CodeGen/RegAllocGreedy.cpp
diff options
context:
space:
mode:
authorJakob Stoklund Olesen <stoklund@2pi.dk>2011-05-25 23:58:36 +0000
committerJakob Stoklund Olesen <stoklund@2pi.dk>2011-05-25 23:58:36 +0000
commitb8d936bc179ddf31b6350015d74900b74db6b450 (patch)
tree15cad4f40c5cb7b4785b4dcfd0ad79e5db1655ff /lib/CodeGen/RegAllocGreedy.cpp
parent76927d7303046058c627691bd45d6bff608f49f4 (diff)
downloadllvm-b8d936bc179ddf31b6350015d74900b74db6b450.tar.gz
llvm-b8d936bc179ddf31b6350015d74900b74db6b450.tar.bz2
llvm-b8d936bc179ddf31b6350015d74900b74db6b450.tar.xz
Add a RAGreedy::canEvict function.
This doesn't change functionality (much), but it allows for a more fine-grained eviction policy. The current policy only compares spill weights, and that is not always the best thing to do. Spill weights are designed to serve linear scan, and they don't consider live range splitting. Add a mechanism so canEvict() can request that a live range be evicted and split/spilled. This is to avoid infinite eviction loops. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@132101 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/RegAllocGreedy.cpp')
-rw-r--r--lib/CodeGen/RegAllocGreedy.cpp66
1 files changed, 62 insertions, 4 deletions
diff --git a/lib/CodeGen/RegAllocGreedy.cpp b/lib/CodeGen/RegAllocGreedy.cpp
index 87e08ba199..af77b476c8 100644
--- a/lib/CodeGen/RegAllocGreedy.cpp
+++ b/lib/CodeGen/RegAllocGreedy.cpp
@@ -100,6 +100,8 @@ class RAGreedy : public MachineFunctionPass,
RS_Spill ///< Produced by spilling.
};
+ static const char *const StageName[];
+
IndexedMap<unsigned char, VirtReg2IndexFunctor> LRStage;
LiveRangeStage getStage(const LiveInterval &VirtReg) const {
@@ -116,6 +118,15 @@ class RAGreedy : public MachineFunctionPass,
}
}
+ // Eviction. Sometimes an assigned live range can be evicted without
+ // conditions, but other times it must be split after being evicted to avoid
+ // infinite loops.
+ enum CanEvict {
+ CE_Never, ///< Can never evict.
+ CE_Always, ///< Can always evict.
+ CE_WithSplit ///< Can evict only if range is also split or spilled.
+ };
+
// splitting state.
std::auto_ptr<SplitAnalysis> SA;
std::auto_ptr<SplitEditor> SE;
@@ -187,6 +198,7 @@ private:
SlotIndex getPrevMappedIndex(const MachineInstr*);
void calcPrevSlots();
unsigned nextSplitPoint(unsigned);
+ CanEvict canEvict(LiveInterval &A, LiveInterval &B);
bool canEvictInterference(LiveInterval&, unsigned, float&);
unsigned tryAssign(LiveInterval&, AllocationOrder&,
@@ -204,6 +216,17 @@ private:
char RAGreedy::ID = 0;
+#ifndef NDEBUG
+const char *const RAGreedy::StageName[] = {
+ "RS_New",
+ "RS_First",
+ "RS_Second",
+ "RS_Global",
+ "RS_Local",
+ "RS_Spill"
+};
+#endif
+
// Hysteresis to use when comparing floats.
// This helps stabilize decisions based on float comparisons.
const float Hysteresis = 0.98f;
@@ -378,6 +401,20 @@ unsigned RAGreedy::tryAssign(LiveInterval &VirtReg,
// Interference eviction
//===----------------------------------------------------------------------===//
+/// canEvict - determine if A can evict the assigned live range B. The eviction
+/// policy defined by this function together with the allocation order defined
+/// by enqueue() decides which registers ultimately end up being split and
+/// spilled.
+///
+/// This function must define a non-circular relation when it returns CE_Always,
+/// otherwise infinite eviction loops are possible. When evicting a <= RS_Second
+/// range, it is possible to return CE_WithSplit which forces the evicted
+/// register to be split or spilled before it can evict anything again. That
+/// guarantees progress.
+RAGreedy::CanEvict RAGreedy::canEvict(LiveInterval &A, LiveInterval &B) {
+ return A.weight > B.weight ? CE_Always : CE_Never;
+}
+
/// canEvict - Return true if all interferences between VirtReg and PhysReg can
/// be evicted.
/// Return false if any interference is heavier than MaxWeight.
@@ -398,6 +435,16 @@ bool RAGreedy::canEvictInterference(LiveInterval &VirtReg, unsigned PhysReg,
return false;
if (Intf->weight >= MaxWeight)
return false;
+ switch (canEvict(VirtReg, *Intf)) {
+ case CE_Always:
+ break;
+ case CE_Never:
+ return false;
+ case CE_WithSplit:
+ if (getStage(*Intf) > RS_Second)
+ return false;
+ break;
+ }
Weight = std::max(Weight, Intf->weight);
}
}
@@ -416,7 +463,7 @@ unsigned RAGreedy::tryEvict(LiveInterval &VirtReg,
NamedRegionTimer T("Evict", TimerGroupName, TimePassesIsEnabled);
// Keep track of the lightest single interference seen so far.
- float BestWeight = VirtReg.weight;
+ float BestWeight = HUGE_VALF;
unsigned BestPhys = 0;
Order.rewind();
@@ -457,6 +504,11 @@ unsigned RAGreedy::tryEvict(LiveInterval &VirtReg,
unassign(*Intf, VRM->getPhys(Intf->reg));
++NumEvicted;
NewVRegs.push_back(Intf);
+ // Prevent looping by forcing the evicted ranges to be split before they
+ // can evict anything else.
+ if (getStage(*Intf) < RS_Second &&
+ canEvict(VirtReg, *Intf) == CE_WithSplit)
+ LRStage[Intf->reg] = RS_Second;
}
}
return BestPhys;
@@ -1362,15 +1414,21 @@ unsigned RAGreedy::selectOrSplit(LiveInterval &VirtReg,
if (unsigned PhysReg = tryAssign(VirtReg, Order, NewVRegs))
return PhysReg;
- if (unsigned PhysReg = tryEvict(VirtReg, Order, NewVRegs))
- return PhysReg;
+ LiveRangeStage Stage = getStage(VirtReg);
+ DEBUG(dbgs() << StageName[Stage] << '\n');
+
+ // Try to evict a less worthy live range, but only for ranges from the primary
+ // queue. The RS_Second ranges already failed to do this, and they should not
+ // get a second chance until they have been split.
+ if (Stage != RS_Second)
+ if (unsigned PhysReg = tryEvict(VirtReg, Order, NewVRegs))
+ return PhysReg;
assert(NewVRegs.empty() && "Cannot append to existing NewVRegs");
// The first time we see a live range, don't try to split or spill.
// Wait until the second time, when all smaller ranges have been allocated.
// This gives a better picture of the interference to split around.
- LiveRangeStage Stage = getStage(VirtReg);
if (Stage == RS_First) {
LRStage[VirtReg.reg] = RS_Second;
DEBUG(dbgs() << "wait for second round\n");