From: Erik Verbruggen Date: Mon, 12 May 2014 11:33:48 +0000 (+0200) Subject: V4 RegAlloc: store, pass, and use life-time intervals by pointer. X-Git-Tag: v5.3.99+beta1~402 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=788b8bbff92b8fe7563501db7708c2ac87b4e361;p=platform%2Fupstream%2Fqtdeclarative.git V4 RegAlloc: store, pass, and use life-time intervals by pointer. By storing LifeTimeIntervals by pointer (instead of by value), other data-structures can safely use pointers too. This removes a lot of copies, especially in vectors that act as worklists. Also change the order of the "unhandled" list of intervals to be sorted in descending order. Not only is this more efficient, but it also removes the need to reverse the results of the life-range calculation (which produces the list in exactly this order). This change speeds up register allocation by about 20%. Change-Id: I6ea3dcd110f250d9ccc881753dc7392510a26d87 Reviewed-by: Simon Hausmann --- diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index 4783465..b1debbd 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -168,22 +168,20 @@ inline bool isBoolType(IR::Expr *e) */ class AllocateStackSlots: protected ConvertTemps { - const QVector _intervals; - QVector _unhandled; - QVector _live; + IR::LifeTimeIntervals::Ptr _intervals; + QVector _unhandled; + QVector _live; QBitArray _slotIsInUse; IR::Function *_function; public: - AllocateStackSlots(const QVector &intervals) + AllocateStackSlots(const IR::LifeTimeIntervals::Ptr &intervals) : _intervals(intervals) - , _slotIsInUse(intervals.size(), false) + , _slotIsInUse(intervals->size(), false) , _function(0) { _live.reserve(8); - _unhandled.reserve(_intervals.size()); - for (int i = _intervals.size() - 1; i >= 0; --i) - _unhandled.append(&_intervals.at(i)); + _unhandled = _intervals->intervals(); } void forFunction(IR::Function *function) @@ -242,7 +240,7 @@ protected: // active new ranges: while (!_unhandled.isEmpty()) { - const IR::LifeTimeInterval *lti = _unhandled.last(); + IR::LifeTimeInterval *lti = _unhandled.last(); if (lti->start() > s->id()) break; // we're done Q_ASSERT(!_stackSlotForTemp.contains(lti->temp().index)); @@ -286,7 +284,7 @@ protected: int i = _unhandled.size() - 1; for (; i >= 0; --i) { - const IR::LifeTimeInterval *lti = _unhandled[i]; + IR::LifeTimeInterval *lti = _unhandled[i]; if (lti->temp() == t) { _live.append(lti); _unhandled.remove(i); diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 82c3628..9c269dc 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -3578,9 +3578,7 @@ class LifeRanges { std::vector _liveIn; std::vector _intervals; - std::vector _finishedIntervals; - typedef QVector LifeTimeIntervals; - LifeTimeIntervals _sortedIntervals; + LifeTimeIntervals::Ptr _sortedIntervals; LifeTimeInterval &interval(const Temp *temp) { @@ -3595,32 +3593,27 @@ class LifeRanges { public: LifeRanges(IR::Function *function, const QHash &startEndLoops) : _intervals(function->tempCount) + , _sortedIntervals(LifeTimeIntervals::create(function->tempCount)) { function->renumberForLifeRanges(); _liveIn.resize(function->basicBlockCount()); - _finishedIntervals.reserve(function->tempCount); for (int i = function->basicBlockCount() - 1; i >= 0; --i) { BasicBlock *bb = function->basicBlock(i); buildIntervals(bb, startEndLoops.value(bb, 0)); } - _sortedIntervals.reserve(_finishedIntervals.size()); - for (unsigned i = _finishedIntervals.size(); i > 0;) - if (LifeTimeInterval *lti = _finishedIntervals[--i]) - _sortedIntervals.append(*lti); - qDeleteAll(_intervals); _intervals.clear(); } - QVector intervals() const { return _sortedIntervals; } + LifeTimeIntervals::Ptr intervals() const { return _sortedIntervals; } void dump() const { qout << "Life ranges:" << endl; qout << "Intervals:" << endl; - foreach (const LifeTimeInterval &range, _sortedIntervals) { - range.dump(qout); + foreach (const LifeTimeInterval *range, _sortedIntervals->intervals()) { + range->dump(qout); qout << endl; } @@ -3673,8 +3666,8 @@ private: interval(phi->targetTemp).setFrom(s); } else { live.erase(it); - _finishedIntervals.push_back(&interval(phi->targetTemp)); } + _sortedIntervals->add(&interval(phi->targetTemp)); continue; } collector.collect(s); @@ -3682,7 +3675,7 @@ private: LifeTimeInterval <i = interval(opd); lti.setFrom(s); live.remove(lti.temp()); - _finishedIntervals.push_back(<i); + _sortedIntervals->add(<i); } for (unsigned i = 0, ei = collector.inputs.size(); i != ei; ++i) { Temp *opd = collector.inputs[i]; @@ -3919,19 +3912,24 @@ void LifeTimeInterval::dump(QTextStream &out) const { out << " (register " << _reg << ")"; } -bool LifeTimeInterval::lessThan(const LifeTimeInterval &r1, const LifeTimeInterval &r2) { - if (r1._ranges.first().start == r2._ranges.first().start) { - if (r1.isSplitFromInterval() == r2.isSplitFromInterval()) - return r1._ranges.last().end < r2._ranges.last().end; +bool LifeTimeInterval::lessThan(const LifeTimeInterval *r1, const LifeTimeInterval *r2) { + if (r1->_ranges.first().start == r2->_ranges.first().start) { + if (r1->isSplitFromInterval() == r2->isSplitFromInterval()) + return r1->_ranges.last().end < r2->_ranges.last().end; else - return r1.isSplitFromInterval(); + return r1->isSplitFromInterval(); } else - return r1._ranges.first().start < r2._ranges.first().start; + return r1->_ranges.first().start < r2->_ranges.first().start; } -bool LifeTimeInterval::lessThanForTemp(const LifeTimeInterval &r1, const LifeTimeInterval &r2) +bool LifeTimeInterval::lessThanForTemp(const LifeTimeInterval *r1, const LifeTimeInterval *r2) { - return r1.temp() < r2.temp(); + return r1->temp() < r2->temp(); +} + +LifeTimeIntervals::~LifeTimeIntervals() +{ + qDeleteAll(_intervals); } Optimizer::Optimizer(IR::Function *function) @@ -4079,7 +4077,7 @@ void Optimizer::convertOutOfSSA() { } } -QVector Optimizer::lifeTimeIntervals() const +LifeTimeIntervals::Ptr Optimizer::lifeTimeIntervals() const { Q_ASSERT(isInSSA()); diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h index 372fe5c..324532a 100644 --- a/src/qml/compiler/qv4ssa_p.h +++ b/src/qml/compiler/qv4ssa_p.h @@ -43,6 +43,7 @@ #define QV4SSA_P_H #include "qv4jsir_p.h" +#include QT_BEGIN_NAMESPACE class QTextStream; @@ -118,8 +119,8 @@ public: void setSplitFromInterval(bool isSplitFromInterval) { _isSplitFromInterval = isSplitFromInterval; } void dump(QTextStream &out) const; - static bool lessThan(const LifeTimeInterval &r1, const LifeTimeInterval &r2); - static bool lessThanForTemp(const LifeTimeInterval &r1, const LifeTimeInterval &r2); + static bool lessThan(const LifeTimeInterval *r1, const LifeTimeInterval *r2); + static bool lessThanForTemp(const LifeTimeInterval *r1, const LifeTimeInterval *r2); void validate() const { #if !defined(QT_NO_DEBUG) @@ -136,6 +137,35 @@ public: } }; +class LifeTimeIntervals +{ + Q_DISABLE_COPY(LifeTimeIntervals) + + LifeTimeIntervals(int sizeHint) + { _intervals.reserve(sizeHint + 32); } + +public: + typedef QSharedPointer Ptr; + static Ptr create(int sizeHint) + { return Ptr(new LifeTimeIntervals(sizeHint)); } + + ~LifeTimeIntervals(); + + // takes ownership of the pointer + void add(LifeTimeInterval *interval) + { _intervals.append(interval); } + + // After calling Optimizer::lifeTimeIntervals() the result will have all intervals in descending order of start position. + QVector intervals() const + { return _intervals; } + + int size() const + { return _intervals.size(); } + +private: + QVector _intervals; +}; + class Q_QML_PRIVATE_EXPORT Optimizer { Q_DISABLE_COPY(Optimizer) @@ -151,7 +181,7 @@ public: QHash loopStartEndBlocks() const { return startEndLoops; } - QVector lifeTimeIntervals() const; + LifeTimeIntervals::Ptr lifeTimeIntervals() const; QSet calculateOptionalJumps(); diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp index c8962b0..14eef15 100644 --- a/src/qml/jit/qv4regalloc.cpp +++ b/src/qml/jit/qv4regalloc.cpp @@ -696,8 +696,10 @@ using namespace QT_PREPEND_NAMESPACE(QV4); namespace { class ResolutionPhase: protected StmtVisitor, protected ExprVisitor { - const QVector &_intervals; - QVector _unprocessed; + Q_DISABLE_COPY(ResolutionPhase) + + QVector _intervals; + QVector _unprocessed; IR::Function *_function; #if !defined(QT_NO_DEBUG) RegAllocInfo *_info; @@ -715,7 +717,7 @@ class ResolutionPhase: protected StmtVisitor, protected ExprVisitor { QHash > _liveAtEnd; public: - ResolutionPhase(const QVector &intervals, IR::Function *function, RegAllocInfo *info, + ResolutionPhase(const QVector &intervals, IR::Function *function, RegAllocInfo *info, const QHash &assignedSpillSlots, const QVector &intRegs, const QVector &fpRegs) : _intervals(intervals) @@ -731,10 +733,7 @@ public: Q_UNUSED(info) #endif - _unprocessed.resize(_intervals.size()); - for (int i = 0, ei = _intervals.size(); i != ei; ++i) - _unprocessed[i] = &_intervals[i]; - + _unprocessed = _intervals; _liveAtStart.reserve(function->basicBlockCount()); _liveAtEnd.reserve(function->basicBlockCount()); } @@ -1124,7 +1123,9 @@ void RegisterAllocator::run(IR::Function *function, const Optimizer &opt) if (DebugRegAlloc) qDebug() << "*** Running regalloc for function" << (function->name ? qPrintable(*function->name) : "NO NAME") << "***"; - _unhandled = opt.lifeTimeIntervals(); + _lifeTimeIntervals = opt.lifeTimeIntervals(); + + _unhandled = _lifeTimeIntervals->intervals(); _handled.reserve(_unhandled.size()); _info.reset(new RegAllocInfo); @@ -1133,10 +1134,10 @@ void RegisterAllocator::run(IR::Function *function, const Optimizer &opt) if (DebugRegAlloc) { QTextStream qout(stdout, QIODevice::WriteOnly); qout << "Ranges:" << endl; - QVector intervals = _unhandled; - std::sort(intervals.begin(), intervals.end(), LifeTimeInterval::lessThanForTemp); - foreach (const LifeTimeInterval &r, intervals) { - r.dump(qout); + QVector intervals = _unhandled; + std::reverse(intervals.begin(), intervals.end()); + foreach (const LifeTimeInterval *r, intervals) { + r->dump(qout); qout << endl; } _info->dump(); @@ -1176,15 +1177,17 @@ static inline LifeTimeInterval createFixedInterval(int rangeCount) return i; } -static inline LifeTimeInterval cloneFixedInterval(int reg, bool isFP, LifeTimeInterval lti) +LifeTimeInterval *RegisterAllocator::cloneFixedInterval(int reg, bool isFP, const LifeTimeInterval &original) { - lti.setReg(reg); - lti.setFixedInterval(true); + LifeTimeInterval *lti = new LifeTimeInterval(original); + _lifeTimeIntervals->add(lti); + lti->setReg(reg); + lti->setFixedInterval(true); Temp t; t.init(Temp::PhysicalRegister, reg); t.type = isFP ? IR::DoubleType : IR::SInt32Type; - lti.setTemp(t); + lti->setTemp(t); return lti; } @@ -1198,18 +1201,18 @@ void RegisterAllocator::prepareRanges() const int regCount = _normalRegisters.size(); _fixedRegisterRanges.reserve(regCount); for (int reg = 0; reg < regCount; ++reg) { - LifeTimeInterval lti = cloneFixedInterval(reg, false, ltiWithCalls); + LifeTimeInterval *lti = cloneFixedInterval(reg, false, ltiWithCalls); _fixedRegisterRanges.append(lti); - if (lti.isValid()) + if (lti->isValid()) _active.append(lti); } const int fpRegCount = _fpRegisters.size(); _fixedFPRegisterRanges.reserve(fpRegCount); for (int fpReg = 0; fpReg < fpRegCount; ++fpReg) { - LifeTimeInterval lti = cloneFixedInterval(fpReg, true, ltiWithCalls); + LifeTimeInterval *lti = cloneFixedInterval(fpReg, true, ltiWithCalls); _fixedFPRegisterRanges.append(lti); - if (lti.isValid()) + if (lti->isValid()) _active.append(lti); } } @@ -1217,18 +1220,18 @@ void RegisterAllocator::prepareRanges() void RegisterAllocator::linearScan() { while (!_unhandled.isEmpty()) { - LifeTimeInterval current = _unhandled.first(); - _unhandled.removeFirst(); - int position = current.start(); + LifeTimeInterval *current = _unhandled.back(); + _unhandled.pop_back(); + int position = current->start(); // check for intervals in active that are handled or inactive for (int i = 0; i < _active.size(); ) { - const LifeTimeInterval &it = _active.at(i); - if (it.end() < position) { - if (!it.isFixedInterval()) + LifeTimeInterval *it = _active.at(i); + if (it->end() < position) { + if (!it->isFixedInterval()) _handled += it; _active.remove(i); - } else if (!it.covers(position)) { + } else if (!it->covers(position)) { _inactive += it; _active.remove(i); } else { @@ -1238,13 +1241,13 @@ void RegisterAllocator::linearScan() // check for intervals in inactive that are handled or active for (int i = 0; i < _inactive.size(); ) { - const LifeTimeInterval &it = _inactive.at(i); - if (it.end() < position) { - if (!it.isFixedInterval()) + LifeTimeInterval *it = _inactive.at(i); + if (it->end() < position) { + if (!it->isFixedInterval()) _handled += it; _inactive.remove(i); - } else if (it.covers(position)) { - if (it.reg() != LifeTimeInterval::Invalid) { + } else if (it->covers(position)) { + if (it->reg() != LifeTimeInterval::Invalid) { _active += it; _inactive.remove(i); } else { @@ -1257,33 +1260,33 @@ void RegisterAllocator::linearScan() } } - Q_ASSERT(!current.isFixedInterval()); + Q_ASSERT(!current->isFixedInterval()); #ifdef DEBUG_REGALLOC qDebug() << "** Position" << position; #endif // DEBUG_REGALLOC - if (_info->canHaveRegister(current.temp())) { - tryAllocateFreeReg(current, position); - if (current.reg() == LifeTimeInterval::Invalid) - allocateBlockedReg(current, position); - if (current.reg() != LifeTimeInterval::Invalid) + if (_info->canHaveRegister(current->temp())) { + tryAllocateFreeReg(*current, position); + if (current->reg() == LifeTimeInterval::Invalid) + allocateBlockedReg(*current, position); + if (current->reg() != LifeTimeInterval::Invalid) _active += current; } else { - assignSpillSlot(current.temp(), current.start(), current.end()); + assignSpillSlot(current->temp(), current->start(), current->end()); _inactive += current; if (DebugRegAlloc) - qDebug() << "*** allocating stack slot" << _assignedSpillSlots[current.temp()] - << "for %" << current.temp().index << "as it cannot be loaded in a register"; + qDebug() << "*** allocating stack slot" << _assignedSpillSlots[current->temp()] + << "for %" << current->temp().index << "as it cannot be loaded in a register"; } } - foreach (const LifeTimeInterval &r, _active) - if (!r.isFixedInterval()) + foreach (LifeTimeInterval *r, _active) + if (!r->isFixedInterval()) _handled.append(r); _active.clear(); - foreach (const LifeTimeInterval &r, _inactive) - if (!r.isFixedInterval()) + foreach (LifeTimeInterval *r, _inactive) + if (!r->isFixedInterval()) _handled.append(r); _inactive.clear(); } @@ -1319,30 +1322,30 @@ void RegisterAllocator::tryAllocateFreeReg(LifeTimeInterval ¤t, const int Q_ASSERT(freeUntilPos.size() > 0); const bool isPhiTarget = _info->isPhiTarget(current.temp()); - foreach (const LifeTimeInterval &it, _active) { - if (it.isFP() == needsFPReg) { - if (!isPhiTarget && it.isFixedInterval() && !current.isSplitFromInterval()) { - const int idx = indexOfRangeCoveringPosition(it.ranges(), position); - if (it.ranges().at(idx).end == current.start()) { - if (it.ranges().size() > idx + 1) - freeUntilPos[it.reg()] = it.ranges().at(idx + 1).start; + foreach (const LifeTimeInterval *it, _active) { + if (it->isFP() == needsFPReg) { + if (!isPhiTarget && it->isFixedInterval() && !current.isSplitFromInterval()) { + const int idx = indexOfRangeCoveringPosition(it->ranges(), position); + if (it->ranges().at(idx).end == current.start()) { + if (it->ranges().size() > idx + 1) + freeUntilPos[it->reg()] = it->ranges().at(idx + 1).start; continue; } } - if (isPhiTarget || it.end() >= current.firstPossibleUsePosition(isPhiTarget)) - freeUntilPos[it.reg()] = 0; // mark register as unavailable + if (isPhiTarget || it->end() >= current.firstPossibleUsePosition(isPhiTarget)) + freeUntilPos[it->reg()] = 0; // mark register as unavailable } } - foreach (const LifeTimeInterval &it, _inactive) { - if (current.isSplitFromInterval() || it.isFixedInterval()) { - if (it.isFP() == needsFPReg && it.reg() != LifeTimeInterval::Invalid) { - const int intersectionPos = nextIntersection(current, it, position); - if (!isPhiTarget && it.isFixedInterval() && current.end() == intersectionPos) - freeUntilPos[it.reg()] = qMin(freeUntilPos[it.reg()], intersectionPos + 1); + foreach (const LifeTimeInterval *it, _inactive) { + if (current.isSplitFromInterval() || it->isFixedInterval()) { + if (it->isFP() == needsFPReg && it->reg() != LifeTimeInterval::Invalid) { + const int intersectionPos = nextIntersection(current, *it, position); + if (!isPhiTarget && it->isFixedInterval() && current.end() == intersectionPos) + freeUntilPos[it->reg()] = qMin(freeUntilPos[it->reg()], intersectionPos + 1); else if (intersectionPos != -1) - freeUntilPos[it.reg()] = qMin(freeUntilPos[it.reg()], intersectionPos); + freeUntilPos[it->reg()] = qMin(freeUntilPos[it->reg()], intersectionPos); } } } @@ -1402,7 +1405,7 @@ void RegisterAllocator::allocateBlockedReg(LifeTimeInterval ¤t, const int const bool isPhiTarget = _info->isPhiTarget(current.temp()); if (isPhiTarget && !current.isSplitFromInterval()) { split(current, position + 1, true); - _inactive.append(current); + _inactive.append(¤t); return; } @@ -1414,7 +1417,7 @@ void RegisterAllocator::allocateBlockedReg(LifeTimeInterval ¤t, const int const bool definedAtCurrentPosition = !current.isSplitFromInterval() && current.start() == position; for (int i = 0, ei = _active.size(); i != ei; ++i) { - LifeTimeInterval &it = _active[i]; + LifeTimeInterval &it = *_active[i]; if (it.isFP() == needsFPReg) { int nu = it.isFixedInterval() ? 0 : nextUse(it.temp(), current.firstPossibleUsePosition(isPhiTarget)); if (nu == position && !definedAtCurrentPosition) { @@ -1430,7 +1433,7 @@ void RegisterAllocator::allocateBlockedReg(LifeTimeInterval ¤t, const int } for (int i = 0, ei = _inactive.size(); i != ei; ++i) { - LifeTimeInterval &it = _inactive[i]; + LifeTimeInterval &it = *_inactive[i]; if (current.isSplitFromInterval() || it.isFixedInterval()) { if (it.isFP() == needsFPReg && it.reg() != LifeTimeInterval::Invalid) { if (nextIntersection(current, it, position) != -1) { @@ -1455,7 +1458,7 @@ void RegisterAllocator::allocateBlockedReg(LifeTimeInterval ¤t, const int } Q_ASSERT(!_info->useMustHaveReg(current.temp(), position)); split(current, position + 1, true); - _inactive.append(current); + _inactive.append(¤t); } else { // spill intervals that currently block reg if (DebugRegAlloc) { @@ -1481,8 +1484,8 @@ void RegisterAllocator::allocateBlockedReg(LifeTimeInterval ¤t, const int splitInactiveAtEndOfLifetimeHole(reg, needsFPReg, position); // make sure that current does not intersect with the fixed interval for reg - const LifeTimeInterval &fixedRegRange = needsFPReg ? _fixedFPRegisterRanges.at(reg) - : _fixedRegisterRanges.at(reg); + const LifeTimeInterval &fixedRegRange = needsFPReg ? *_fixedFPRegisterRanges.at(reg) + : *_fixedRegisterRanges.at(reg); int ni = nextIntersection(current, fixedRegRange, position); if (ni != -1) { if (DebugRegAlloc) { @@ -1550,16 +1553,16 @@ int RegisterAllocator::nextUse(const Temp &t, int startPosition) const return -1; } -static inline void insertSorted(QVector &intervals, const LifeTimeInterval &newInterval) +static inline void insertReverseSorted(QVector &intervals, LifeTimeInterval *newInterval) { - newInterval.validate(); - for (int i = 0, ei = intervals.size(); i != ei; ++i) { - if (LifeTimeInterval::lessThan(newInterval, intervals.at(i))) { - intervals.insert(i, newInterval); + newInterval->validate(); + for (int i = intervals.size(); i > 0;) { + if (LifeTimeInterval::lessThan(newInterval, intervals.at(--i))) { + intervals.insert(i + 1, newInterval); return; } } - intervals.append(newInterval); + intervals.insert(0, newInterval); } void RegisterAllocator::split(LifeTimeInterval ¤t, int beforePosition, @@ -1616,14 +1619,16 @@ void RegisterAllocator::split(LifeTimeInterval ¤t, int beforePosition, if (current.reg() != LifeTimeInterval::Invalid) _info->addHint(current.temp(), current.reg()); newInterval.setReg(LifeTimeInterval::Invalid); - insertSorted(_unhandled, newInterval); + LifeTimeInterval *newIntervalPtr = new LifeTimeInterval(newInterval); + _lifeTimeIntervals->add(newIntervalPtr); + insertReverseSorted(_unhandled, newIntervalPtr); } } void RegisterAllocator::splitInactiveAtEndOfLifetimeHole(int reg, bool isFPReg, int position) { for (int i = 0, ei = _inactive.size(); i != ei; ++i) { - LifeTimeInterval &interval = _inactive[i]; + LifeTimeInterval &interval = *_inactive[i]; if (interval.isFixedInterval()) continue; if (isFPReg == interval.isFP() && interval.reg() == reg) { @@ -1663,10 +1668,10 @@ void RegisterAllocator::dump() const { qout << "Ranges:" << endl; - QVector handled = _handled; + QVector handled = _handled; std::sort(handled.begin(), handled.end(), LifeTimeInterval::lessThanForTemp); - foreach (const LifeTimeInterval &r, handled) { - r.dump(qout); + foreach (const LifeTimeInterval *r, handled) { + r->dump(qout); qout << endl; } } diff --git a/src/qml/jit/qv4regalloc_p.h b/src/qml/jit/qv4regalloc_p.h index 030fb4b..e1048cc 100644 --- a/src/qml/jit/qv4regalloc_p.h +++ b/src/qml/jit/qv4regalloc_p.h @@ -62,9 +62,10 @@ class RegisterAllocator QVector _fpRegisters; QScopedPointer _info; - QVector _fixedRegisterRanges, _fixedFPRegisterRanges; + QVector _fixedRegisterRanges, _fixedFPRegisterRanges; - QVector _unhandled, _active, _inactive, _handled; + IR::LifeTimeIntervals::Ptr _lifeTimeIntervals; + QVector _unhandled, _active, _inactive, _handled; QHash _lastAssignedRegister; QHash _assignedSpillSlots; @@ -79,6 +80,7 @@ public: void run(IR::Function *function, const IR::Optimizer &opt); private: + LifeTimeInterval *cloneFixedInterval(int reg, bool isFP, const LifeTimeInterval &original); void prepareRanges(); void linearScan(); void tryAllocateFreeReg(LifeTimeInterval ¤t, const int position);