V4 IR: lower the number of memory allocations.

By using vectors indexed on temp-id instead of hashes.

Also record the order in which intervals are removed from the list of
life ranges. This order is the inverse of the list of ranges sorted by
start position. So instead of building _sortedIntervals and then sorting
them, reverse iterating over the finished intervals will do the same.

This speeds up the interval calculation by 40%.

Change-Id: If3c78496d7ca2d0e23f0a51302dcd1094dad7d4a
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
This commit is contained in:
Erik Verbruggen 2014-05-12 11:24:08 +02:00 committed by The Qt Project
parent 6725bc8f16
commit 481447ae66
1 changed files with 51 additions and 24 deletions

View File

@ -3500,13 +3500,22 @@ void optimizeSSA(StatementWorklist &W, DefUses &defUses, DominatorTree &df)
} }
class InputOutputCollector: protected StmtVisitor, protected ExprVisitor { class InputOutputCollector: protected StmtVisitor, protected ExprVisitor {
void setOutput(Temp *out)
{
Q_ASSERT(!output);
output = out;
}
public: public:
QList<Temp> inputs; std::vector<Temp *> inputs;
QList<Temp> outputs; Temp *output;
InputOutputCollector()
{ inputs.reserve(4); }
void collect(Stmt *s) { void collect(Stmt *s) {
inputs.clear(); inputs.resize(0);
outputs.clear(); output = 0;
s->accept(this); s->accept(this);
} }
@ -3516,7 +3525,7 @@ protected:
virtual void visitRegExp(IR::RegExp *) {} virtual void visitRegExp(IR::RegExp *) {}
virtual void visitName(Name *) {} virtual void visitName(Name *) {}
virtual void visitTemp(Temp *e) { virtual void visitTemp(Temp *e) {
inputs.append(*e); inputs.push_back(e);
} }
virtual void visitArgLocal(ArgLocal *) {} virtual void visitArgLocal(ArgLocal *) {}
virtual void visitClosure(Closure *) {} virtual void visitClosure(Closure *) {}
@ -3539,7 +3548,7 @@ protected:
virtual void visitMove(Move *s) { virtual void visitMove(Move *s) {
s->source->accept(this); s->source->accept(this);
if (Temp *t = s->target->asTemp()) { if (Temp *t = s->target->asTemp()) {
outputs.append(*t); setOutput(t);
} else { } else {
s->target->accept(this); s->target->accept(this);
} }
@ -3567,28 +3576,40 @@ protected:
class LifeRanges { class LifeRanges {
typedef QSet<Temp> LiveRegs; typedef QSet<Temp> LiveRegs;
QVector<LiveRegs> _liveIn; std::vector<LiveRegs> _liveIn;
QHash<Temp, LifeTimeInterval> _intervals; std::vector<LifeTimeInterval *> _intervals;
std::vector<LifeTimeInterval *> _finishedIntervals;
typedef QVector<LifeTimeInterval> LifeTimeIntervals; typedef QVector<LifeTimeInterval> LifeTimeIntervals;
LifeTimeIntervals _sortedIntervals; LifeTimeIntervals _sortedIntervals;
LifeTimeInterval &interval(const Temp *temp)
{
LifeTimeInterval *&lti = _intervals[temp->index];
if (Q_UNLIKELY(!lti)) {
lti = new LifeTimeInterval;
lti->setTemp(*temp);
}
return *lti;
}
public: public:
LifeRanges(IR::Function *function, const QHash<BasicBlock *, BasicBlock *> &startEndLoops) LifeRanges(IR::Function *function, const QHash<BasicBlock *, BasicBlock *> &startEndLoops)
: _intervals(function->tempCount)
{ {
function->renumberForLifeRanges(); function->renumberForLifeRanges();
_liveIn.resize(function->basicBlockCount()); _liveIn.resize(function->basicBlockCount());
_finishedIntervals.reserve(function->tempCount);
for (int i = function->basicBlockCount() - 1; i >= 0; --i) { for (int i = function->basicBlockCount() - 1; i >= 0; --i) {
BasicBlock *bb = function->basicBlock(i); BasicBlock *bb = function->basicBlock(i);
buildIntervals(bb, startEndLoops.value(bb, 0)); buildIntervals(bb, startEndLoops.value(bb, 0));
} }
_sortedIntervals.reserve(_intervals.size()); _sortedIntervals.reserve(_finishedIntervals.size());
for (QHash<Temp, LifeTimeInterval>::const_iterator i = _intervals.begin(), ei = _intervals.end(); i != ei; ++i) { for (unsigned i = _finishedIntervals.size(); i > 0;)
LifeTimeIntervals::iterator lti = _sortedIntervals.insert(_sortedIntervals.end(), i.value()); if (LifeTimeInterval *lti = _finishedIntervals[--i])
lti->setTemp(i.key()); _sortedIntervals.append(*lti);
} qDeleteAll(_intervals);
std::sort(_sortedIntervals.begin(), _sortedIntervals.end(), LifeTimeInterval::lessThan);
_intervals.clear(); _intervals.clear();
} }
@ -3607,6 +3628,8 @@ public:
for (int i = 0, ei = _liveIn.size(); i != ei; ++i) { for (int i = 0, ei = _liveIn.size(); i != ei; ++i) {
qout << "L" << i <<" live-in: "; qout << "L" << i <<" live-in: ";
QList<Temp> live = QList<Temp>::fromSet(_liveIn.at(i)); QList<Temp> live = QList<Temp>::fromSet(_liveIn.at(i));
if (live.isEmpty())
qout << "(none)";
std::sort(live.begin(), live.end()); std::sort(live.begin(), live.end());
for (int i = 0; i < live.size(); ++i) { for (int i = 0; i < live.size(); ++i) {
if (i > 0) qout << ", "; if (i > 0) qout << ", ";
@ -3638,35 +3661,39 @@ private:
QVector<Stmt *> statements = bb->statements(); QVector<Stmt *> statements = bb->statements();
foreach (const Temp &opd, live) foreach (const Temp &opd, live)
_intervals[opd].addRange(statements.first()->id(), statements.last()->id()); interval(&opd).addRange(statements.first()->id(), statements.last()->id());
InputOutputCollector collector; InputOutputCollector collector;
for (int i = statements.size() - 1; i >= 0; --i) { for (int i = statements.size() - 1; i >= 0; --i) {
Stmt *s = statements[i]; Stmt *s = statements.at(i);
if (Phi *phi = s->asPhi()) { if (Phi *phi = s->asPhi()) {
LiveRegs::iterator it = live.find(*phi->targetTemp); LiveRegs::iterator it = live.find(*phi->targetTemp);
if (it == live.end()) { if (it == live.end()) {
// a phi node target that is only defined, but never used // a phi node target that is only defined, but never used
_intervals[*phi->targetTemp].setFrom(s); interval(phi->targetTemp).setFrom(s);
} else { } else {
live.erase(it); live.erase(it);
_finishedIntervals.push_back(&interval(phi->targetTemp));
} }
continue; continue;
} }
collector.collect(s); collector.collect(s);
foreach (const Temp &opd, collector.outputs) { if (Temp *opd = collector.output) {
_intervals[opd].setFrom(s); LifeTimeInterval &lti = interval(opd);
live.remove(opd); lti.setFrom(s);
live.remove(lti.temp());
_finishedIntervals.push_back(&lti);
} }
foreach (const Temp &opd, collector.inputs) { for (unsigned i = 0, ei = collector.inputs.size(); i != ei; ++i) {
_intervals[opd].addRange(statements.first()->id(), s->id()); Temp *opd = collector.inputs[i];
live.insert(opd); interval(opd).addRange(statements.first()->id(), s->id());
live.insert(*opd);
} }
} }
if (loopEnd) { // Meaning: bb is a loop header, because loopEnd is set to non-null. if (loopEnd) { // Meaning: bb is a loop header, because loopEnd is set to non-null.
foreach (const Temp &opd, live) foreach (const Temp &opd, live)
_intervals[opd].addRange(statements.first()->id(), loopEnd->terminator()->id()); interval(&opd).addRange(statements.first()->id(), loopEnd->terminator()->id());
} }
_liveIn[bb->index()] = live; _liveIn[bb->index()] = live;