mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-06-13 04:38:24 +00:00
Jakob's review of the basic register allocator.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@117384 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@ -21,6 +21,9 @@
|
|||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
// Merge a LiveInterval's segments. Guarantee no overlaps.
|
// Merge a LiveInterval's segments. Guarantee no overlaps.
|
||||||
|
//
|
||||||
|
// Consider coalescing adjacent segments to save space, even though it makes
|
||||||
|
// extraction more complicated.
|
||||||
void LiveIntervalUnion::unify(LiveInterval &lvr) {
|
void LiveIntervalUnion::unify(LiveInterval &lvr) {
|
||||||
// Add this live virtual register to the union
|
// Add this live virtual register to the union
|
||||||
LiveVirtRegs::iterator pos = std::upper_bound(lvrs_.begin(), lvrs_.end(),
|
LiveVirtRegs::iterator pos = std::upper_bound(lvrs_.begin(), lvrs_.end(),
|
||||||
@ -34,19 +37,21 @@ void LiveIntervalUnion::unify(LiveInterval &lvr) {
|
|||||||
LiveSegment segment(lvrI->start, lvrI->end, lvr);
|
LiveSegment segment(lvrI->start, lvrI->end, lvr);
|
||||||
segPos = segments_.insert(segPos, segment);
|
segPos = segments_.insert(segPos, segment);
|
||||||
assert(*segPos == segment && "need equal val for equal key");
|
assert(*segPos == segment && "need equal val for equal key");
|
||||||
|
#ifndef NDEBUG
|
||||||
|
// check for overlap (inductively)
|
||||||
|
if (segPos != segments_.begin()) {
|
||||||
|
SegmentIter prevPos = segPos;
|
||||||
|
--prevPos;
|
||||||
|
assert(prevPos->end <= segment.start && "overlapping segments" );
|
||||||
|
}
|
||||||
|
SegmentIter nextPos = segPos;
|
||||||
|
++nextPos;
|
||||||
|
if (nextPos != segments_.end())
|
||||||
|
assert(segment.end <= nextPos->start && "overlapping segments" );
|
||||||
|
#endif // NDEBUG
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
// Keep LVRs sorted for fast membership test and extraction.
|
|
||||||
struct LessReg
|
|
||||||
: public std::binary_function<LiveInterval*, LiveInterval*, bool> {
|
|
||||||
bool operator()(const LiveInterval *left, const LiveInterval *right) const {
|
|
||||||
return left->reg < right->reg;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Low-level helper to find the first segment in the range [segI,segEnd) that
|
// Low-level helper to find the first segment in the range [segI,segEnd) that
|
||||||
// intersects with a live virtual register segment, or segI.start >= lvr.end
|
// intersects with a live virtual register segment, or segI.start >= lvr.end
|
||||||
//
|
//
|
||||||
@ -67,10 +72,8 @@ struct LessReg
|
|||||||
// Assuming intervals are disjoint, if an intersection exists, it must be the
|
// Assuming intervals are disjoint, if an intersection exists, it must be the
|
||||||
// segment found or immediately behind it. We continue reverse iterating to
|
// segment found or immediately behind it. We continue reverse iterating to
|
||||||
// return the first overlap.
|
// return the first overlap.
|
||||||
//
|
|
||||||
// FIXME: support extract(), handle tombstones of extracted lvrs.
|
|
||||||
typedef LiveIntervalUnion::SegmentIter SegmentIter;
|
typedef LiveIntervalUnion::SegmentIter SegmentIter;
|
||||||
SegmentIter upperBound(SegmentIter segBegin,
|
static SegmentIter upperBound(SegmentIter segBegin,
|
||||||
SegmentIter segEnd,
|
SegmentIter segEnd,
|
||||||
const LiveRange &lvrSeg) {
|
const LiveRange &lvrSeg) {
|
||||||
assert(lvrSeg.end > segBegin->start && "segment iterator precondition");
|
assert(lvrSeg.end > segBegin->start && "segment iterator precondition");
|
||||||
@ -84,7 +87,6 @@ SegmentIter upperBound(SegmentIter segBegin,
|
|||||||
}
|
}
|
||||||
return segI;
|
return segI;
|
||||||
}
|
}
|
||||||
} // end anonymous namespace
|
|
||||||
|
|
||||||
// Private interface accessed by Query.
|
// Private interface accessed by Query.
|
||||||
//
|
//
|
||||||
|
@ -23,13 +23,16 @@
|
|||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
// A LiveSegment is a copy of a LiveRange object used within
|
/// A LiveSegment is a copy of a LiveRange object used within
|
||||||
// LiveIntervalUnion. LiveSegment additionally contains a pointer to its
|
/// LiveIntervalUnion. LiveSegment additionally contains a pointer to its
|
||||||
// original live virtual register (LiveInterval). This allows quick lookup of
|
/// original live virtual register (LiveInterval). This allows quick lookup of
|
||||||
// the live virtual register as we iterate over live segments in a union. Note
|
/// the live virtual register as we iterate over live segments in a union. Note
|
||||||
// that LiveRange is misnamed and actually represents only a single contiguous
|
/// that LiveRange is misnamed and actually represents only a single contiguous
|
||||||
// interval within a virtual register's liveness. To limit confusion, in this
|
/// interval within a virtual register's liveness. To limit confusion, in this
|
||||||
// file we refer it as a live segment.
|
/// file we refer it as a live segment.
|
||||||
|
///
|
||||||
|
/// Note: This currently represents a half-open interval [start,end).
|
||||||
|
/// If LiveRange is modified to represent a closed interval, so should this.
|
||||||
struct LiveSegment {
|
struct LiveSegment {
|
||||||
SlotIndex start;
|
SlotIndex start;
|
||||||
SlotIndex end;
|
SlotIndex end;
|
||||||
@ -46,16 +49,10 @@ struct LiveSegment {
|
|||||||
return !operator==(ls);
|
return !operator==(ls);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(const LiveSegment &ls) const {
|
// Order segments by starting point only--we expect them to be disjoint.
|
||||||
return start < ls.start || (start == ls.start && end < ls.end);
|
bool operator<(const LiveSegment &ls) const { return start < ls.start; }
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Compare a live virtual register segment to a LiveIntervalUnion segment.
|
|
||||||
inline bool overlap(const LiveRange &lvrSeg, const LiveSegment &liuSeg) {
|
|
||||||
return lvrSeg.start < liuSeg.end && liuSeg.start < lvrSeg.end;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator<(SlotIndex V, const LiveSegment &ls) {
|
inline bool operator<(SlotIndex V, const LiveSegment &ls) {
|
||||||
return V < ls.start;
|
return V < ls.start;
|
||||||
}
|
}
|
||||||
@ -64,6 +61,11 @@ inline bool operator<(const LiveSegment &ls, SlotIndex V) {
|
|||||||
return ls.start < V;
|
return ls.start < V;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compare a live virtual register segment to a LiveIntervalUnion segment.
|
||||||
|
inline bool overlap(const LiveRange &lvrSeg, const LiveSegment &liuSeg) {
|
||||||
|
return lvrSeg.start < liuSeg.end && liuSeg.start < lvrSeg.end;
|
||||||
|
}
|
||||||
|
|
||||||
/// Union of live intervals that are strong candidates for coalescing into a
|
/// Union of live intervals that are strong candidates for coalescing into a
|
||||||
/// single register (either physical or virtual depending on the context). We
|
/// single register (either physical or virtual depending on the context). We
|
||||||
/// expect the constituent live intervals to be disjoint, although we may
|
/// expect the constituent live intervals to be disjoint, although we may
|
||||||
@ -100,13 +102,18 @@ private:
|
|||||||
public:
|
public:
|
||||||
// default ctor avoids placement new
|
// default ctor avoids placement new
|
||||||
LiveIntervalUnion() : repReg_(0) {}
|
LiveIntervalUnion() : repReg_(0) {}
|
||||||
|
|
||||||
|
// Initialize the union by associating it with a representative register
|
||||||
|
// number.
|
||||||
void init(unsigned repReg) { repReg_ = repReg; }
|
void init(unsigned repReg) { repReg_ = repReg; }
|
||||||
|
|
||||||
|
// Iterate over all segments in the union of live virtual registers ordered
|
||||||
|
// by their starting position.
|
||||||
SegmentIter begin() { return segments_.begin(); }
|
SegmentIter begin() { return segments_.begin(); }
|
||||||
SegmentIter end() { return segments_.end(); }
|
SegmentIter end() { return segments_.end(); }
|
||||||
|
|
||||||
/// FIXME: !!!!!!!!!!! Keeps a non-const ref
|
// Add a live virtual register to this union and merge its segments.
|
||||||
|
// Holds a nonconst reference to the LVR for later maniplution.
|
||||||
void unify(LiveInterval &lvr);
|
void unify(LiveInterval &lvr);
|
||||||
|
|
||||||
// FIXME: needed by RegAllocGreedy
|
// FIXME: needed by RegAllocGreedy
|
||||||
|
@ -37,17 +37,29 @@
|
|||||||
#ifndef LLVM_CODEGEN_REGALLOCBASE
|
#ifndef LLVM_CODEGEN_REGALLOCBASE
|
||||||
#define LLVM_CODEGEN_REGALLOCBASE
|
#define LLVM_CODEGEN_REGALLOCBASE
|
||||||
|
|
||||||
#include "LiveIntervalUnion.h"
|
|
||||||
#include "VirtRegMap.h"
|
|
||||||
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
|
|
||||||
#include "llvm/Target/TargetRegisterInfo.h"
|
|
||||||
#include "llvm/ADT/OwningPtr.h"
|
#include "llvm/ADT/OwningPtr.h"
|
||||||
#include <vector>
|
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
|
template<typename T> class SmallVectorImpl;
|
||||||
|
class TargetRegisterInfo;
|
||||||
class VirtRegMap;
|
class VirtRegMap;
|
||||||
|
class LiveIntervals;
|
||||||
|
|
||||||
|
// Heuristic that determines the priority of assigning virtual to physical
|
||||||
|
// registers. The main impact of the heuristic is expected to be compile time.
|
||||||
|
// The default is to simply compare spill weights.
|
||||||
|
struct LessSpillWeightPriority
|
||||||
|
: public std::binary_function<LiveInterval,LiveInterval, bool> {
|
||||||
|
bool operator()(const LiveInterval *left, const LiveInterval *right) const {
|
||||||
|
return left->weight < right->weight;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Forward declare a priority queue of live virtual registers. If an
|
||||||
|
// implementation needs to prioritize by anything other than spill weight, then
|
||||||
|
// this will become an abstract base class with virtual calls to push/get.
|
||||||
|
class LiveVirtRegQueue;
|
||||||
|
|
||||||
/// RegAllocBase provides the register allocation driver and interface that can
|
/// RegAllocBase provides the register allocation driver and interface that can
|
||||||
/// be extended to add interesting heuristics.
|
/// be extended to add interesting heuristics.
|
||||||
@ -58,9 +70,6 @@ class VirtRegMap;
|
|||||||
/// standard comparator.
|
/// standard comparator.
|
||||||
class RegAllocBase {
|
class RegAllocBase {
|
||||||
protected:
|
protected:
|
||||||
typedef SmallVector<LiveInterval*, 4> LiveVirtRegs;
|
|
||||||
typedef LiveVirtRegs::iterator LVRIter;
|
|
||||||
|
|
||||||
// Array of LiveIntervalUnions indexed by physical register.
|
// Array of LiveIntervalUnions indexed by physical register.
|
||||||
class LIUArray {
|
class LIUArray {
|
||||||
unsigned nRegs_;
|
unsigned nRegs_;
|
||||||
@ -92,18 +101,20 @@ protected:
|
|||||||
// A RegAlloc pass should call this before allocatePhysRegs.
|
// A RegAlloc pass should call this before allocatePhysRegs.
|
||||||
void init(const TargetRegisterInfo &tri, VirtRegMap &vrm, LiveIntervals &lis);
|
void init(const TargetRegisterInfo &tri, VirtRegMap &vrm, LiveIntervals &lis);
|
||||||
|
|
||||||
// The top-level driver. Specialize with the comparator that determines the
|
// The top-level driver. The output is a VirtRegMap that us updated with
|
||||||
// priority of assigning live virtual registers. The output is a VirtRegMap
|
// physical register assignments.
|
||||||
// that us updated with physical register assignments.
|
//
|
||||||
template<typename LICompare>
|
// If an implementation wants to override the LiveInterval comparator, we
|
||||||
void allocatePhysRegs(LICompare liCompare);
|
// should modify this interface to allow passing in an instance derived from
|
||||||
|
// LiveVirtRegQueue.
|
||||||
|
void allocatePhysRegs();
|
||||||
|
|
||||||
// A RegAlloc pass should override this to provide the allocation heuristics.
|
// A RegAlloc pass should override this to provide the allocation heuristics.
|
||||||
// Each call must guarantee forward progess by returning an available
|
// Each call must guarantee forward progess by returning an available PhysReg
|
||||||
// PhysReg or new set of split LiveVirtRegs. It is up to the splitter to
|
// or new set of split live virtual registers. It is up to the splitter to
|
||||||
// converge quickly toward fully spilled live ranges.
|
// converge quickly toward fully spilled live ranges.
|
||||||
virtual unsigned selectOrSplit(LiveInterval &lvr,
|
virtual unsigned selectOrSplit(LiveInterval &lvr,
|
||||||
LiveVirtRegs &splitLVRs) = 0;
|
SmallVectorImpl<LiveInterval*> &splitLVRs) = 0;
|
||||||
|
|
||||||
// A RegAlloc pass should call this when PassManager releases its memory.
|
// A RegAlloc pass should call this when PassManager releases its memory.
|
||||||
virtual void releaseMemory();
|
virtual void releaseMemory();
|
||||||
@ -113,69 +124,9 @@ protected:
|
|||||||
bool checkPhysRegInterference(LiveIntervalUnion::Query &query, unsigned preg);
|
bool checkPhysRegInterference(LiveIntervalUnion::Query &query, unsigned preg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename PQ>
|
void seedLiveVirtRegs(LiveVirtRegQueue &lvrQ);
|
||||||
void seedLiveVirtRegs(PQ &lvrQ);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Heuristic that determines the priority of assigning virtual to physical
|
|
||||||
// registers. The main impact of the heuristic is expected to be compile time.
|
|
||||||
// The default is to simply compare spill weights.
|
|
||||||
struct LessSpillWeightPriority
|
|
||||||
: public std::binary_function<LiveInterval,LiveInterval, bool> {
|
|
||||||
bool operator()(const LiveInterval *left, const LiveInterval *right) const {
|
|
||||||
return left->weight < right->weight;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Visit all the live virtual registers. If they are already assigned to a
|
|
||||||
// physical register, unify them with the corresponding LiveIntervalUnion,
|
|
||||||
// otherwise push them on the priority queue for later assignment.
|
|
||||||
template<typename PQ>
|
|
||||||
void RegAllocBase::seedLiveVirtRegs(PQ &lvrQ) {
|
|
||||||
for (LiveIntervals::iterator liItr = lis_->begin(), liEnd = lis_->end();
|
|
||||||
liItr != liEnd; ++liItr) {
|
|
||||||
unsigned reg = liItr->first;
|
|
||||||
LiveInterval &li = *liItr->second;
|
|
||||||
if (TargetRegisterInfo::isPhysicalRegister(reg)) {
|
|
||||||
physReg2liu_[reg].unify(li);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
lvrQ.push(&li);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Top-level driver to manage the queue of unassigned LiveVirtRegs and call the
|
|
||||||
// selectOrSplit implementation.
|
|
||||||
template<typename LICompare>
|
|
||||||
void RegAllocBase::allocatePhysRegs(LICompare liCompare) {
|
|
||||||
typedef std::priority_queue
|
|
||||||
<LiveInterval*, std::vector<LiveInterval*>, LICompare> LiveVirtRegQueue;
|
|
||||||
|
|
||||||
LiveVirtRegQueue lvrQ(liCompare);
|
|
||||||
seedLiveVirtRegs(lvrQ);
|
|
||||||
while (!lvrQ.empty()) {
|
|
||||||
LiveInterval *lvr = lvrQ.top();
|
|
||||||
lvrQ.pop();
|
|
||||||
LiveVirtRegs splitLVRs;
|
|
||||||
unsigned availablePhysReg = selectOrSplit(*lvr, splitLVRs);
|
|
||||||
if (availablePhysReg) {
|
|
||||||
assert(splitLVRs.empty() && "inconsistent splitting");
|
|
||||||
assert(!vrm_->hasPhys(lvr->reg) && "duplicate vreg in interval unions");
|
|
||||||
vrm_->assignVirt2Phys(lvr->reg, availablePhysReg);
|
|
||||||
physReg2liu_[availablePhysReg].unify(*lvr);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (LVRIter lvrI = splitLVRs.begin(), lvrEnd = splitLVRs.end();
|
|
||||||
lvrI != lvrEnd; ++lvrI ) {
|
|
||||||
assert(TargetRegisterInfo::isVirtualRegister((*lvrI)->reg) &&
|
|
||||||
"expect split value in virtual register");
|
|
||||||
lvrQ.push(*lvrI);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
|
||||||
#endif // !defined(LLVM_CODEGEN_REGALLOCBASE)
|
#endif // !defined(LLVM_CODEGEN_REGALLOCBASE)
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#define DEBUG_TYPE "regalloc"
|
#define DEBUG_TYPE "regalloc"
|
||||||
|
#include "LiveIntervalUnion.h"
|
||||||
#include "RegAllocBase.h"
|
#include "RegAllocBase.h"
|
||||||
#include "RenderMachineFunction.h"
|
#include "RenderMachineFunction.h"
|
||||||
#include "Spiller.h"
|
#include "Spiller.h"
|
||||||
@ -33,6 +34,14 @@
|
|||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
|
||||||
|
#include "VirtRegMap.h"
|
||||||
|
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
|
||||||
|
#include "llvm/Target/TargetRegisterInfo.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
static RegisterRegAlloc basicRegAlloc("basic", "basic register allocator",
|
static RegisterRegAlloc basicRegAlloc("basic", "basic register allocator",
|
||||||
@ -72,7 +81,8 @@ public:
|
|||||||
|
|
||||||
virtual void releaseMemory();
|
virtual void releaseMemory();
|
||||||
|
|
||||||
virtual unsigned selectOrSplit(LiveInterval &lvr, LiveVirtRegs &splitLVRs);
|
virtual unsigned selectOrSplit(LiveInterval &lvr,
|
||||||
|
SmallVectorImpl<LiveInterval*> &splitLVRs);
|
||||||
|
|
||||||
/// Perform register allocation.
|
/// Perform register allocation.
|
||||||
virtual bool runOnMachineFunction(MachineFunction &mf);
|
virtual bool runOnMachineFunction(MachineFunction &mf);
|
||||||
@ -101,7 +111,7 @@ INITIALIZE_PASS_DEPENDENCY(RenderMachineFunction)
|
|||||||
#endif
|
#endif
|
||||||
INITIALIZE_PASS_END(RABasic, "basic-regalloc",
|
INITIALIZE_PASS_END(RABasic, "basic-regalloc",
|
||||||
"Basic Register Allocator", false, false)
|
"Basic Register Allocator", false, false)
|
||||||
#endif // INITIALIZE_PASS
|
#endif // disable INITIALIZE_PASS
|
||||||
|
|
||||||
RABasic::RABasic(): MachineFunctionPass(ID) {
|
RABasic::RABasic(): MachineFunctionPass(ID) {
|
||||||
initializeLiveIntervalsPass(*PassRegistry::getPassRegistry());
|
initializeLiveIntervalsPass(*PassRegistry::getPassRegistry());
|
||||||
@ -168,6 +178,79 @@ void RegAllocBase::releaseMemory() {
|
|||||||
physReg2liu_.clear();
|
physReg2liu_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
/// This class defines a queue of live virtual registers prioritized by spill
|
||||||
|
/// weight. The heaviest vreg is popped first.
|
||||||
|
///
|
||||||
|
/// Currently, this is trivial wrapper that gives us an opaque type in the
|
||||||
|
/// header, but we may later give it a virtual interface for register allocators
|
||||||
|
/// to override the priority queue comparator.
|
||||||
|
class LiveVirtRegQueue {
|
||||||
|
typedef std::priority_queue
|
||||||
|
<LiveInterval*, std::vector<LiveInterval*>, LessSpillWeightPriority> PQ;
|
||||||
|
PQ pq_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Is the queue empty?
|
||||||
|
bool empty() { return pq_.empty(); }
|
||||||
|
|
||||||
|
// Get the highest priority lvr (top + pop)
|
||||||
|
LiveInterval *get() {
|
||||||
|
LiveInterval *lvr = pq_.top();
|
||||||
|
pq_.pop();
|
||||||
|
return lvr;
|
||||||
|
}
|
||||||
|
// Add this lvr to the queue
|
||||||
|
void push(LiveInterval *lvr) {
|
||||||
|
pq_.push(lvr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // end namespace llvm
|
||||||
|
|
||||||
|
// Visit all the live virtual registers. If they are already assigned to a
|
||||||
|
// physical register, unify them with the corresponding LiveIntervalUnion,
|
||||||
|
// otherwise push them on the priority queue for later assignment.
|
||||||
|
void RegAllocBase::seedLiveVirtRegs(LiveVirtRegQueue &lvrQ) {
|
||||||
|
for (LiveIntervals::iterator liItr = lis_->begin(), liEnd = lis_->end();
|
||||||
|
liItr != liEnd; ++liItr) {
|
||||||
|
unsigned reg = liItr->first;
|
||||||
|
LiveInterval &li = *liItr->second;
|
||||||
|
if (TargetRegisterInfo::isPhysicalRegister(reg)) {
|
||||||
|
physReg2liu_[reg].unify(li);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lvrQ.push(&li);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top-level driver to manage the queue of unassigned LiveVirtRegs and call the
|
||||||
|
// selectOrSplit implementation.
|
||||||
|
void RegAllocBase::allocatePhysRegs() {
|
||||||
|
LiveVirtRegQueue lvrQ;
|
||||||
|
seedLiveVirtRegs(lvrQ);
|
||||||
|
while (!lvrQ.empty()) {
|
||||||
|
LiveInterval *lvr = lvrQ.get();
|
||||||
|
typedef SmallVector<LiveInterval*, 4> LVRVec;
|
||||||
|
LVRVec splitLVRs;
|
||||||
|
unsigned availablePhysReg = selectOrSplit(*lvr, splitLVRs);
|
||||||
|
if (availablePhysReg) {
|
||||||
|
assert(splitLVRs.empty() && "inconsistent splitting");
|
||||||
|
assert(!vrm_->hasPhys(lvr->reg) && "duplicate vreg in interval unions");
|
||||||
|
vrm_->assignVirt2Phys(lvr->reg, availablePhysReg);
|
||||||
|
physReg2liu_[availablePhysReg].unify(*lvr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (LVRVec::iterator lvrI = splitLVRs.begin(), lvrEnd = splitLVRs.end();
|
||||||
|
lvrI != lvrEnd; ++lvrI) {
|
||||||
|
assert(TargetRegisterInfo::isVirtualRegister((*lvrI)->reg) &&
|
||||||
|
"expect split value in virtual register");
|
||||||
|
lvrQ.push(*lvrI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if this live virtual reg interferes with a physical register. If not,
|
// Check if this live virtual reg interferes with a physical register. If not,
|
||||||
// then check for interference on each register that aliases with the physical
|
// then check for interference on each register that aliases with the physical
|
||||||
// register.
|
// register.
|
||||||
@ -201,7 +284,8 @@ bool RegAllocBase::checkPhysRegInterference(LiveIntervalUnion::Query &query,
|
|||||||
// available register. So, the number of interference tests in the worst case is
|
// available register. So, the number of interference tests in the worst case is
|
||||||
// |vregs| * |machineregs|. And since the number of interference tests is
|
// |vregs| * |machineregs|. And since the number of interference tests is
|
||||||
// minimal, there is no value in caching them.
|
// minimal, there is no value in caching them.
|
||||||
unsigned RABasic::selectOrSplit(LiveInterval &lvr, LiveVirtRegs &splitLVRs) {
|
unsigned RABasic::selectOrSplit(LiveInterval &lvr,
|
||||||
|
SmallVectorImpl<LiveInterval*> &splitLVRs) {
|
||||||
// Check for an available reg in this class.
|
// Check for an available reg in this class.
|
||||||
const TargetRegisterClass *trc = mri_->getRegClass(lvr.reg);
|
const TargetRegisterClass *trc = mri_->getRegClass(lvr.reg);
|
||||||
for (TargetRegisterClass::iterator trcI = trc->allocation_order_begin(*mf_),
|
for (TargetRegisterClass::iterator trcI = trc->allocation_order_begin(*mf_),
|
||||||
@ -238,7 +322,7 @@ bool RABasic::runOnMachineFunction(MachineFunction &mf) {
|
|||||||
|
|
||||||
spiller_.reset(createSpiller(*this, *mf_, *vrm_));
|
spiller_.reset(createSpiller(*this, *mf_, *vrm_));
|
||||||
|
|
||||||
allocatePhysRegs(LessSpillWeightPriority());
|
allocatePhysRegs();
|
||||||
|
|
||||||
// Diagnostic output before rewriting
|
// Diagnostic output before rewriting
|
||||||
DEBUG(dbgs() << "Post alloc VirtRegMap:\n" << *vrm_ << "\n");
|
DEBUG(dbgs() << "Post alloc VirtRegMap:\n" << *vrm_ << "\n");
|
||||||
@ -249,6 +333,9 @@ bool RABasic::runOnMachineFunction(MachineFunction &mf) {
|
|||||||
// Run rewriter
|
// Run rewriter
|
||||||
std::auto_ptr<VirtRegRewriter> rewriter(createVirtRegRewriter());
|
std::auto_ptr<VirtRegRewriter> rewriter(createVirtRegRewriter());
|
||||||
rewriter->runOnMachineFunction(*mf_, *vrm_, lis_);
|
rewriter->runOnMachineFunction(*mf_, *vrm_, lis_);
|
||||||
|
|
||||||
|
// The pass output is in VirtRegMap. Release all the transient data.
|
||||||
|
releaseMemory();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user