mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-28 04:33:05 +00:00
Adds RABasic verification and tracing.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@118604 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
5df08d8f55
commit
39a5ce46a5
@ -15,6 +15,7 @@
|
||||
|
||||
#define DEBUG_TYPE "regalloc"
|
||||
#include "LiveIntervalUnion.h"
|
||||
#include "llvm/ADT/SparseBitVector.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
@ -73,12 +74,9 @@ void LiveIntervalUnion::unify(LiveInterval &lvr) {
|
||||
#ifndef NDEBUG
|
||||
// check for overlap (inductively)
|
||||
if (segPos != segments_.begin()) {
|
||||
SegmentIter prevPos = segPos;
|
||||
--prevPos;
|
||||
assert(prevPos->end <= segment.start && "overlapping segments" );
|
||||
assert(prior(segPos)->end <= segment.start && "overlapping segments" );
|
||||
}
|
||||
SegmentIter nextPos = segPos;
|
||||
++nextPos;
|
||||
SegmentIter nextPos = next(segPos);
|
||||
if (nextPos != segments_.end())
|
||||
assert(segment.end <= nextPos->start && "overlapping segments" );
|
||||
#endif // NDEBUG
|
||||
@ -98,6 +96,49 @@ void LiveIntervalUnion::extract(const LiveInterval &lvr) {
|
||||
}
|
||||
}
|
||||
|
||||
raw_ostream& llvm::operator<<(raw_ostream& os, const LiveSegment &ls) {
|
||||
return os << '[' << ls.start << ',' << ls.end << ':' <<
|
||||
ls.liveVirtReg->reg << ")";
|
||||
}
|
||||
|
||||
void LiveSegment::dump() const {
|
||||
dbgs() << *this << "\n";
|
||||
}
|
||||
|
||||
void
|
||||
LiveIntervalUnion::print(raw_ostream &os,
|
||||
const AbstractRegisterDescription *rdesc) const {
|
||||
os << "LIU ";
|
||||
if (rdesc != NULL)
|
||||
os << rdesc->getName(repReg_);
|
||||
else {
|
||||
os << repReg_;
|
||||
}
|
||||
for (SegmentIter segI = segments_.begin(), segEnd = segments_.end();
|
||||
segI != segEnd; ++segI) {
|
||||
dbgs() << " " << *segI;
|
||||
}
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void LiveIntervalUnion::dump(const AbstractRegisterDescription *rdesc) const {
|
||||
print(dbgs(), rdesc);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Verify the live intervals in this union and add them to the visited set.
|
||||
void LiveIntervalUnion::verify(LvrBitSet& visitedVRegs) {
|
||||
SegmentIter segI = segments_.begin();
|
||||
SegmentIter segEnd = segments_.end();
|
||||
if (segI == segEnd) return;
|
||||
visitedVRegs.set(segI->liveVirtReg->reg);
|
||||
for (++segI; segI != segEnd; ++segI) {
|
||||
visitedVRegs.set(segI->liveVirtReg->reg);
|
||||
assert(prior(segI)->end <= segI->start && "overlapping segments" );
|
||||
}
|
||||
}
|
||||
#endif //!NDEBUG
|
||||
|
||||
// Private interface accessed by Query.
|
||||
//
|
||||
// Find a pair of segments that intersect, one in the live virtual register
|
||||
|
@ -23,6 +23,12 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
#ifndef NDEBUG
|
||||
// forward declaration
|
||||
template <unsigned Element> class SparseBitVector;
|
||||
typedef SparseBitVector<128> LvrBitSet;
|
||||
#endif
|
||||
|
||||
/// A LiveSegment is a copy of a LiveRange object used within
|
||||
/// LiveIntervalUnion. LiveSegment additionally contains a pointer to its
|
||||
/// original live virtual register (LiveInterval). This allows quick lookup of
|
||||
@ -51,6 +57,9 @@ struct LiveSegment {
|
||||
|
||||
// Order segments by starting point only--we expect them to be disjoint.
|
||||
bool operator<(const LiveSegment &ls) const { return start < ls.start; }
|
||||
|
||||
void dump() const;
|
||||
void print(raw_ostream &os) const;
|
||||
};
|
||||
|
||||
inline bool operator<(SlotIndex V, const LiveSegment &ls) {
|
||||
@ -66,6 +75,16 @@ inline bool overlap(const LiveRange &lvrSeg, const LiveSegment &liuSeg) {
|
||||
return lvrSeg.start < liuSeg.end && liuSeg.start < lvrSeg.end;
|
||||
}
|
||||
|
||||
template <> struct isPodLike<LiveSegment> { static const bool value = true; };
|
||||
|
||||
raw_ostream& operator<<(raw_ostream& os, const LiveSegment &ls);
|
||||
|
||||
/// Abstraction to provide info for the representative register.
|
||||
class AbstractRegisterDescription {
|
||||
public:
|
||||
virtual const char *getName(unsigned reg) const = 0;
|
||||
};
|
||||
|
||||
/// Union of live intervals that are strong candidates for coalescing into a
|
||||
/// single register (either physical or virtual depending on the context). We
|
||||
/// expect the constituent live intervals to be disjoint, although we may
|
||||
@ -122,6 +141,16 @@ public:
|
||||
// Remove a live virtual register's segments from this union.
|
||||
void extract(const LiveInterval &lvr);
|
||||
|
||||
void dump(const AbstractRegisterDescription *regInfo) const;
|
||||
|
||||
// If tri != NULL, use it to decode repReg_
|
||||
void print(raw_ostream &os, const AbstractRegisterDescription *rdesc) const;
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Verify the live intervals in this union and add them to the visited set.
|
||||
void verify(LvrBitSet& visitedVRegs);
|
||||
#endif
|
||||
|
||||
/// Cache a single interference test result in the form of two intersecting
|
||||
/// segments. This allows efficiently iterating over the interferences. The
|
||||
/// iteration logic is handled by LiveIntervalUnion::Query which may
|
||||
|
@ -128,6 +128,11 @@ protected:
|
||||
// exists, return the interfering register, which may be preg or an alias.
|
||||
unsigned checkPhysRegInterference(LiveInterval& lvr, unsigned preg);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Verify each LiveIntervalUnion.
|
||||
void verify();
|
||||
#endif
|
||||
|
||||
// Helper that spills all live virtual registers currently unified under preg
|
||||
// that interfere with the most recently queried lvr.
|
||||
void spillInterferences(unsigned preg,
|
||||
|
@ -34,6 +34,9 @@
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
#ifndef NDEBUG
|
||||
#include "llvm/ADT/SparseBitVector.h"
|
||||
#endif
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
@ -46,6 +49,19 @@ using namespace llvm;
|
||||
static RegisterRegAlloc basicRegAlloc("basic", "basic register allocator",
|
||||
createBasicRegisterAllocator);
|
||||
|
||||
// Temporary verification option until we can put verification inside
|
||||
// MachineVerifier.
|
||||
static cl::opt<bool>
|
||||
VerifyRegAlloc("verify-regalloc",
|
||||
cl::desc("Verify live intervals before renaming"));
|
||||
|
||||
class PhysicalRegisterDescription : public AbstractRegisterDescription {
|
||||
const TargetRegisterInfo *tri_;
|
||||
public:
|
||||
PhysicalRegisterDescription(const TargetRegisterInfo *tri): tri_(tri) {}
|
||||
virtual const char *getName(unsigned reg) const { return tri_->getName(reg); }
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
/// RABasic provides a minimal implementation of the basic register allocation
|
||||
@ -153,6 +169,40 @@ void RABasic::releaseMemory() {
|
||||
RegAllocBase::releaseMemory();
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Verify each LiveIntervalUnion.
|
||||
void RegAllocBase::verify() {
|
||||
LvrBitSet visitedVRegs;
|
||||
OwningArrayPtr<LvrBitSet> unionVRegs(new LvrBitSet[physReg2liu_.numRegs()]);
|
||||
// Verify disjoint unions.
|
||||
for (unsigned preg = 0; preg < physReg2liu_.numRegs(); ++preg) {
|
||||
DEBUG(PhysicalRegisterDescription prd(tri_); physReg2liu_[preg].dump(&prd));
|
||||
LvrBitSet &vregs = unionVRegs[preg];
|
||||
physReg2liu_[preg].verify(vregs);
|
||||
// Union + intersection test could be done efficiently in one pass, but
|
||||
// don't add a method to SparseBitVector unless we really need it.
|
||||
assert(!visitedVRegs.intersects(vregs) && "vreg in multiple unions");
|
||||
visitedVRegs |= vregs;
|
||||
}
|
||||
// Verify vreg coverage.
|
||||
for (LiveIntervals::iterator liItr = lis_->begin(), liEnd = lis_->end();
|
||||
liItr != liEnd; ++liItr) {
|
||||
unsigned reg = liItr->first;
|
||||
LiveInterval &li = *liItr->second;
|
||||
if (li.empty() ) continue;
|
||||
if (TargetRegisterInfo::isPhysicalRegister(reg)) continue;
|
||||
if (!vrm_->hasPhys(reg)) continue; // spilled?
|
||||
unsigned preg = vrm_->getPhys(reg);
|
||||
if (!unionVRegs[preg].test(reg)) {
|
||||
dbgs() << "LiveVirtReg " << reg << " not in union " <<
|
||||
tri_->getName(preg) << "\n";
|
||||
llvm_unreachable("unallocated live vreg");
|
||||
}
|
||||
}
|
||||
// FIXME: I'm not sure how to verify spilled intervals.
|
||||
}
|
||||
#endif //!NDEBUG
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// RegAllocBase Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -222,6 +272,7 @@ void RegAllocBase::seedLiveVirtRegs(LiveVirtRegQueue &lvrQ) {
|
||||
liItr != liEnd; ++liItr) {
|
||||
unsigned reg = liItr->first;
|
||||
LiveInterval &li = *liItr->second;
|
||||
if (li.empty()) continue;
|
||||
if (TargetRegisterInfo::isPhysicalRegister(reg)) {
|
||||
physReg2liu_[reg].unify(li);
|
||||
}
|
||||
@ -243,13 +294,14 @@ void RegAllocBase::allocatePhysRegs() {
|
||||
unsigned availablePhysReg = selectOrSplit(*lvr, splitLVRs);
|
||||
if (availablePhysReg) {
|
||||
DEBUG(dbgs() << "allocating: " << tri_->getName(availablePhysReg) <<
|
||||
" " << lvr << '\n');
|
||||
" " << *lvr << '\n');
|
||||
assert(!vrm_->hasPhys(lvr->reg) && "duplicate vreg in interval unions");
|
||||
vrm_->assignVirt2Phys(lvr->reg, availablePhysReg);
|
||||
physReg2liu_[availablePhysReg].unify(*lvr);
|
||||
}
|
||||
for (LVRVec::iterator lvrI = splitLVRs.begin(), lvrEnd = splitLVRs.end();
|
||||
lvrI != lvrEnd; ++lvrI) {
|
||||
if ((*lvrI)->empty()) continue;
|
||||
DEBUG(dbgs() << "queuing new interval: " << **lvrI << "\n");
|
||||
assert(TargetRegisterInfo::isVirtualRegister((*lvrI)->reg) &&
|
||||
"expect split value in virtual register");
|
||||
@ -274,26 +326,32 @@ unsigned RegAllocBase::checkPhysRegInterference(LiveInterval &lvr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Spill all live virtual registers currently unified under preg that interfere
|
||||
// with lvr.
|
||||
// Spill or split all live virtual registers currently unified under preg that
|
||||
// interfere with lvr. The newly spilled or split live intervals are returned by
|
||||
// appending them to splitLVRs.
|
||||
void RABasic::spillInterferences(unsigned preg,
|
||||
SmallVectorImpl<LiveInterval*> &splitLVRs) {
|
||||
SmallPtrSet<LiveInterval*, 8> spilledLVRs;
|
||||
LiveIntervalUnion::Query &query = queries_[preg];
|
||||
// Record each interference before mutating either the union or live
|
||||
// intervals.
|
||||
LiveIntervalUnion::InterferenceResult ir = query.firstInterference();
|
||||
assert(query.isInterference(ir) && "expect interference");
|
||||
do {
|
||||
LiveInterval *lvr = ir.liuSegPos()->liveVirtReg;
|
||||
if (!spilledLVRs.insert(lvr)) continue;
|
||||
// Spill the previously allocated lvr.
|
||||
SmallVector<LiveInterval*, 1> spillIs; // ignored
|
||||
spiller_->spill(lvr, splitLVRs, spillIs);
|
||||
spilledLVRs.insert(ir.liuSegPos()->liveVirtReg);
|
||||
} while (query.nextInterference(ir));
|
||||
for (SmallPtrSetIterator<LiveInterval*> lvrI = spilledLVRs.begin(),
|
||||
lvrEnd = spilledLVRs.end();
|
||||
lvrI != lvrEnd; ++lvrI ) {
|
||||
LiveInterval& lvr = **lvrI;
|
||||
// Spill the previously allocated lvr.
|
||||
DEBUG(dbgs() << "extracting from " << preg << " " << lvr << '\n');
|
||||
// Deallocate the interfering lvr by removing it from the preg union.
|
||||
physReg2liu_[preg].extract(**lvrI);
|
||||
// Live intervals may not be in a union during modification.
|
||||
physReg2liu_[preg].extract(lvr);
|
||||
// Spill the extracted interval.
|
||||
SmallVector<LiveInterval*, 8> spillIs;
|
||||
spiller_->spill(&lvr, splitLVRs, spillIs);
|
||||
}
|
||||
// After extracting segments, the query's results are invalid.
|
||||
query.clear();
|
||||
@ -399,6 +457,24 @@ bool RABasic::runOnMachineFunction(MachineFunction &mf) {
|
||||
// optional HTML output
|
||||
DEBUG(rmf_->renderMachineFunction("After basic register allocation.", vrm_));
|
||||
|
||||
// FIXME: Verification currently must run before VirtRegRewriter. We should
|
||||
// make the rewriter a separate pass and override verifyAnalysis instead. When
|
||||
// that happens, verification naturally falls under VerifyMachineCode.
|
||||
#ifndef NDEBUG
|
||||
if (VerifyRegAlloc) {
|
||||
// Verify accuracy of LiveIntervals. The standard machine code verifier
|
||||
// ensures that each LiveIntervals covers all uses of the virtual reg.
|
||||
|
||||
// FIXME: MachineVerifier is currently broken when using the standard
|
||||
// spiller. Enable it for InlineSpiller only.
|
||||
// mf_->verify(this);
|
||||
|
||||
// Verify that LiveIntervals are partitioned into unions and disjoint within
|
||||
// the unions.
|
||||
verify();
|
||||
}
|
||||
#endif // !NDEBUG
|
||||
|
||||
// Run rewriter
|
||||
std::auto_ptr<VirtRegRewriter> rewriter(createVirtRegRewriter());
|
||||
rewriter->runOnMachineFunction(*mf_, *vrm_, lis_);
|
||||
|
Loading…
Reference in New Issue
Block a user