aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler/qv4regalloc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/compiler/qv4regalloc.cpp')
-rw-r--r--src/qml/compiler/qv4regalloc.cpp162
1 files changed, 89 insertions, 73 deletions
diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp
index 65685f1148..7996b134a1 100644
--- a/src/qml/compiler/qv4regalloc.cpp
+++ b/src/qml/compiler/qv4regalloc.cpp
@@ -127,7 +127,7 @@ public:
return _defs[t].isPhiTarget;
}
- QList<int> calls() const { return _calls; }
+ const QList<int> &calls() const { return _calls; }
QList<Temp> hints(const Temp &t) const { return _hints[t]; }
void addHint(const Temp &t, int physicalRegister)
{
@@ -661,13 +661,14 @@ using namespace QT_PREPEND_NAMESPACE(QQmlJS);
namespace {
class ResolutionPhase: protected StmtVisitor, protected ExprVisitor {
- QVector<LifeTimeInterval> _intervals;
+ const QVector<LifeTimeInterval> &_intervals;
+ QVector<const LifeTimeInterval *> _unprocessed;
Function *_function;
#if !defined(QT_NO_DEBUG)
RegAllocInfo *_info;
#endif
const QHash<V4IR::Temp, int> &_assignedSpillSlots;
- QHash<V4IR::Temp, LifeTimeInterval> _intervalForTemp;
+ QHash<V4IR::Temp, const LifeTimeInterval *> _intervalForTemp;
const QVector<int> &_intRegs;
const QVector<int> &_fpRegs;
@@ -675,8 +676,8 @@ class ResolutionPhase: protected StmtVisitor, protected ExprVisitor {
QVector<Move *> _loads;
QVector<Move *> _stores;
- QHash<BasicBlock *, QList<LifeTimeInterval> > _liveAtStart;
- QHash<BasicBlock *, QList<LifeTimeInterval> > _liveAtEnd;
+ QHash<BasicBlock *, QList<const LifeTimeInterval *> > _liveAtStart;
+ QHash<BasicBlock *, QList<const LifeTimeInterval *> > _liveAtEnd;
public:
ResolutionPhase(const QVector<LifeTimeInterval> &intervals, Function *function, RegAllocInfo *info,
@@ -694,6 +695,13 @@ public:
#if defined(QT_NO_DEBUG)
Q_UNUSED(info)
#endif
+
+ _unprocessed.resize(_intervals.size());
+ for (int i = 0, ei = _intervals.size(); i != ei; ++i)
+ _unprocessed[i] = &_intervals[i];
+
+ _liveAtStart.reserve(function->basicBlocks.size());
+ _liveAtEnd.reserve(function->basicBlocks.size());
}
void run() {
@@ -707,6 +715,7 @@ private:
{
foreach (BasicBlock *bb, _function->basicBlocks) {
QVector<Stmt *> newStatements;
+ newStatements.reserve(bb->statements.size() + 7);
bool seenFirstNonPhiStmt = false;
for (int i = 0, ei = bb->statements.size(); i != ei; ++i) {
@@ -757,22 +766,22 @@ private:
}
- void activate(const LifeTimeInterval &i)
+ void activate(const LifeTimeInterval *i)
{
- Q_ASSERT(!i.isFixedInterval());
- _intervalForTemp[i.temp()] = i;
+ Q_ASSERT(!i->isFixedInterval());
+ _intervalForTemp[i->temp()] = i;
- if (i.reg() != LifeTimeInterval::Invalid) {
+ if (i->reg() != LifeTimeInterval::Invalid) {
// check if we need to generate spill/unspill instructions
- if (i.start() == _currentStmt->id) {
- if (i.isSplitFromInterval()) {
- int pReg = platformRegister(i);
- _loads.append(generateUnspill(i.temp(), pReg));
+ if (i->start() == _currentStmt->id) {
+ if (i->isSplitFromInterval()) {
+ int pReg = platformRegister(*i);
+ _loads.append(generateUnspill(i->temp(), pReg));
} else {
- int pReg = platformRegister(i);
- int spillSlot = _assignedSpillSlots.value(i.temp(), -1);
+ int pReg = platformRegister(*i);
+ int spillSlot = _assignedSpillSlots.value(i->temp(), -1);
if (spillSlot != -1)
- _stores.append(generateSpill(spillSlot, i.temp().type, pReg));
+ _stores.append(generateSpill(spillSlot, i->temp().type, pReg));
}
}
}
@@ -782,37 +791,37 @@ private:
{
if (Phi *phi = _currentStmt->asPhi()) {
// for phi nodes, only activate the range belonging to that node
- for (int it = 0, eit = _intervals.size(); it != eit; ++it) {
- const LifeTimeInterval &i = _intervals.at(it);
- if (i.start() > _currentStmt->id)
+ for (int it = 0, eit = _unprocessed.size(); it != eit; ++it) {
+ const LifeTimeInterval *i = _unprocessed.at(it);
+ if (i->start() > _currentStmt->id)
break;
- if (i.temp() == *phi->targetTemp) {
+ if (i->temp() == *phi->targetTemp) {
activate(i);
- _intervals.remove(it);
+ _unprocessed.remove(it);
break;
}
}
return;
}
- while (!_intervals.isEmpty()) {
- const LifeTimeInterval &i = _intervals.first();
- if (i.start() > _currentStmt->id)
+ while (!_unprocessed.isEmpty()) {
+ const LifeTimeInterval *i = _unprocessed.first();
+ if (i->start() > _currentStmt->id)
break;
activate(i);
- _intervals.removeFirst();
+ _unprocessed.removeFirst();
}
}
void cleanOldIntervals()
{
const int id = _currentStmt->id;
- QMutableHashIterator<Temp, LifeTimeInterval> it(_intervalForTemp);
+ QMutableHashIterator<Temp, const LifeTimeInterval *> it(_intervalForTemp);
while (it.hasNext()) {
- const LifeTimeInterval &i = it.next().value();
- if (i.end() < id || i.isFixedInterval())
+ const LifeTimeInterval *i = it.next().value();
+ if (i->end() < id || i->isFixedInterval())
it.remove();
}
}
@@ -820,19 +829,15 @@ private:
void resolve()
{
foreach (BasicBlock *bb, _function->basicBlocks) {
- foreach (BasicBlock *bbOut, bb->out) {
-#ifdef DEBUG_REGALLOC
- Optimizer::showMeTheCode(_function);
-#endif // DEBUG_REGALLOC
-
+ foreach (BasicBlock *bbOut, bb->out)
resolveEdge(bb, bbOut);
- }
}
}
void resolveEdge(BasicBlock *predecessor, BasicBlock *successor)
{
#ifdef DEBUG_REGALLOC
+ Optimizer::showMeTheCode(_function);
qDebug() << "Resolving edge" << predecessor->index << "->" << successor->index;
#endif // DEBUG_REGALLOC
@@ -851,17 +856,21 @@ private:
Q_ASSERT(successorStart > 0);
- foreach (const LifeTimeInterval &it, _liveAtStart[successor]) {
- bool lifeTimeHole = false;
- if (it.end() < successorStart)
+ foreach (const LifeTimeInterval *it, _liveAtStart[successor]) {
+ if (it->end() < successorStart)
continue;
+
+ bool lifeTimeHole = false;
+ bool isPhiTarget = false;
Expr *moveFrom = 0;
- if (it.start() == successorStart) {
+
+ if (it->start() == successorStart) {
foreach (Stmt *s, successor->statements) {
if (!s || s->id < 1)
continue;
if (Phi *phi = s->asPhi()) {
- if (*phi->targetTemp == it.temp()) {
+ if (*phi->targetTemp == it->temp()) {
+ isPhiTarget = true;
Expr *opd = phi->d->incoming[successor->in.indexOf(predecessor)];
if (opd->asConst()) {
moveFrom = opd;
@@ -869,12 +878,12 @@ private:
Temp *t = opd->asTemp();
Q_ASSERT(t);
- foreach (const LifeTimeInterval &it2, _liveAtEnd[predecessor]) {
- if (it2.temp() == *t
- && it2.reg() != LifeTimeInterval::Invalid
- && it2.covers(predecessorEnd)) {
+ foreach (const LifeTimeInterval *it2, _liveAtEnd[predecessor]) {
+ if (it2->temp() == *t
+ && it2->reg() != LifeTimeInterval::Invalid
+ && it2->covers(predecessorEnd)) {
moveFrom = createTemp(Temp::PhysicalRegister,
- platformRegister(it2), t->type);
+ platformRegister(*it2), t->type);
break;
}
}
@@ -889,18 +898,18 @@ private:
}
}
} else {
- foreach (const LifeTimeInterval &predIt, _liveAtEnd[predecessor]) {
- if (predIt.temp() == it.temp()) {
- if (predIt.reg() != LifeTimeInterval::Invalid
- && predIt.covers(predecessorEnd)) {
- moveFrom = createTemp(Temp::PhysicalRegister, platformRegister(predIt),
- predIt.temp().type);
+ foreach (const LifeTimeInterval *predIt, _liveAtEnd[predecessor]) {
+ if (predIt->temp() == it->temp()) {
+ if (predIt->reg() != LifeTimeInterval::Invalid
+ && predIt->covers(predecessorEnd)) {
+ moveFrom = createTemp(Temp::PhysicalRegister, platformRegister(*predIt),
+ predIt->temp().type);
} else {
- int spillSlot = _assignedSpillSlots.value(predIt.temp(), -1);
+ int spillSlot = _assignedSpillSlots.value(predIt->temp(), -1);
if (spillSlot == -1)
lifeTimeHole = true;
else
- moveFrom = createTemp(Temp::StackSlot, spillSlot, predIt.temp().type);
+ moveFrom = createTemp(Temp::StackSlot, spillSlot, predIt->temp().type);
}
break;
}
@@ -909,20 +918,20 @@ private:
if (!moveFrom) {
Q_UNUSED(lifeTimeHole);
#if !defined(QT_NO_DEBUG)
- Q_ASSERT(!_info->isPhiTarget(it.temp()) || it.isSplitFromInterval() || lifeTimeHole);
- if (_info->def(it.temp()) != successorStart && !it.isSplitFromInterval()) {
+ Q_ASSERT(!_info->isPhiTarget(it->temp()) || it->isSplitFromInterval() || lifeTimeHole);
+ if (_info->def(it->temp()) != successorStart && !it->isSplitFromInterval()) {
const int successorEnd = successor->statements.last()->id;
const int idx = successor->in.indexOf(predecessor);
- foreach (const Use &use, _info->uses(it.temp())) {
+ foreach (const Use &use, _info->uses(it->temp())) {
if (use.pos == static_cast<unsigned>(successorStart)) {
// only check the current edge, not all other possible ones. This is
// important for phi nodes: they have uses that are only valid when
// coming in over a specific edge.
foreach (Stmt *s, successor->statements) {
if (Phi *phi = s->asPhi()) {
- Q_ASSERT(it.temp().index != phi->targetTemp->index);
+ Q_ASSERT(it->temp().index != phi->targetTemp->index);
Q_ASSERT(phi->d->incoming[idx]->asTemp() == 0
- || it.temp().index != phi->d->incoming[idx]->asTemp()->index);
+ || it->temp().index != phi->d->incoming[idx]->asTemp()->index);
} else {
// TODO: check that the first non-phi statement does not use
// the temp.
@@ -941,13 +950,18 @@ private:
}
Temp *moveTo;
- if (it.reg() == LifeTimeInterval::Invalid || !it.covers(successorStart)) {
- int spillSlot = _assignedSpillSlots.value(it.temp(), -1);
+ if (it->reg() == LifeTimeInterval::Invalid || !it->covers(successorStart)) {
+ if (!isPhiTarget) // if it->temp() is a phi target, skip it.
+ continue;
+ const int spillSlot = _assignedSpillSlots.value(it->temp(), -1);
if (spillSlot == -1)
continue; // it has a life-time hole here.
- moveTo = createTemp(Temp::StackSlot, spillSlot, it.temp().type);
+ moveTo = createTemp(Temp::StackSlot, spillSlot, it->temp().type);
} else {
- moveTo = createTemp(Temp::PhysicalRegister, platformRegister(it), it.temp().type);
+ moveTo = createTemp(Temp::PhysicalRegister, platformRegister(*it), it->temp().type);
+ const int spillSlot = _assignedSpillSlots.value(it->temp(), -1);
+ if (isPhiTarget && spillSlot != -1)
+ mapping.add(moveFrom, createTemp(Temp::StackSlot, spillSlot, it->temp().type));
}
// add move to mapping
@@ -1008,10 +1022,10 @@ protected:
if (t->kind != Temp::VirtualRegister)
return;
- const LifeTimeInterval &i = _intervalForTemp[*t];
- Q_ASSERT(i.isValid());
- if (i.reg() != LifeTimeInterval::Invalid && i.covers(_currentStmt->id)) {
- int pReg = platformRegister(i);
+ const LifeTimeInterval *i = _intervalForTemp[*t];
+ Q_ASSERT(i->isValid());
+ if (i->reg() != LifeTimeInterval::Invalid && i->covers(_currentStmt->id)) {
+ int pReg = platformRegister(*i);
t->kind = Temp::PhysicalRegister;
t->index = pReg;
} else {
@@ -1081,7 +1095,7 @@ void RegisterAllocator::run(Function *function, const Optimizer &opt)
{
QTextStream qout(stdout, QIODevice::WriteOnly);
qout << "Ranges:" << endl;
- QList<LifeTimeInterval> intervals = _unhandled;
+ QVector<LifeTimeInterval> intervals = _unhandled;
std::sort(intervals.begin(), intervals.end(), LifeTimeInterval::lessThanForTemp);
foreach (const LifeTimeInterval &r, intervals) {
r.dump(qout);
@@ -1117,7 +1131,7 @@ void RegisterAllocator::run(Function *function, const Optimizer &opt)
#endif // DEBUG_REGALLOC
}
-static inline LifeTimeInterval createFixedInterval(int reg, bool isFP)
+static inline LifeTimeInterval createFixedInterval(int reg, bool isFP, int rangeCount)
{
Temp t;
t.init(Temp::PhysicalRegister, reg, 0);
@@ -1126,6 +1140,7 @@ static inline LifeTimeInterval createFixedInterval(int reg, bool isFP)
i.setTemp(t);
i.setReg(reg);
i.setFixedInterval(true);
+ i.reserveRanges(rangeCount);
return i;
}
@@ -1134,12 +1149,13 @@ void RegisterAllocator::prepareRanges()
const int regCount = _normalRegisters.size();
_fixedRegisterRanges.resize(regCount);
for (int reg = 0; reg < regCount; ++reg)
- _fixedRegisterRanges[reg] = createFixedInterval(reg, false);
+ _fixedRegisterRanges[reg] = createFixedInterval(reg, false, _info->calls().size());
const int fpRegCount = _fpRegisters.size();
_fixedFPRegisterRanges.resize(fpRegCount);
- for (int fpReg = 0; fpReg < fpRegCount; ++fpReg)
- _fixedFPRegisterRanges[fpReg] = createFixedInterval(fpReg, true);
+ for (int fpReg = 0; fpReg < fpRegCount; ++fpReg) {
+ _fixedFPRegisterRanges[fpReg] = createFixedInterval(fpReg, true, _info->calls().size());
+ }
foreach (int callPosition, _info->calls()) {
for (int reg = 0; reg < regCount; ++reg)
@@ -1451,9 +1467,9 @@ int RegisterAllocator::nextIntersection(const LifeTimeInterval &current,
return -1;
for (int currentEnd = currentRanges.size(); currentIt < currentEnd; ++currentIt) {
- const LifeTimeInterval::Range &currentRange = currentRanges[currentIt];
+ const LifeTimeInterval::Range currentRange = currentRanges.at(currentIt);
for (int anotherIt = anotherItStart, anotherEnd = anotherRanges.size(); anotherIt < anotherEnd; ++anotherIt) {
- const LifeTimeInterval::Range &anotherRange = anotherRanges[anotherIt];
+ const LifeTimeInterval::Range anotherRange = anotherRanges.at(anotherIt);
if (anotherRange.start > currentRange.end)
break;
int intersectPos = intersectionPosition(currentRange, anotherRange);
@@ -1588,7 +1604,7 @@ void RegisterAllocator::dump() const
{
qout << "Ranges:" << endl;
- QList<LifeTimeInterval> handled = _handled;
+ QVector<LifeTimeInterval> handled = _handled;
std::sort(handled.begin(), handled.end(), LifeTimeInterval::lessThanForTemp);
foreach (const LifeTimeInterval &r, handled) {
r.dump(qout);