mirror of
https://github.com/RPCSX/llvm.git
synced 2024-12-02 00:36:36 +00:00
Pull the LiveRange and LiveInterval classes out of LiveIntervals.h (which
will soon be renamed) into their own file. The new file should not emit DEBUG output or have other side effects. The LiveInterval class also now doesn't know whether its working on registers or some other thing. In the future we will want to use the LiveInterval class and friends to do stack packing. In addition to a code simplification, this will allow us to do it more easily. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@15134 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
e2eceb5c73
commit
fb449b9ea5
109
include/llvm/CodeGen/LiveInterval.h
Normal file
109
include/llvm/CodeGen/LiveInterval.h
Normal file
@ -0,0 +1,109 @@
|
||||
//===-- llvm/CodeGen/LiveInterval.h - Interval representation ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the LiveRange and LiveInterval classes. Given some
|
||||
// numbering of each the machine instructions an interval [i, j) is said to be a
|
||||
// live interval for register v if there is no instruction with number j' > j
|
||||
// such that v is live at j' abd there is no instruction with number i' < i such
|
||||
// that v is live at i'. In this implementation intervals can have holes,
|
||||
// i.e. an interval might look like [1,20), [50,65), [1000,1001). Each
|
||||
// individual range is represented as an instance of LiveRange, and the whole
|
||||
// interval is represented as an instance of LiveInterval.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LIVEINTERVAL_H
|
||||
#define LLVM_CODEGEN_LIVEINTERVAL_H
|
||||
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
/// LiveRange structure - This represents a simple register range in the
|
||||
/// program, with an inclusive start point and an exclusive end point.
|
||||
/// These ranges are rendered as [start,end).
|
||||
struct LiveRange {
|
||||
unsigned start; // Start point of the interval (inclusive)
|
||||
unsigned end; // End point of the interval (exclusive)
|
||||
LiveRange(unsigned S, unsigned E) : start(S), end(E) {
|
||||
assert(S < E && "Cannot create empty or backwards range");
|
||||
}
|
||||
|
||||
bool operator<(const LiveRange &LR) const {
|
||||
return start < LR.start || (start == LR.start && end < LR.end);
|
||||
}
|
||||
bool operator==(const LiveRange &LR) const {
|
||||
return start == LR.start && end == LR.end;
|
||||
}
|
||||
private:
|
||||
LiveRange(); // DO NOT IMPLEMENT
|
||||
};
|
||||
std::ostream& operator<<(std::ostream& os, const LiveRange &LR);
|
||||
|
||||
/// LiveInterval - This class represents some number of live ranges for a
|
||||
/// register or value. This class also contains a bit of register allocator
|
||||
/// state.
|
||||
struct LiveInterval {
|
||||
typedef std::vector<LiveRange> Ranges;
|
||||
unsigned reg; // the register of this interval
|
||||
float weight; // weight of this interval
|
||||
Ranges ranges; // the ranges in which this register is live
|
||||
bool isDefinedOnce; // True if this interval contains one value.
|
||||
|
||||
LiveInterval(unsigned Reg, float Weight)
|
||||
: reg(Reg), weight(Weight), isDefinedOnce(false) {
|
||||
}
|
||||
|
||||
bool containsOneValue() const { return isDefinedOnce; }
|
||||
|
||||
bool empty() const { return ranges.empty(); }
|
||||
|
||||
/// start - Return the lowest numbered slot covered by interval.
|
||||
unsigned start() const {
|
||||
assert(!empty() && "empty interval for register");
|
||||
return ranges.front().start;
|
||||
}
|
||||
|
||||
/// end - return the maximum point of the interval of the whole,
|
||||
/// exclusive.
|
||||
unsigned end() const {
|
||||
assert(!empty() && "empty interval for register");
|
||||
return ranges.back().end;
|
||||
}
|
||||
|
||||
bool expiredAt(unsigned index) const {
|
||||
return end() <= (index + 1);
|
||||
}
|
||||
|
||||
bool liveAt(unsigned index) const;
|
||||
|
||||
bool overlaps(const LiveInterval& other) const;
|
||||
|
||||
void addRange(LiveRange R);
|
||||
|
||||
void join(const LiveInterval& other);
|
||||
|
||||
bool operator<(const LiveInterval& other) const {
|
||||
return start() < other.start();
|
||||
}
|
||||
|
||||
bool operator==(const LiveInterval& other) const {
|
||||
return reg == other.reg;
|
||||
}
|
||||
|
||||
private:
|
||||
Ranges::iterator mergeRangesForward(Ranges::iterator it);
|
||||
Ranges::iterator mergeRangesBackward(Ranges::iterator it);
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const LiveInterval& li);
|
||||
}
|
||||
|
||||
#endif
|
@ -21,6 +21,7 @@
|
||||
#define LLVM_CODEGEN_LIVEINTERVALS_H
|
||||
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "LiveInterval.h"
|
||||
#include <list>
|
||||
|
||||
namespace llvm {
|
||||
@ -29,81 +30,6 @@ namespace llvm {
|
||||
class MRegisterInfo;
|
||||
class VirtRegMap;
|
||||
|
||||
/// LiveRange structure - This represents a simple register range in the
|
||||
/// program, with an inclusive start point and an exclusive end point.
|
||||
/// These ranges are rendered as [start,end).
|
||||
struct LiveRange {
|
||||
unsigned start; // Start point of the interval (inclusive)
|
||||
unsigned end; // End point of the interval (exclusive)
|
||||
LiveRange(unsigned S, unsigned E) : start(S), end(E) {
|
||||
assert(S < E && "Cannot create empty or backwards range");
|
||||
}
|
||||
|
||||
bool operator<(const LiveRange &LR) const {
|
||||
return start < LR.start || (start == LR.start && end < LR.end);
|
||||
}
|
||||
bool operator==(const LiveRange &LR) const {
|
||||
return start == LR.start && end == LR.end;
|
||||
}
|
||||
private:
|
||||
LiveRange(); // DO NOT IMPLEMENT
|
||||
};
|
||||
std::ostream& operator<<(std::ostream& os, const LiveRange &LR);
|
||||
|
||||
struct LiveInterval {
|
||||
typedef std::vector<LiveRange> Ranges;
|
||||
unsigned reg; // the register of this interval
|
||||
float weight; // weight of this interval:
|
||||
// (number of uses *10^loopDepth)
|
||||
Ranges ranges; // the ranges in which this register is live
|
||||
bool isDefinedOnce; // True if there is one def of this register
|
||||
|
||||
explicit LiveInterval(unsigned r);
|
||||
|
||||
bool empty() const { return ranges.empty(); }
|
||||
|
||||
bool spilled() const;
|
||||
|
||||
/// start - Return the lowest numbered slot covered by interval.
|
||||
unsigned start() const {
|
||||
assert(!empty() && "empty interval for register");
|
||||
return ranges.front().start;
|
||||
}
|
||||
|
||||
/// end - return the maximum point of the interval of the whole,
|
||||
/// exclusive.
|
||||
unsigned end() const {
|
||||
assert(!empty() && "empty interval for register");
|
||||
return ranges.back().end;
|
||||
}
|
||||
|
||||
bool expiredAt(unsigned index) const {
|
||||
return end() <= (index + 1);
|
||||
}
|
||||
|
||||
bool liveAt(unsigned index) const;
|
||||
|
||||
bool overlaps(const LiveInterval& other) const;
|
||||
|
||||
void addRange(LiveRange R);
|
||||
|
||||
void join(const LiveInterval& other);
|
||||
|
||||
bool operator<(const LiveInterval& other) const {
|
||||
return start() < other.start();
|
||||
}
|
||||
|
||||
bool operator==(const LiveInterval& other) const {
|
||||
return reg == other.reg;
|
||||
}
|
||||
|
||||
private:
|
||||
Ranges::iterator mergeRangesForward(Ranges::iterator it);
|
||||
Ranges::iterator mergeRangesBackward(Ranges::iterator it);
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const LiveInterval& li);
|
||||
|
||||
class LiveIntervals : public MachineFunctionPass
|
||||
{
|
||||
public:
|
||||
|
151
lib/CodeGen/LiveInterval.cpp
Normal file
151
lib/CodeGen/LiveInterval.cpp
Normal file
@ -0,0 +1,151 @@
|
||||
//===-- LiveInterval.cpp - Live Interval Representation -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the LiveRange and LiveInterval classes. Given some
|
||||
// numbering of each the machine instructions an interval [i, j) is said to be a
|
||||
// live interval for register v if there is no instruction with number j' > j
|
||||
// such that v is live at j' abd there is no instruction with number i' < i such
|
||||
// that v is live at i'. In this implementation intervals can have holes,
|
||||
// i.e. an interval might look like [1,20), [50,65), [1000,1001). Each
|
||||
// individual range is represented as an instance of LiveRange, and the whole
|
||||
// interval is represented as an instance of LiveInterval.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "LiveInterval.h"
|
||||
#include "Support/STLExtras.h"
|
||||
#include <ostream>
|
||||
using namespace llvm;
|
||||
|
||||
// An example for liveAt():
|
||||
//
|
||||
// this = [1,4), liveAt(0) will return false. The instruction defining
|
||||
// this spans slots [0,3]. The interval belongs to an spilled
|
||||
// definition of the variable it represents. This is because slot 1 is
|
||||
// used (def slot) and spans up to slot 3 (store slot).
|
||||
//
|
||||
bool LiveInterval::liveAt(unsigned index) const {
|
||||
LiveRange dummy(index, index+1);
|
||||
Ranges::const_iterator r = std::upper_bound(ranges.begin(),
|
||||
ranges.end(),
|
||||
dummy);
|
||||
if (r == ranges.begin())
|
||||
return false;
|
||||
|
||||
--r;
|
||||
return index >= r->start && index < r->end;
|
||||
}
|
||||
|
||||
// An example for overlaps():
|
||||
//
|
||||
// 0: A = ...
|
||||
// 4: B = ...
|
||||
// 8: C = A + B ;; last use of A
|
||||
//
|
||||
// The live intervals should look like:
|
||||
//
|
||||
// A = [3, 11)
|
||||
// B = [7, x)
|
||||
// C = [11, y)
|
||||
//
|
||||
// A->overlaps(C) should return false since we want to be able to join
|
||||
// A and C.
|
||||
bool LiveInterval::overlaps(const LiveInterval& other) const {
|
||||
Ranges::const_iterator i = ranges.begin();
|
||||
Ranges::const_iterator ie = ranges.end();
|
||||
Ranges::const_iterator j = other.ranges.begin();
|
||||
Ranges::const_iterator je = other.ranges.end();
|
||||
if (i->start < j->start) {
|
||||
i = std::upper_bound(i, ie, *j);
|
||||
if (i != ranges.begin()) --i;
|
||||
}
|
||||
else if (j->start < i->start) {
|
||||
j = std::upper_bound(j, je, *i);
|
||||
if (j != other.ranges.begin()) --j;
|
||||
}
|
||||
|
||||
while (i != ie && j != je) {
|
||||
if (i->start == j->start)
|
||||
return true;
|
||||
|
||||
if (i->start > j->start) {
|
||||
swap(i, j);
|
||||
swap(ie, je);
|
||||
}
|
||||
assert(i->start < j->start);
|
||||
|
||||
if (i->end > j->start)
|
||||
return true;
|
||||
++i;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LiveInterval::addRange(LiveRange LR) {
|
||||
Ranges::iterator it =
|
||||
ranges.insert(std::upper_bound(ranges.begin(), ranges.end(), LR), LR);
|
||||
|
||||
mergeRangesBackward(mergeRangesForward(it));
|
||||
}
|
||||
|
||||
void LiveInterval::join(const LiveInterval& other) {
|
||||
Ranges::iterator cur = ranges.begin();
|
||||
isDefinedOnce &= other.isDefinedOnce;
|
||||
|
||||
for (Ranges::const_iterator i = other.ranges.begin(),
|
||||
e = other.ranges.end(); i != e; ++i) {
|
||||
cur = ranges.insert(std::upper_bound(cur, ranges.end(), *i), *i);
|
||||
cur = mergeRangesBackward(mergeRangesForward(cur));
|
||||
}
|
||||
weight += other.weight;
|
||||
}
|
||||
|
||||
LiveInterval::Ranges::iterator
|
||||
LiveInterval::mergeRangesForward(Ranges::iterator it) {
|
||||
Ranges::iterator n;
|
||||
while ((n = next(it)) != ranges.end()) {
|
||||
if (n->start > it->end)
|
||||
break;
|
||||
it->end = std::max(it->end, n->end);
|
||||
n = ranges.erase(n);
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
LiveInterval::Ranges::iterator
|
||||
LiveInterval::mergeRangesBackward(Ranges::iterator it) {
|
||||
while (it != ranges.begin()) {
|
||||
Ranges::iterator p = prior(it);
|
||||
if (it->start > p->end)
|
||||
break;
|
||||
|
||||
it->start = std::min(it->start, p->start);
|
||||
it->end = std::max(it->end, p->end);
|
||||
it = ranges.erase(p);
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
std::ostream& llvm::operator<<(std::ostream& os, const LiveRange &LR) {
|
||||
return os << "[" << LR.start << "," << LR.end << ")";
|
||||
}
|
||||
|
||||
std::ostream& llvm::operator<<(std::ostream& os, const LiveInterval& li) {
|
||||
os << "%reg" << li.reg << ',' << li.weight;
|
||||
if (li.empty())
|
||||
return os << "EMPTY";
|
||||
|
||||
os << " = ";
|
||||
for (LiveInterval::Ranges::const_iterator i = li.ranges.begin(),
|
||||
e = li.ranges.end(); i != e; ++i)
|
||||
os << *i;
|
||||
return os;
|
||||
}
|
109
lib/CodeGen/LiveInterval.h
Normal file
109
lib/CodeGen/LiveInterval.h
Normal file
@ -0,0 +1,109 @@
|
||||
//===-- llvm/CodeGen/LiveInterval.h - Interval representation ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the LiveRange and LiveInterval classes. Given some
|
||||
// numbering of each the machine instructions an interval [i, j) is said to be a
|
||||
// live interval for register v if there is no instruction with number j' > j
|
||||
// such that v is live at j' abd there is no instruction with number i' < i such
|
||||
// that v is live at i'. In this implementation intervals can have holes,
|
||||
// i.e. an interval might look like [1,20), [50,65), [1000,1001). Each
|
||||
// individual range is represented as an instance of LiveRange, and the whole
|
||||
// interval is represented as an instance of LiveInterval.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LIVEINTERVAL_H
|
||||
#define LLVM_CODEGEN_LIVEINTERVAL_H
|
||||
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
/// LiveRange structure - This represents a simple register range in the
|
||||
/// program, with an inclusive start point and an exclusive end point.
|
||||
/// These ranges are rendered as [start,end).
|
||||
struct LiveRange {
|
||||
unsigned start; // Start point of the interval (inclusive)
|
||||
unsigned end; // End point of the interval (exclusive)
|
||||
LiveRange(unsigned S, unsigned E) : start(S), end(E) {
|
||||
assert(S < E && "Cannot create empty or backwards range");
|
||||
}
|
||||
|
||||
bool operator<(const LiveRange &LR) const {
|
||||
return start < LR.start || (start == LR.start && end < LR.end);
|
||||
}
|
||||
bool operator==(const LiveRange &LR) const {
|
||||
return start == LR.start && end == LR.end;
|
||||
}
|
||||
private:
|
||||
LiveRange(); // DO NOT IMPLEMENT
|
||||
};
|
||||
std::ostream& operator<<(std::ostream& os, const LiveRange &LR);
|
||||
|
||||
/// LiveInterval - This class represents some number of live ranges for a
|
||||
/// register or value. This class also contains a bit of register allocator
|
||||
/// state.
|
||||
struct LiveInterval {
|
||||
typedef std::vector<LiveRange> Ranges;
|
||||
unsigned reg; // the register of this interval
|
||||
float weight; // weight of this interval
|
||||
Ranges ranges; // the ranges in which this register is live
|
||||
bool isDefinedOnce; // True if this interval contains one value.
|
||||
|
||||
LiveInterval(unsigned Reg, float Weight)
|
||||
: reg(Reg), weight(Weight), isDefinedOnce(false) {
|
||||
}
|
||||
|
||||
bool containsOneValue() const { return isDefinedOnce; }
|
||||
|
||||
bool empty() const { return ranges.empty(); }
|
||||
|
||||
/// start - Return the lowest numbered slot covered by interval.
|
||||
unsigned start() const {
|
||||
assert(!empty() && "empty interval for register");
|
||||
return ranges.front().start;
|
||||
}
|
||||
|
||||
/// end - return the maximum point of the interval of the whole,
|
||||
/// exclusive.
|
||||
unsigned end() const {
|
||||
assert(!empty() && "empty interval for register");
|
||||
return ranges.back().end;
|
||||
}
|
||||
|
||||
bool expiredAt(unsigned index) const {
|
||||
return end() <= (index + 1);
|
||||
}
|
||||
|
||||
bool liveAt(unsigned index) const;
|
||||
|
||||
bool overlaps(const LiveInterval& other) const;
|
||||
|
||||
void addRange(LiveRange R);
|
||||
|
||||
void join(const LiveInterval& other);
|
||||
|
||||
bool operator<(const LiveInterval& other) const {
|
||||
return start() < other.start();
|
||||
}
|
||||
|
||||
bool operator==(const LiveInterval& other) const {
|
||||
return reg == other.reg;
|
||||
}
|
||||
|
||||
private:
|
||||
Ranges::iterator mergeRangesForward(Ranges::iterator it);
|
||||
Ranges::iterator mergeRangesBackward(Ranges::iterator it);
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const LiveInterval& li);
|
||||
}
|
||||
|
||||
#endif
|
@ -250,6 +250,7 @@ std::vector<LiveInterval*> LiveIntervals::addIntervalsForSpills(
|
||||
// the spill weight is now infinity as it
|
||||
// cannot be spilled again
|
||||
nI.weight = HUGE_VAL;
|
||||
DEBUG(std::cerr << " +" << LiveRange(start, end));
|
||||
nI.addRange(LiveRange(start, end));
|
||||
added.push_back(&nI);
|
||||
// update live variables
|
||||
@ -309,7 +310,7 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock* mbb,
|
||||
assert(vi.AliveBlocks.empty() &&
|
||||
"Shouldn't be alive across any blocks!");
|
||||
interval.addRange(LiveRange(defIndex, killIdx));
|
||||
DEBUG(std::cerr << "\n");
|
||||
DEBUG(std::cerr << " +" << LiveRange(defIndex, killIdx) << "\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -318,9 +319,10 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock* mbb,
|
||||
// of the defining block, potentially live across some blocks, then is
|
||||
// live into some number of blocks, but gets killed. Start by adding a
|
||||
// range that goes from this definition to the end of the defining block.
|
||||
interval.addRange(LiveRange(defIndex,
|
||||
getInstructionIndex(&mbb->back()) +
|
||||
InstrSlots::NUM));
|
||||
LiveRange NewLR(defIndex, getInstructionIndex(&mbb->back()) +
|
||||
InstrSlots::NUM);
|
||||
DEBUG(std::cerr << " +" << NewLR);
|
||||
interval.addRange(NewLR);
|
||||
|
||||
// Iterate over all of the blocks that the variable is completely
|
||||
// live in, adding [insrtIndex(begin), instrIndex(end)+4) to the
|
||||
@ -329,9 +331,10 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock* mbb,
|
||||
if (vi.AliveBlocks[i]) {
|
||||
MachineBasicBlock* mbb = mf_->getBlockNumbered(i);
|
||||
if (!mbb->empty()) {
|
||||
interval.addRange(LiveRange(
|
||||
getInstructionIndex(&mbb->front()),
|
||||
getInstructionIndex(&mbb->back()) + InstrSlots::NUM));
|
||||
LiveRange LR(getInstructionIndex(&mbb->front()),
|
||||
getInstructionIndex(&mbb->back())+InstrSlots::NUM);
|
||||
interval.addRange(LR);
|
||||
DEBUG(std::cerr << " +" << LR);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -340,9 +343,10 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock* mbb,
|
||||
// block to the 'use' slot of the killing instruction.
|
||||
for (unsigned i = 0, e = vi.Kills.size(); i != e; ++i) {
|
||||
MachineInstr *Kill = vi.Kills[i];
|
||||
interval.addRange(LiveRange(
|
||||
getInstructionIndex(Kill->getParent()->begin()),
|
||||
getUseIndex(getInstructionIndex(Kill))+1));
|
||||
LiveRange LR(getInstructionIndex(Kill->getParent()->begin()),
|
||||
getUseIndex(getInstructionIndex(Kill))+1);
|
||||
interval.addRange(LR);
|
||||
DEBUG(std::cerr << " +" << LR);
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -359,8 +363,10 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock* mbb,
|
||||
// the defined value will be live until the end of the basic block it
|
||||
// is defined in.
|
||||
unsigned defIndex = getDefIndex(getInstructionIndex(mi));
|
||||
interval.addRange(LiveRange(defIndex,
|
||||
getInstructionIndex(&mbb->back()) +InstrSlots::NUM));
|
||||
LiveRange LR(defIndex,
|
||||
getInstructionIndex(&mbb->back()) +InstrSlots::NUM);
|
||||
interval.addRange(LR);
|
||||
DEBUG(std::cerr << " +" << LR);
|
||||
}
|
||||
interval.isDefinedOnce = false;
|
||||
}
|
||||
@ -413,7 +419,7 @@ void LiveIntervals::handlePhysicalRegisterDef(MachineBasicBlock* mbb,
|
||||
exit:
|
||||
assert(start < end && "did not find end of interval?");
|
||||
interval.addRange(LiveRange(start, end));
|
||||
DEBUG(std::cerr << '\n');
|
||||
DEBUG(std::cerr << " +" << LiveRange(start, end) << '\n');
|
||||
}
|
||||
|
||||
void LiveIntervals::handleRegisterDef(MachineBasicBlock* mbb,
|
||||
@ -547,10 +553,11 @@ void LiveIntervals::joinIntervalsInMachineBB(MachineBasicBlock *MBB) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if their intervals do not overlap we join them
|
||||
if ((intA->isDefinedOnce && intB->isDefinedOnce) ||
|
||||
// if their intervals do not overlap we join them.
|
||||
if ((intA->containsOneValue() && intB->containsOneValue()) ||
|
||||
!intB->overlaps(*intA)) {
|
||||
intA->join(*intB);
|
||||
++numJoins;
|
||||
DEBUG(std::cerr << "Joined. Result = " << *intA << "\n");
|
||||
r2iB->second = r2iA->second;
|
||||
r2rMap_.insert(std::make_pair(intB->reg, intA->reg));
|
||||
@ -582,6 +589,7 @@ void LiveIntervals::joinIntervalsInMachineBB(MachineBasicBlock *MBB) {
|
||||
if (!intA->overlaps(*intB) &&
|
||||
!overlapsAliases(*intA, *intB)) {
|
||||
intA->join(*intB);
|
||||
++numJoins;
|
||||
DEBUG(std::cerr << "Joined. Result = " << *intA << "\n");
|
||||
r2iB->second = r2iA->second;
|
||||
r2rMap_.insert(std::make_pair(intB->reg, intA->reg));
|
||||
@ -656,158 +664,11 @@ LiveInterval& LiveIntervals::getOrCreateInterval(unsigned reg)
|
||||
{
|
||||
Reg2IntervalMap::iterator r2iit = r2iMap_.lower_bound(reg);
|
||||
if (r2iit == r2iMap_.end() || r2iit->first != reg) {
|
||||
intervals_.push_back(LiveInterval(reg));
|
||||
float Weight = MRegisterInfo::isPhysicalRegister(reg) ? HUGE_VAL :0.0F;
|
||||
intervals_.push_back(LiveInterval(reg, Weight));
|
||||
r2iit = r2iMap_.insert(r2iit, std::make_pair(reg, --intervals_.end()));
|
||||
}
|
||||
|
||||
return *r2iit->second;
|
||||
}
|
||||
|
||||
LiveInterval::LiveInterval(unsigned r)
|
||||
: reg(r),
|
||||
weight((MRegisterInfo::isPhysicalRegister(r) ? HUGE_VAL : 0.0F)),
|
||||
isDefinedOnce(false) {
|
||||
}
|
||||
|
||||
bool LiveInterval::spilled() const
|
||||
{
|
||||
return (weight == HUGE_VAL &&
|
||||
MRegisterInfo::isVirtualRegister(reg));
|
||||
}
|
||||
|
||||
// An example for liveAt():
|
||||
//
|
||||
// this = [1,4), liveAt(0) will return false. The instruction defining
|
||||
// this spans slots [0,3]. The interval belongs to an spilled
|
||||
// definition of the variable it represents. This is because slot 1 is
|
||||
// used (def slot) and spans up to slot 3 (store slot).
|
||||
//
|
||||
bool LiveInterval::liveAt(unsigned index) const
|
||||
{
|
||||
LiveRange dummy(index, index+1);
|
||||
Ranges::const_iterator r = std::upper_bound(ranges.begin(),
|
||||
ranges.end(),
|
||||
dummy);
|
||||
if (r == ranges.begin())
|
||||
return false;
|
||||
|
||||
--r;
|
||||
return index >= r->start && index < r->end;
|
||||
}
|
||||
|
||||
// An example for overlaps():
|
||||
//
|
||||
// 0: A = ...
|
||||
// 4: B = ...
|
||||
// 8: C = A + B ;; last use of A
|
||||
//
|
||||
// The live intervals should look like:
|
||||
//
|
||||
// A = [3, 11)
|
||||
// B = [7, x)
|
||||
// C = [11, y)
|
||||
//
|
||||
// A->overlaps(C) should return false since we want to be able to join
|
||||
// A and C.
|
||||
bool LiveInterval::overlaps(const LiveInterval& other) const
|
||||
{
|
||||
Ranges::const_iterator i = ranges.begin();
|
||||
Ranges::const_iterator ie = ranges.end();
|
||||
Ranges::const_iterator j = other.ranges.begin();
|
||||
Ranges::const_iterator je = other.ranges.end();
|
||||
if (i->start < j->start) {
|
||||
i = std::upper_bound(i, ie, *j);
|
||||
if (i != ranges.begin()) --i;
|
||||
}
|
||||
else if (j->start < i->start) {
|
||||
j = std::upper_bound(j, je, *i);
|
||||
if (j != other.ranges.begin()) --j;
|
||||
}
|
||||
|
||||
while (i != ie && j != je) {
|
||||
if (i->start == j->start)
|
||||
return true;
|
||||
|
||||
if (i->start > j->start) {
|
||||
swap(i, j);
|
||||
swap(ie, je);
|
||||
}
|
||||
assert(i->start < j->start);
|
||||
|
||||
if (i->end > j->start)
|
||||
return true;
|
||||
++i;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LiveInterval::addRange(LiveRange LR) {
|
||||
DEBUG(std::cerr << " +" << LR);
|
||||
Ranges::iterator it =
|
||||
ranges.insert(std::upper_bound(ranges.begin(), ranges.end(), LR), LR);
|
||||
|
||||
mergeRangesBackward(mergeRangesForward(it));
|
||||
}
|
||||
|
||||
void LiveInterval::join(const LiveInterval& other)
|
||||
{
|
||||
Ranges::iterator cur = ranges.begin();
|
||||
isDefinedOnce &= other.isDefinedOnce;
|
||||
|
||||
for (Ranges::const_iterator i = other.ranges.begin(),
|
||||
e = other.ranges.end(); i != e; ++i) {
|
||||
cur = ranges.insert(std::upper_bound(cur, ranges.end(), *i), *i);
|
||||
cur = mergeRangesForward(cur);
|
||||
cur = mergeRangesBackward(cur);
|
||||
}
|
||||
weight += other.weight;
|
||||
++numJoins;
|
||||
}
|
||||
|
||||
LiveInterval::Ranges::iterator LiveInterval::
|
||||
mergeRangesForward(Ranges::iterator it)
|
||||
{
|
||||
Ranges::iterator n;
|
||||
while ((n = next(it)) != ranges.end()) {
|
||||
if (n->start > it->end)
|
||||
break;
|
||||
it->end = std::max(it->end, n->end);
|
||||
n = ranges.erase(n);
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
LiveInterval::Ranges::iterator LiveInterval::
|
||||
mergeRangesBackward(Ranges::iterator it)
|
||||
{
|
||||
while (it != ranges.begin()) {
|
||||
Ranges::iterator p = prior(it);
|
||||
if (it->start > p->end)
|
||||
break;
|
||||
|
||||
it->start = std::min(it->start, p->start);
|
||||
it->end = std::max(it->end, p->end);
|
||||
it = ranges.erase(p);
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
std::ostream& llvm::operator<<(std::ostream& os, const LiveRange &LR) {
|
||||
return os << "[" << LR.start << "," << LR.end << ")";
|
||||
}
|
||||
|
||||
|
||||
std::ostream& llvm::operator<<(std::ostream& os, const LiveInterval& li)
|
||||
{
|
||||
os << "%reg" << li.reg << ',' << li.weight;
|
||||
if (li.empty())
|
||||
return os << "EMPTY";
|
||||
|
||||
os << " = ";
|
||||
for (LiveInterval::Ranges::const_iterator i = li.ranges.begin(),
|
||||
e = li.ranges.end(); i != e; ++i)
|
||||
os << *i;
|
||||
return os;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define LLVM_CODEGEN_LIVEINTERVALS_H
|
||||
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "LiveInterval.h"
|
||||
#include <list>
|
||||
|
||||
namespace llvm {
|
||||
@ -29,81 +30,6 @@ namespace llvm {
|
||||
class MRegisterInfo;
|
||||
class VirtRegMap;
|
||||
|
||||
/// LiveRange structure - This represents a simple register range in the
|
||||
/// program, with an inclusive start point and an exclusive end point.
|
||||
/// These ranges are rendered as [start,end).
|
||||
struct LiveRange {
|
||||
unsigned start; // Start point of the interval (inclusive)
|
||||
unsigned end; // End point of the interval (exclusive)
|
||||
LiveRange(unsigned S, unsigned E) : start(S), end(E) {
|
||||
assert(S < E && "Cannot create empty or backwards range");
|
||||
}
|
||||
|
||||
bool operator<(const LiveRange &LR) const {
|
||||
return start < LR.start || (start == LR.start && end < LR.end);
|
||||
}
|
||||
bool operator==(const LiveRange &LR) const {
|
||||
return start == LR.start && end == LR.end;
|
||||
}
|
||||
private:
|
||||
LiveRange(); // DO NOT IMPLEMENT
|
||||
};
|
||||
std::ostream& operator<<(std::ostream& os, const LiveRange &LR);
|
||||
|
||||
struct LiveInterval {
|
||||
typedef std::vector<LiveRange> Ranges;
|
||||
unsigned reg; // the register of this interval
|
||||
float weight; // weight of this interval:
|
||||
// (number of uses *10^loopDepth)
|
||||
Ranges ranges; // the ranges in which this register is live
|
||||
bool isDefinedOnce; // True if there is one def of this register
|
||||
|
||||
explicit LiveInterval(unsigned r);
|
||||
|
||||
bool empty() const { return ranges.empty(); }
|
||||
|
||||
bool spilled() const;
|
||||
|
||||
/// start - Return the lowest numbered slot covered by interval.
|
||||
unsigned start() const {
|
||||
assert(!empty() && "empty interval for register");
|
||||
return ranges.front().start;
|
||||
}
|
||||
|
||||
/// end - return the maximum point of the interval of the whole,
|
||||
/// exclusive.
|
||||
unsigned end() const {
|
||||
assert(!empty() && "empty interval for register");
|
||||
return ranges.back().end;
|
||||
}
|
||||
|
||||
bool expiredAt(unsigned index) const {
|
||||
return end() <= (index + 1);
|
||||
}
|
||||
|
||||
bool liveAt(unsigned index) const;
|
||||
|
||||
bool overlaps(const LiveInterval& other) const;
|
||||
|
||||
void addRange(LiveRange R);
|
||||
|
||||
void join(const LiveInterval& other);
|
||||
|
||||
bool operator<(const LiveInterval& other) const {
|
||||
return start() < other.start();
|
||||
}
|
||||
|
||||
bool operator==(const LiveInterval& other) const {
|
||||
return reg == other.reg;
|
||||
}
|
||||
|
||||
private:
|
||||
Ranges::iterator mergeRangesForward(Ranges::iterator it);
|
||||
Ranges::iterator mergeRangesBackward(Ranges::iterator it);
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const LiveInterval& li);
|
||||
|
||||
class LiveIntervals : public MachineFunctionPass
|
||||
{
|
||||
public:
|
||||
|
Loading…
Reference in New Issue
Block a user