diff options
Diffstat (limited to 'src/qml/compiler/qv4ssa.cpp')
-rw-r--r-- | src/qml/compiler/qv4ssa.cpp | 736 |
1 files changed, 393 insertions, 343 deletions
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index ca0bbb1bb3..84232a9ebb 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -54,9 +54,6 @@ #include <QtCore/QLinkedList> #include <QtCore/QStack> #include <qv4runtime_p.h> -#include <qv4context_p.h> -#include <private/qqmlpropertycache_p.h> -#include <private/qqmlengine_p.h> #include <cmath> #include <iostream> #include <cassert> @@ -82,11 +79,11 @@ void showMeTheCode(IR::Function *function) QVector<Stmt *> code; QHash<Stmt *, BasicBlock *> leader; - foreach (BasicBlock *block, function->basicBlocks) { - if (block->statements.isEmpty()) + foreach (BasicBlock *block, function->basicBlocks()) { + if (block->isRemoved() || block->isEmpty()) continue; - leader.insert(block->statements.first(), block); - foreach (Stmt *s, block->statements) { + leader.insert(block->statements().first(), block); + foreach (Stmt *s, block->statements()) { code.append(s); } } @@ -118,11 +115,11 @@ void showMeTheCode(IR::Function *function) qout << endl; QByteArray str; str.append('L'); - str.append(QByteArray::number(bb->index)); + str.append(QByteArray::number(bb->index())); str.append(':'); if (bb->catchBlock) { str.append(" (exception handler L"); - str.append(QByteArray::number(bb->catchBlock->index)); + str.append(QByteArray::number(bb->catchBlock->index())); str.append(')'); } for (int i = 66 - str.length(); i; --i) @@ -130,11 +127,11 @@ void showMeTheCode(IR::Function *function) qout << str; qout << "// predecessor blocks:"; foreach (BasicBlock *in, bb->in) - qout << " L" << in->index; + qout << " L" << in->index(); if (bb->in.isEmpty()) qout << "(none)"; if (BasicBlock *container = bb->containingGroup()) - qout << "; container block: L" << container->index; + qout << "; container block: L" << container->index(); if (bb->isGroupStart()) qout << "; group start"; qout << endl; @@ -161,7 +158,7 @@ void showMeTheCode(IR::Function *function) qout << endl; if (n && s->asCJump()) { - qout << " else goto L" << s->asCJump()->iffalse->index << ";" << endl; + qout << " else goto L" << s->asCJump()->iffalse->index() << ";" << endl; } } @@ -175,24 +172,21 @@ class ProcessedBlocks QBitArray processed; public: - ProcessedBlocks(const QVector<BasicBlock *> allBlocks) + ProcessedBlocks(IR::Function *function) { - int maxBB = 0; - foreach (BasicBlock *bb, allBlocks) - maxBB = qMax(maxBB, bb->index); - processed = QBitArray(maxBB + 1, false); + processed = QBitArray(function->basicBlockCount(), false); } bool alreadyProcessed(BasicBlock *bb) const { Q_ASSERT(bb); - return processed.at(bb->index); + return processed.at(bb->index()); } void markAsProcessed(BasicBlock *bb) { - processed.setBit(bb->index); + processed.setBit(bb->index()); } }; @@ -226,7 +220,7 @@ class BasicBlockSet Numbers *blockNumbers; Flags *blockFlags; - QVector<BasicBlock *> allBlocks; + IR::Function *function; enum { MaxVectorCapacity = 8 }; // Q_DISABLE_COPY(BasicBlockSet); disabled because MSVC wants assignment operator for std::vector @@ -268,10 +262,10 @@ public: BasicBlock *operator*() const { if (set.blockNumbers) { - return set.allBlocks.at(*numberIt); + return set.function->basicBlock(*numberIt); } else { Q_ASSERT(flagIt <= INT_MAX); - return set.allBlocks.at(static_cast<int>(flagIt)); + return set.function->basicBlock(static_cast<int>(flagIt)); } } @@ -308,22 +302,23 @@ public: friend class const_iterator; public: - BasicBlockSet(): blockNumbers(0), blockFlags(0) {} + BasicBlockSet(): blockNumbers(0), blockFlags(0), function(0) {} #ifdef Q_COMPILER_RVALUE_REFS BasicBlockSet(BasicBlockSet &&other): blockNumbers(0), blockFlags(0) { std::swap(blockNumbers, other.blockNumbers); std::swap(blockFlags, other.blockFlags); - std::swap(allBlocks, other.allBlocks); + std::swap(function, other.function); } #endif // Q_COMPILER_RVALUE_REFS ~BasicBlockSet() { delete blockNumbers; delete blockFlags; } - void init(const QVector<BasicBlock *> &nodes) + void init(IR::Function *f) { - Q_ASSERT(allBlocks.isEmpty()); - allBlocks = nodes; + Q_ASSERT(!function); + Q_ASSERT(f); + function = f; blockNumbers = new Numbers; blockNumbers->reserve(MaxVectorCapacity); } @@ -331,25 +326,25 @@ public: void insert(BasicBlock *bb) { if (blockFlags) { - (*blockFlags)[bb->index] = true; + (*blockFlags)[bb->index()] = true; return; } for (std::vector<int>::const_iterator i = blockNumbers->begin(), ei = blockNumbers->end(); i != ei; ++i) - if (*i == bb->index) + if (*i == bb->index()) return; if (blockNumbers->size() == MaxVectorCapacity) { - blockFlags = new Flags(allBlocks.size(), false); + blockFlags = new Flags(function->basicBlockCount(), false); for (std::vector<int>::const_iterator i = blockNumbers->begin(), ei = blockNumbers->end(); i != ei; ++i) blockFlags->operator[](*i) = true; delete blockNumbers; blockNumbers = 0; - blockFlags->operator[](bb->index) = true; + blockFlags->operator[](bb->index()) = true; } else { - blockNumbers->push_back(bb->index); + blockNumbers->push_back(bb->index()); } } @@ -371,7 +366,7 @@ class DominatorTree { typedef int BasicBlockIndex; enum { InvalidBasicBlockIndex = -1 }; - QVector<BasicBlock *> nodes; + IR::Function *function; int N; std::vector<int> dfnum; // BasicBlock index -> dfnum std::vector<int> vertex; @@ -410,12 +405,12 @@ class DominatorTree { vertex[N] = n; parent[n] = todo.parent; ++N; - const QVector<BasicBlock *> &out = nodes[n]->out; + const QVector<BasicBlock *> &out = function->basicBlock(n)->out; for (int i = out.size() - 1; i > 0; --i) - worklist.push_back(DFSTodo(out[i]->index, n)); + worklist.push_back(DFSTodo(out[i]->index(), n)); if (out.size() > 0) { - todo.node = out.first()->index; + todo.node = out.first()->index(); todo.parent = n; continue; } @@ -463,21 +458,23 @@ class DominatorTree { } void calculateIDoms() { - Q_ASSERT(nodes.first()->in.isEmpty()); - - vertex = std::vector<int>(nodes.size(), InvalidBasicBlockIndex); - parent = std::vector<int>(nodes.size(), InvalidBasicBlockIndex); - dfnum = std::vector<int>(nodes.size(), 0); - semi = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex); - ancestor = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex); - idom = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex); - samedom = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex); - best = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex); + Q_ASSERT(function->basicBlock(0)->in.isEmpty()); + + const int bbCount = function->basicBlockCount(); + vertex = std::vector<int>(bbCount, InvalidBasicBlockIndex); + parent = std::vector<int>(bbCount, InvalidBasicBlockIndex); + dfnum = std::vector<int>(bbCount, 0); + semi = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex); + ancestor = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex); + idom = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex); + samedom = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex); + best = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex); QHash<BasicBlockIndex, std::vector<BasicBlockIndex> > bucket; + bucket.reserve(bbCount); - DFS(nodes.first()->index); - Q_ASSERT(N == nodes.size()); // fails with unreachable nodes, but those should have been removed before. + DFS(function->basicBlock(0)->index()); + Q_ASSERT(N == function->liveBasicBlocksCount()); std::vector<BasicBlockIndex> worklist; worklist.reserve(vertex.capacity() / 2); @@ -487,12 +484,12 @@ class DominatorTree { BasicBlockIndex p = parent[n]; BasicBlockIndex s = p; - foreach (BasicBlock *v, nodes.at(n)->in) { + foreach (BasicBlock *v, function->basicBlock(n)->in) { BasicBlockIndex ss = InvalidBasicBlockIndex; - if (dfnum[v->index] <= dfnum[n]) - ss = v->index; + if (dfnum[v->index()] <= dfnum[n]) + ss = v->index(); else - ss = semi[ancestorWithLowestSemi(v->index, worklist)]; + ss = semi[ancestorWithLowestSemi(v->index(), worklist)]; if (dfnum[ss] < dfnum[s]) s = ss; } @@ -540,6 +537,7 @@ class DominatorTree { qout << "(none)"; qout << " -> " << to->index << endl; } + qout << "N = " << N << endl; #endif // SHOW_SSA } @@ -551,10 +549,12 @@ class DominatorTree { void computeDF() { // compute children of each node in the dominator tree std::vector<std::vector<BasicBlockIndex> > children; // BasicBlock index -> children - children.resize(nodes.size()); - foreach (BasicBlock *n, nodes) { - const BasicBlockIndex nodeIndex = n->index; - Q_ASSERT(nodes.at(nodeIndex) == n); + children.resize(function->basicBlockCount()); + foreach (BasicBlock *n, function->basicBlocks()) { + if (n->isRemoved()) + continue; + const BasicBlockIndex nodeIndex = n->index(); + Q_ASSERT(function->basicBlock(nodeIndex) == n); const BasicBlockIndex nodeDominator = idom[nodeIndex]; if (nodeDominator == InvalidBasicBlockIndex) continue; // there is no dominator to add this node to as a child (e.g. the start node) @@ -563,18 +563,20 @@ class DominatorTree { // Fill the worklist and initialize the node status for each basic-block QHash<BasicBlockIndex, NodeProgress> nodeStatus; - nodeStatus.reserve(nodes.size()); + nodeStatus.reserve(function->basicBlockCount()); std::vector<BasicBlockIndex> worklist; - worklist.reserve(nodes.size() * 2); - for (int i = 0, ei = nodes.size(); i != ei; ++i) { - BasicBlockIndex nodeIndex = nodes.at(i)->index; + worklist.reserve(function->basicBlockCount() * 2); + foreach (BasicBlock *bb, function->basicBlocks()) { + if (bb->isRemoved()) + continue; + BasicBlockIndex nodeIndex = bb->index(); worklist.push_back(nodeIndex); NodeProgress &np = nodeStatus[nodeIndex]; np.children = children[nodeIndex]; np.todo = children[nodeIndex]; } - std::vector<bool> DF_done(nodes.size(), false); + std::vector<bool> DF_done(function->basicBlockCount(), false); while (!worklist.empty()) { BasicBlockIndex node = worklist.back(); @@ -597,16 +599,16 @@ class DominatorTree { if (np.todo.empty()) { BasicBlockSet &S = DF[node]; - S.init(nodes); - foreach (BasicBlock *y, nodes.at(node)->out) - if (idom[y->index] != node) + S.init(function); + foreach (BasicBlock *y, function->basicBlock(node)->out) + if (idom[y->index()] != node) S.insert(y); foreach (BasicBlockIndex child, np.children) { const BasicBlockSet &ws = DF[child]; for (BasicBlockSet::const_iterator it = ws.begin(), eit = ws.end(); it != eit; ++it) { BasicBlock *w = *it; - const BasicBlockIndex wIndex = w->index; - if (node == wIndex || !dominates(node, w->index)) + const BasicBlockIndex wIndex = w->index(); + if (node == wIndex || !dominates(node, w->index())) S.insert(w); } } @@ -651,21 +653,21 @@ class DominatorTree { } public: - DominatorTree(const QVector<BasicBlock *> &nodes) - : nodes(nodes) + DominatorTree(IR::Function *function) + : function(function) , N(0) { - DF.resize(nodes.size()); + DF.resize(function->basicBlockCount()); calculateIDoms(); computeDF(); } const BasicBlockSet &dominatorFrontier(BasicBlock *n) const { - return DF[n->index]; + return DF[n->index()]; } BasicBlock *immediateDominator(BasicBlock *bb) const { - return nodes[idom[bb->index]]; + return function->basicBlock(idom[bb->index()]); } void dumpImmediateDominators() const @@ -680,46 +682,30 @@ public: void updateImmediateDominator(BasicBlock *bb, BasicBlock *newDominator) { - Q_ASSERT(bb->index >= 0); + Q_ASSERT(bb->index() >= 0); - int blockIndex; - if (static_cast<std::vector<BasicBlockIndex>::size_type>(bb->index) >= idom.size()) { + if (static_cast<std::vector<BasicBlockIndex>::size_type>(bb->index()) >= idom.size()) { // This is a new block, probably introduced by edge splitting. So, we'll have to grow // the array before inserting the immediate dominator. - nodes.append(bb); - idom.resize(nodes.size(), InvalidBasicBlockIndex); - blockIndex = nodes.size() - 1; - } else { - blockIndex = getBlockIndex(bb); + idom.resize(function->basicBlockCount(), InvalidBasicBlockIndex); } - idom[blockIndex] = getBlockIndex(newDominator); + idom[bb->index()] = newDominator->index(); } bool dominates(BasicBlock *dominator, BasicBlock *dominated) const { - // The index of the basic blocks might have changed, or the nodes array might have changed, - // so get the index from our copy of the array. - return dominates(getBlockIndex(dominator), getBlockIndex(dominated)); + return dominates(dominator->index(), dominated->index()); } private: - int getBlockIndex(BasicBlock *bb) const { - if (!bb) - return InvalidBasicBlockIndex; - - if (bb->index >= 0 && bb->index < nodes.size()) { - if (nodes.at(bb->index) == bb) - return bb->index; - } - - return nodes.indexOf(bb); - } - bool dominates(BasicBlockIndex dominator, BasicBlockIndex dominated) const { // dominator can be Invalid when the dominated block has no dominator (i.e. the start node) Q_ASSERT(dominated != InvalidBasicBlockIndex); - for (BasicBlockIndex it = dominated; it != InvalidBasicBlockIndex; it = idom[it]) { + if (dominator == dominated) + return false; + + for (BasicBlockIndex it = idom[dominated]; it != InvalidBasicBlockIndex; it = idom[it]) { if (it == dominator) return true; } @@ -729,8 +715,9 @@ private: }; class VariableCollector: public StmtVisitor, ExprVisitor { - QHash<Temp, QSet<BasicBlock *> > _defsites; - QHash<BasicBlock *, QSet<Temp> > A_orig; + typedef QHash<Temp, QSet<BasicBlock *> > DefSites; + DefSites _defsites; + QVector<QSet<Temp> > A_orig; QSet<Temp> nonLocals; QSet<Temp> killed; @@ -747,16 +734,22 @@ public: : function(function) { _defsites.reserve(function->tempCount); + A_orig.resize(function->basicBlockCount()); + for (int i = 0, ei = A_orig.size(); i != ei; ++i) + A_orig[i].reserve(8); #if defined(SHOW_SSA) qout << "Variables collected:" << endl; #endif // SHOW_SSA - foreach (BasicBlock *bb, function->basicBlocks) { + foreach (BasicBlock *bb, function->basicBlocks()) { + if (bb->isRemoved()) + continue; + currentBB = bb; killed.clear(); - killed.reserve(bb->statements.size() / 2); - foreach (Stmt *s, bb->statements) { + killed.reserve(bb->statements().size() / 2); + foreach (Stmt *s, bb->statements()) { s->accept(this); } } @@ -782,7 +775,7 @@ public: } QSet<Temp> inBlock(BasicBlock *n) const { - return A_orig[n]; + return A_orig.at(n->index()); } bool isNonLocal(const Temp &var) const { return nonLocals.contains(var); } @@ -828,8 +821,15 @@ protected: qout << " -> L" << currentBB->index << endl; #endif // SHOW_SSA - _defsites[*t].insert(currentBB); - A_orig[currentBB].insert(*t); + DefSites::iterator defsitesIt = _defsites.find(*t); + if (defsitesIt == _defsites.end()) { + QSet<BasicBlock *> bbs; + bbs.reserve(4); + defsitesIt = _defsites.insert(*t, bbs); + } + defsitesIt->insert(currentBB); + + A_orig[currentBB->index()].insert(*t); // For semi-pruned SSA: killed.insert(*t); @@ -858,7 +858,7 @@ void insertPhiNode(const Temp &a, BasicBlock *y, IR::Function *f) { phiNode->d = new Stmt::Data; phiNode->targetTemp = f->New<Temp>(); phiNode->targetTemp->init(a.kind, a.index, 0); - y->statements.prepend(phiNode); + y->prependStatement(phiNode); phiNode->d->incoming.resize(y->in.size()); for (int i = 0, ei = y->in.size(); i < ei; ++i) { @@ -997,15 +997,15 @@ public: VariableRenamer(IR::Function *f) : function(f) , tempCount(0) - , processed(f->basicBlocks) + , processed(f) { localMapping.reserve(f->tempCount); vregMapping.reserve(f->tempCount); - todo.reserve(f->basicBlocks.size()); + todo.reserve(f->basicBlockCount()); } void run() { - todo.append(TodoAction(function->basicBlocks.first())); + todo.append(TodoAction(function->basicBlock(0))); while (!todo.isEmpty()) { TodoAction todoAction = todo.back(); @@ -1060,13 +1060,13 @@ private: void renameStatementsAndPhis(BasicBlock *bb) { - foreach (Stmt *s, bb->statements) + foreach (Stmt *s, bb->statements()) s->accept(this); foreach (BasicBlock *Y, bb->out) { const int j = Y->in.indexOf(bb); Q_ASSERT(j >= 0 && j < Y->in.size()); - foreach (Stmt *s, Y->statements) { + foreach (Stmt *s, Y->statements()) { if (Phi *phi = s->asPhi()) { Temp *t = phi->d->incoming[j]->asTemp(); unsigned newTmp = currentNumber(*t); @@ -1201,7 +1201,7 @@ protected: void convertToSSA(IR::Function *function, const DominatorTree &df) { -#ifdef SHOW_SSA +#if defined(SHOW_SSA) qout << "Converting function "; if (function->name) qout << *function->name; @@ -1213,8 +1213,16 @@ void convertToSSA(IR::Function *function, const DominatorTree &df) // Collect all applicable variables: VariableCollector variables(function); + // Prepare for phi node insertion: + QVector<QSet<Temp> > A_phi; + A_phi.resize(function->basicBlockCount()); + for (int i = 0, ei = A_phi.size(); i != ei; ++i) { + QSet<Temp> temps; + temps.reserve(4); + A_phi[i] = temps; + } + // Place phi functions: - QHash<BasicBlock *, QSet<Temp> > A_phi; foreach (Temp a, variables.vars()) { if (!variables.isNonLocal(a)) continue; // for semi-pruned SSA @@ -1227,9 +1235,9 @@ void convertToSSA(IR::Function *function, const DominatorTree &df) for (BasicBlockSet::const_iterator it = dominatorFrontierForN.begin(), eit = dominatorFrontierForN.end(); it != eit; ++it) { BasicBlock *y = *it; - if (!A_phi[y].contains(a)) { + if (!A_phi.at(y->index()).contains(a)) { insertPhiNode(a, y, function); - A_phi[y].insert(a); + A_phi[y->index()].insert(a); if (!variables.inBlock(y).contains(a)) W.append(y); } @@ -1267,7 +1275,8 @@ public: private: IR::Function *function; - QHash<UntypedTemp, DefUse> _defUses; + typedef QHash<UntypedTemp, DefUse> DefUses; + DefUses _defUses; QHash<Stmt *, QList<Temp> > _usesPerStatement; BasicBlock *_block; @@ -1302,9 +1311,12 @@ public: DefUsesCalculator(IR::Function *function) : function(function) { - foreach (BasicBlock *bb, function->basicBlocks) { + foreach (BasicBlock *bb, function->basicBlocks()) { + if (bb->isRemoved()) + continue; + _block = bb; - foreach (Stmt *stmt, bb->statements) { + foreach (Stmt *stmt, bb->statements()) { _stmt = stmt; stmt->accept(this); } @@ -1360,8 +1372,16 @@ public: QList<Temp> usedVars(Stmt *s) const { return _usesPerStatement[s]; } - QList<Stmt *> uses(const UntypedTemp &var) const - { return _defUses[var].uses; } + const QList<Stmt *> &uses(const UntypedTemp &var) const + { + static const QList<Stmt *> noUses; + + DefUses::const_iterator it = _defUses.find(var); + if (it == _defUses.end()) + return noUses; + else + return it->uses; + } QVector<Stmt*> removeDefUses(Stmt *s) { @@ -1386,7 +1406,7 @@ public: foreach (const UntypedTemp &var, _defUses.keys()) { const DefUse &du = _defUses[var]; var.temp.dump(qout); - qout<<" -> defined in block "<<du.blockOfStatement->index<<", statement: "; + qout<<" -> defined in block "<<du.blockOfStatement->index()<<", statement: "; du.defStmt->dump(qout); qout<<endl<<" uses:"<<endl; foreach (Stmt *s, du.uses) { @@ -1478,10 +1498,7 @@ void cleanupPhis(DefUsesCalculator &defUses) foreach (Phi *phi, toRemove) { Temp targetVar = *phi->targetTemp; - BasicBlock *bb = defUses.defStmtBlock(targetVar); - int idx = bb->statements.indexOf(phi); - bb->statements[idx]->destroyData(); - bb->statements.remove(idx); + defUses.defStmtBlock(targetVar)->removeStatement(phi); foreach (const Temp &usedVar, defUses.usedVars(phi)) defUses.removeUse(phi, usedVar); @@ -1493,7 +1510,10 @@ class StatementWorklist { QVector<Stmt *> worklist; QBitArray inWorklist; - QHash<Stmt*,Stmt**> ref; + QSet<Stmt *> removed; + QHash<Stmt*,Stmt*> replaced; + + Q_DISABLE_COPY(StatementWorklist) public: StatementWorklist(IR::Function *function) @@ -1503,12 +1523,13 @@ public: // Put in all statements, and number them on the fly. The numbering is used to index the // bit array. - foreach (BasicBlock *bb, function->basicBlocks) { - for (int i = 0, ei = bb->statements.size(); i != ei; ++i) { - Stmt **s = &bb->statements[i]; - (*s)->id = stmtCount++; - w.append(*s); - ref.insert(*s, s); + foreach (BasicBlock *bb, function->basicBlocks()) { + if (bb->isRemoved()) + continue; + + foreach (Stmt *s, bb->statements()) { + s->id = stmtCount++; + w.append(s); } } @@ -1527,29 +1548,40 @@ public: void clear(Stmt *stmt) { Q_ASSERT(!inWorklist.at(stmt->id)); - *ref[stmt] = 0; + removed.insert(stmt); } void replace(Stmt *oldStmt, Stmt *newStmt) { Q_ASSERT(oldStmt); Q_ASSERT(newStmt); + Q_ASSERT(!removed.contains(oldStmt)); if (newStmt->id == -1) newStmt->id = oldStmt->id; - *ref[oldStmt] = newStmt; + QHash<Stmt *, Stmt *>::const_iterator it = replaced.find(oldStmt); + if (it != replaced.end()) + oldStmt = it.key(); + replaced[oldStmt] = newStmt; } void cleanup(IR::Function *function) { - foreach (BasicBlock *bb, function->basicBlocks) { - for (int i = 0; i < bb->statements.size();) { - if (bb->statements[i]) { - bb->statements[i]->id = -1; - ++i; - } else { - bb->statements.remove(i); + foreach (BasicBlock *bb, function->basicBlocks()) { + if (bb->isRemoved()) + continue; + + for (int i = 0; i < bb->statementCount();) { + Stmt *stmt = bb->statements()[i]; + QHash<Stmt *, Stmt *>::const_iterator it = replaced.find(stmt); + if (it != replaced.end() && !removed.contains(it.value())) { + bb->replaceStatement(i, it.value()); + } else if (removed.contains(stmt)) { + bb->removeStatement(i); + continue; } + + ++i; } } } @@ -1849,8 +1881,9 @@ class TypeInference: public StmtVisitor, public ExprVisitor { QQmlEnginePrivate *qmlEngine; IR::Function *function; const DefUsesCalculator &_defUses; - QHash<Temp, DiscoveredType> _tempTypes; - QSet<Stmt *> _worklist; + typedef QHash<Temp, DiscoveredType> TempTypes; + TempTypes _tempTypes; + QList<Stmt *> _worklist; struct TypingResult { DiscoveredType type; bool fullyTyped; @@ -1872,26 +1905,29 @@ public: // TODO: the worklist handling looks a bit inefficient... check if there is something better _worklist.clear(); - for (int i = 0, ei = function->basicBlocks.size(); i != ei; ++i) { - BasicBlock *bb = function->basicBlocks[i]; + for (int i = 0, ei = function->basicBlockCount(); i != ei; ++i) { + BasicBlock *bb = function->basicBlock(i); + if (bb->isRemoved()) + continue; if (i == 0 || !bb->in.isEmpty()) - foreach (Stmt *s, bb->statements) - if (!s->asJump()) - _worklist.insert(s); + _worklist += bb->statements().toList(); } while (!_worklist.isEmpty()) { - QList<Stmt *> worklist = _worklist.values(); + QList<Stmt *> worklist = QSet<Stmt *>::fromList(_worklist).toList(); _worklist.clear(); while (!worklist.isEmpty()) { Stmt *s = worklist.first(); worklist.removeFirst(); + if (s->asJump()) + continue; + #if defined(SHOW_SSA) qout<<"Typing stmt ";s->dump(qout);qout<<endl; #endif if (!run(s)) { - _worklist.insert(s); + _worklist += s; #if defined(SHOW_SSA) qout<<"Pushing back stmt: "; s->dump(qout);qout<<endl; @@ -1942,8 +1978,11 @@ private: #endif if (isAlwaysVar(t)) ty = DiscoveredType(VarType); - if (_tempTypes[*t] != ty) { - _tempTypes[*t] = ty; + TempTypes::iterator it = _tempTypes.find(*t); + if (it == _tempTypes.end()) + it = _tempTypes.insert(*t, DiscoveredType()); + if (it.value() != ty) { + it.value() = ty; #if defined(SHOW_SSA) foreach (Stmt *s, _defUses.uses(*t)) { @@ -1953,7 +1992,7 @@ private: } #endif - _worklist += QSet<Stmt *>::fromList(_defUses.uses(*t)); + _worklist += _defUses.uses(*t); } } else { e->type = (Type) ty.type; @@ -2243,7 +2282,7 @@ public: private: bool isUsedAsInt32(const UntypedTemp &t, const QVector<UntypedTemp> &knownOk) const { - QList<Stmt *> uses = _defUses.uses(t); + const QList<Stmt *> &uses = _defUses.uses(t); if (uses.isEmpty()) return false; @@ -2305,6 +2344,10 @@ void convertConst(Const *c, Type targetType) case BoolType: c->value = !(c->value == 0 || std::isnan(c->value)); break; + case NullType: + case UndefinedType: + c->value = qSNaN(); + c->type = targetType; default: Q_UNIMPLEMENTED(); Q_ASSERT(!"Unimplemented!"); @@ -2369,10 +2412,12 @@ public: void run(IR::Function *f) { _f = f; - foreach (BasicBlock *bb, f->basicBlocks) { + foreach (BasicBlock *bb, f->basicBlocks()) { + if (bb->isRemoved()) + continue; _conversions.clear(); - foreach (Stmt *s, bb->statements) { + foreach (Stmt *s, bb->statements()) { _currStmt = s; s->accept(this); } @@ -2403,11 +2448,9 @@ public: if (Phi *phi = conversion.stmt->asPhi()) { int idx = phi->d->incoming.indexOf(t); Q_ASSERT(idx != -1); - QVector<Stmt *> &stmts = bb->in[idx]->statements; - stmts.insert(stmts.size() - 1, convCall); + bb->in[idx]->insertStatementBeforeTerminator(convCall); } else { - int idx = bb->statements.indexOf(conversion.stmt); - bb->statements.insert(idx, convCall); + bb->insertStatementBefore(conversion.stmt, convCall); } *conversion.expr = source; @@ -2428,9 +2471,7 @@ public: _defUses.removeUse(move, *unopOperand); } - int idx = bb->statements.indexOf(conversion.stmt); - Q_ASSERT(idx != -1); - bb->statements.insert(idx, extraMove); + bb->insertStatementBefore(conversion.stmt, extraMove); *conversion.expr = bb->CONVERT(tmp, conversion.targetType); _defUses.addUse(*tmp, move); @@ -2562,56 +2603,55 @@ protected: void splitCriticalEdges(IR::Function *f, DominatorTree &df) { - for (int i = 0, ei = f->basicBlocks.size(); i != ei; ++i) { - BasicBlock *bb = f->basicBlocks[i]; - if (bb->in.size() > 1) { - for (int inIdx = 0, eInIdx = bb->in.size(); inIdx != eInIdx; ++inIdx) { - BasicBlock *inBB = bb->in[inIdx]; - if (inBB->out.size() > 1) { // this should have been split! - int newIndex = f->basicBlocks.last()->index + 1; -#if defined(SHOW_SSA) - qDebug() << "Splitting edge from block" << inBB->index << "to block" << bb->index << "by introducing block" << newIndex; -#endif + foreach (BasicBlock *bb, f->basicBlocks()) { + if (bb->isRemoved()) + continue; + if (bb->in.size() < 2) + continue; - BasicBlock *containingGroup = inBB->isGroupStart() ? inBB : inBB->containingGroup(); - - // create the basic block: - BasicBlock *newBB = new BasicBlock(f, containingGroup, bb->catchBlock); - newBB->index = newIndex; - f->basicBlocks.append(newBB); - Jump *s = f->New<Jump>(); - s->init(bb); - newBB->statements.append(s); - - // rewire the old outgoing edge - int outIdx = inBB->out.indexOf(bb); - inBB->out[outIdx] = newBB; - newBB->in.append(inBB); - - // rewire the old incoming edge - bb->in[inIdx] = newBB; - newBB->out.append(bb); - - // patch the terminator - Stmt *terminator = inBB->terminator(); - if (Jump *j = terminator->asJump()) { - Q_ASSERT(outIdx == 0); - j->target = newBB; - } else if (CJump *j = terminator->asCJump()) { - if (outIdx == 0) - j->iftrue = newBB; - else if (outIdx == 1) - j->iffalse = newBB; - else - Q_ASSERT(!"Invalid out edge index for CJUMP!"); - } else { - Q_ASSERT(!"Unknown terminator!"); - } + for (int inIdx = 0, eInIdx = bb->in.size(); inIdx != eInIdx; ++inIdx) { + BasicBlock *inBB = bb->in[inIdx]; + if (inBB->out.size() < 2) + continue; - // Set the immediate dominator of the new block to inBB - df.updateImmediateDominator(newBB, inBB); - } + // We found a critical edge. + BasicBlock *containingGroup = inBB->isGroupStart() ? inBB : inBB->containingGroup(); + + // create the basic block: + BasicBlock *newBB = f->newBasicBlock(containingGroup, bb->catchBlock); + Jump *s = f->New<Jump>(); + s->init(bb); + newBB->appendStatement(s); + + // rewire the old outgoing edge + int outIdx = inBB->out.indexOf(bb); + inBB->out[outIdx] = newBB; + newBB->in.append(inBB); + + // rewire the old incoming edge + bb->in[inIdx] = newBB; + newBB->out.append(bb); + + // patch the terminator + Stmt *terminator = inBB->terminator(); + if (Jump *j = terminator->asJump()) { + Q_ASSERT(outIdx == 0); + j->target = newBB; + } else if (CJump *j = terminator->asCJump()) { + if (outIdx == 0) + j->iftrue = newBB; + else if (outIdx == 1) + j->iffalse = newBB; + else + Q_ASSERT(!"Invalid out edge index for CJUMP!"); + } else if (terminator->asRet()) { + Q_ASSERT(!"A block with a RET at the end cannot have outgoing edges."); + } else { + Q_ASSERT(!"Unknown terminator!"); } + + // Set the immediate dominator of the new block to inBB + df.updateImmediateDominator(newBB, inBB); } } } @@ -2704,6 +2744,7 @@ class BlockScheduler void emitBlock(BasicBlock *bb) { + Q_ASSERT(!bb->isRemoved()); if (emitted.alreadyProcessed(bb)) return; @@ -2751,22 +2792,24 @@ public: BlockScheduler(IR::Function *function, const DominatorTree &dominatorTree) : function(function) , dominatorTree(dominatorTree) - , emitted(function->basicBlocks) + , sequence(0) + , emitted(function) {} QHash<BasicBlock *, BasicBlock *> go() { showMeTheCode(function); - schedule(function->basicBlocks.first()); + schedule(function->basicBlock(0)); #if defined(SHOW_SSA) qDebug() << "Block sequence:"; foreach (BasicBlock *bb, sequence) - qDebug("\tL%d", bb->index); + qDebug("\tL%d", bb->index()); #endif // SHOW_SSA - Q_ASSERT(function->basicBlocks.size() == sequence.size()); - function->basicBlocks = sequence; + Q_ASSERT(function->liveBasicBlocksCount() == sequence.size()); + function->setScheduledBlocks(sequence); + function->renumberBasicBlocks(); return loopsStartEnd; } }; @@ -2778,7 +2821,7 @@ void checkCriticalEdges(QVector<BasicBlock *> basicBlocks) { foreach (BasicBlock *bb2, bb->out) { if (bb2 && bb2->in.size() > 1) { qout << "found critical edge between block " - << bb->index << " and block " << bb2->index; + << bb->index() << " and block " << bb2->index(); Q_ASSERT(false); } } @@ -2787,51 +2830,50 @@ void checkCriticalEdges(QVector<BasicBlock *> basicBlocks) { } #endif -void cleanupBasicBlocks(IR::Function *function, bool renumber) +void cleanupBasicBlocks(IR::Function *function) { showMeTheCode(function); // Algorithm: this is the iterative version of a depth-first search for all blocks that are // reachable through outgoing edges, starting with the start block and all exception handler // blocks. - QSet<BasicBlock *> postponed, done; - QSet<BasicBlock *> toRemove; - toRemove.reserve(function->basicBlocks.size()); - done.reserve(function->basicBlocks.size()); - postponed.reserve(8); - for (int i = 0, ei = function->basicBlocks.size(); i != ei; ++i) { - BasicBlock *bb = function->basicBlocks[i]; - if (i == 0 || bb->isExceptionHandler) - postponed.insert(bb); - else - toRemove.insert(bb); + QBitArray reachableBlocks(function->basicBlockCount()); + QVector<BasicBlock *> postponed; + postponed.reserve(16); + for (int i = 0, ei = function->basicBlockCount(); i != ei; ++i) { + BasicBlock *bb = function->basicBlock(i); + if (i == 0 || bb->isExceptionHandler()) + postponed.append(bb); } while (!postponed.isEmpty()) { - QSet<BasicBlock *>::iterator it = postponed.begin(); - BasicBlock *bb = *it; - postponed.erase(it); - done.insert(bb); + BasicBlock *bb = postponed.back(); + postponed.pop_back(); + if (bb->isRemoved()) // this block was removed before, we don't need to clean it up. + continue; + + reachableBlocks.setBit(bb->index()); foreach (BasicBlock *outBB, bb->out) { - if (!done.contains(outBB)) { - postponed.insert(outBB); - toRemove.remove(outBB); - } + if (!reachableBlocks.at(outBB->index())) + postponed.append(outBB); } } - foreach (BasicBlock *bb, toRemove) { + foreach (BasicBlock *bb, function->basicBlocks()) { + if (bb->isRemoved()) // the block has already been removed, so ignore it + continue; + if (reachableBlocks.at(bb->index())) // the block is reachable, so ignore it + continue; + foreach (BasicBlock *outBB, bb->out) { - if (toRemove.contains(outBB)) + if (outBB->isRemoved() || !reachableBlocks.at(outBB->index())) continue; // We do not need to unlink from blocks that are scheduled to be removed. - // Actually, it is potentially dangerous: if that block was already - // destroyed, this could result in a use-after-free. int idx = outBB->in.indexOf(bb); if (idx != -1) { outBB->in.remove(idx); - foreach (Stmt *s, outBB->statements) { + foreach (Stmt *s, outBB->statements()) { if (Phi *phi = s->asPhi()) phi->d->incoming.remove(idx); else @@ -2840,18 +2882,9 @@ void cleanupBasicBlocks(IR::Function *function, bool renumber) } } - foreach (Stmt *s, bb->statements) - s->destroyData(); - int idx = function->basicBlocks.indexOf(bb); - if (idx != -1) - function->basicBlocks.remove(idx); - delete bb; + function->removeBasicBlock(bb); } - if (renumber) - for (int i = 0; i < function->basicBlocks.size(); ++i) - function->basicBlocks[i]->index = i; - showMeTheCode(function); } @@ -2904,7 +2937,7 @@ public: , _replacement(0) {} - QVector<Stmt *> operator()(Temp *toReplace, Expr *replacement) + void operator()(Temp *toReplace, Expr *replacement, StatementWorklist &W, QList<Stmt *> *newUses = 0) { Q_ASSERT(replacement->asTemp() || replacement->asConst() || replacement->asName()); @@ -2913,20 +2946,22 @@ public: qSwap(_toReplace, toReplace); qSwap(_replacement, replacement); - QList<Stmt *> uses = _defUses.uses(*_toReplace); + const QList<Stmt *> &uses = _defUses.uses(*_toReplace); + if (newUses) + newUses->reserve(uses.size()); + // qout << " " << uses.size() << " uses:"<<endl; - QVector<Stmt *> result; - result.reserve(uses.size()); foreach (Stmt *use, uses) { // qout<<" ";use->dump(qout);qout<<"\n"; use->accept(this); // qout<<" -> ";use->dump(qout);qout<<"\n"; - result.append(use); + W += use; + if (newUses) + newUses->append(use); } qSwap(_replacement, replacement); qSwap(_toReplace, toReplace); - return result; } protected: @@ -2991,6 +3026,11 @@ private: } } + if (e1->type == IR::NullType && e2->type == IR::NullType) + return true; + if (e1->type == IR::UndefinedType && e2->type == IR::UndefinedType) + return true; + return false; } }; @@ -3003,28 +3043,24 @@ namespace { void purgeBB(BasicBlock *bb, IR::Function *func, DefUsesCalculator &defUses, StatementWorklist &W, DominatorTree &df) { - // TODO: change this to mark the block as deleted, but leave it alone so that other references - // won't be dangling pointers. // TODO: after the change above: if we keep on detaching the block from predecessors or // successors, update the DominatorTree too. // don't purge blocks that are entry points for catch statements. They might not be directly // connected, but are required anyway - if (bb->isExceptionHandler) + if (bb->isExceptionHandler()) return; QVector<BasicBlock *> toPurge; + toPurge.reserve(8); toPurge.append(bb); while (!toPurge.isEmpty()) { bb = toPurge.first(); toPurge.removeFirst(); - int bbIdx = func->basicBlocks.indexOf(bb); - if (bbIdx == -1) + if (bb->isRemoved()) continue; - else - func->basicBlocks.remove(bbIdx); // unlink all incoming edges foreach (BasicBlock *in, bb->in) { @@ -3038,7 +3074,7 @@ void purgeBB(BasicBlock *bb, IR::Function *func, DefUsesCalculator &defUses, Sta int idx = out->in.indexOf(bb); if (idx != -1) { out->in.remove(idx); - foreach (Stmt *outStmt, out->statements) { + foreach (Stmt *outStmt, out->statements()) { if (!outStmt) continue; if (Phi *phi = outStmt->asPhi()) { @@ -3063,19 +3099,15 @@ void purgeBB(BasicBlock *bb, IR::Function *func, DefUsesCalculator &defUses, Sta } // unlink all defs/uses from the statements in the basic block - foreach (Stmt *s, bb->statements) { + foreach (Stmt *s, bb->statements()) { if (!s) continue; W += defUses.removeDefUses(s); W -= s; - - // clean-up the statement's data - s->destroyData(); } - bb->statements.clear(); - delete bb; + func->removeBasicBlock(bb); } } @@ -3116,18 +3148,20 @@ bool tryOptimizingComparison(Expr *&expr) expr = leftConst; return true; case OpStrictEqual: - if (!strictlyEqualTypes(leftConst->type, rightConst->type)) - return false; - // intentional fall-through + leftConst->value = Runtime::compareStrictEqual(&l, &r); + leftConst->type = BoolType; + expr = leftConst; + return true; case OpEqual: leftConst->value = Runtime::compareEqual(&l, &r); leftConst->type = BoolType; expr = leftConst; return true; case OpStrictNotEqual: - if (!strictlyEqualTypes(leftConst->type, rightConst->type)) - return false; - // intentional fall-through + leftConst->value = Runtime::compareStrictNotEqual(&l, &r); + leftConst->type = BoolType; + expr = leftConst; + return true; case OpNotEqual: leftConst->value = Runtime::compareNotEqual(&l, &r); leftConst->type = BoolType; @@ -3154,7 +3188,7 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr if (Phi *phi = s->asPhi()) { // constant propagation: if (Const *c = isConstPhi(phi)) { - W += replaceUses(phi->targetTemp, c); + replaceUses(phi->targetTemp, c, W); defUses.removeDef(*phi->targetTemp); W.clear(s); continue; @@ -3165,11 +3199,11 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr Temp *t = phi->targetTemp; Expr *e = phi->d->incoming.first(); - QVector<Stmt *> newT2Uses = replaceUses(t, e); - W += newT2Uses; + QList<Stmt *> newT2Uses; + replaceUses(t, e, W, &newT2Uses); if (Temp *t2 = e->asTemp()) { defUses.removeUse(s, *t2); - defUses.addUses(*t2, QList<Stmt*>::fromVector(newT2Uses)); + defUses.addUses(*t2, newT2Uses); } defUses.removeDef(*t); W.clear(s); @@ -3214,13 +3248,9 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr // constant propagation: if (Const *sourceConst = m->source->asConst()) { - if (sourceConst->type & NumberType || sourceConst->type == BoolType) { - // TODO: when propagating other constants, e.g. undefined, the other - // optimization passes have to be changed to cope with them. - W += replaceUses(targetTemp, sourceConst); - defUses.removeDef(*targetTemp); - W.clear(s); - } + replaceUses(targetTemp, sourceConst, W); + defUses.removeDef(*targetTemp); + W.clear(s); continue; } if (Member *member = m->source->asMember()) { @@ -3228,7 +3258,7 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr Const *c = function->New<Const>(); const int enumValue = member->attachedPropertiesIdOrEnumValue; c->init(SInt32Type, enumValue); - W += replaceUses(targetTemp, c); + replaceUses(targetTemp, c, W); defUses.removeDef(*targetTemp); W.clear(s); defUses.removeUse(s, *member->base->asTemp()); @@ -3246,10 +3276,10 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr // copy propagation: if (Temp *sourceTemp = unescapableTemp(m->source, function)) { - QVector<Stmt *> newT2Uses = replaceUses(targetTemp, sourceTemp); - W += newT2Uses; + QList<Stmt *> newT2Uses; + replaceUses(targetTemp, sourceTemp, W, &newT2Uses); defUses.removeUse(s, *sourceTemp); - defUses.addUses(*sourceTemp, QList<Stmt*>::fromVector(newT2Uses)); + defUses.addUses(*sourceTemp, newT2Uses); defUses.removeDef(*targetTemp); W.clear(s); continue; @@ -3366,8 +3396,8 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr QV4::Primitive lc = convertToValue(leftConst); QV4::Primitive rc = convertToValue(rightConst); - double l = RuntimeHelpers::toNumber(&lc); - double r = RuntimeHelpers::toNumber(&rc); + double l = lc.toNumber(); + double r = rc.toNumber(); switch (binop->op) { case OpMul: @@ -3514,16 +3544,19 @@ protected: class LifeRanges { typedef QSet<Temp> LiveRegs; - QHash<BasicBlock *, LiveRegs> _liveIn; + QVector<LiveRegs> _liveIn; QHash<Temp, LifeTimeInterval> _intervals; - QVector<LifeTimeInterval> _sortedRanges; + typedef QVector<LifeTimeInterval> LifeTimeIntervals; + LifeTimeIntervals _sortedIntervals; public: LifeRanges(IR::Function *function, const QHash<BasicBlock *, BasicBlock *> &startEndLoops) { + _liveIn.resize(function->basicBlockCount()); + int id = 0; - foreach (BasicBlock *bb, function->basicBlocks) { - foreach (Stmt *s, bb->statements) { + foreach (BasicBlock *bb, function->basicBlocks()) { + foreach (Stmt *s, bb->statements()) { if (s->asPhi()) s->id = id + 1; else @@ -3531,34 +3564,34 @@ public: } } - for (int i = function->basicBlocks.size() - 1; i >= 0; --i) { - BasicBlock *bb = function->basicBlocks[i]; + for (int i = function->basicBlockCount() - 1; i >= 0; --i) { + BasicBlock *bb = function->basicBlock(i); buildIntervals(bb, startEndLoops.value(bb, 0), function); } - _sortedRanges.reserve(_intervals.size()); + _sortedIntervals.reserve(_intervals.size()); for (QHash<Temp, LifeTimeInterval>::const_iterator i = _intervals.begin(), ei = _intervals.end(); i != ei; ++i) { - LifeTimeInterval range = i.value(); - range.setTemp(i.key()); - _sortedRanges.append(range); + LifeTimeIntervals::iterator lti = _sortedIntervals.insert(_sortedIntervals.end(), i.value()); + lti->setTemp(i.key()); } - std::sort(_sortedRanges.begin(), _sortedRanges.end(), LifeTimeInterval::lessThan); + std::sort(_sortedIntervals.begin(), _sortedIntervals.end(), LifeTimeInterval::lessThan); + _intervals.clear(); } - QVector<LifeTimeInterval> ranges() const { return _sortedRanges; } + QVector<LifeTimeInterval> intervals() const { return _sortedIntervals; } void dump() const { qout << "Life ranges:" << endl; qout << "Intervals:" << endl; - foreach (const LifeTimeInterval &range, _sortedRanges) { + foreach (const LifeTimeInterval &range, _sortedIntervals) { range.dump(qout); qout << endl; } - foreach (BasicBlock *bb, _liveIn.keys()) { - qout << "L" << bb->index <<" live-in: "; - QList<Temp> live = QList<Temp>::fromSet(_liveIn.value(bb)); + for (int i = 0, ei = _liveIn.size(); i != ei; ++i) { + qout << "L" << i <<" live-in: "; + QList<Temp> live = QList<Temp>::fromSet(_liveIn.at(i)); std::sort(live.begin(), live.end()); for (int i = 0; i < live.size(); ++i) { if (i > 0) qout << ", "; @@ -3573,11 +3606,11 @@ private: { LiveRegs live; foreach (BasicBlock *successor, bb->out) { - live.unite(_liveIn[successor]); + live.unite(_liveIn[successor->index()]); const int bbIndex = successor->in.indexOf(bb); Q_ASSERT(bbIndex >= 0); - foreach (Stmt *s, successor->statements) { + foreach (Stmt *s, successor->statements()) { if (Phi *phi = s->asPhi()) { if (Temp *t = phi->d->incoming[bbIndex]->asTemp()) live.insert(*t); @@ -3587,12 +3620,14 @@ private: } } + QVector<Stmt *> statements = bb->statements(); + foreach (const Temp &opd, live) - _intervals[opd].addRange(bb->statements.first()->id, bb->statements.last()->id); + _intervals[opd].addRange(statements.first()->id, statements.last()->id); InputOutputCollector collector(function); - for (int i = bb->statements.size() - 1; i >= 0; --i) { - Stmt *s = bb->statements[i]; + for (int i = statements.size() - 1; i >= 0; --i) { + Stmt *s = statements[i]; if (Phi *phi = s->asPhi()) { LiveRegs::iterator it = live.find(*phi->targetTemp); if (it == live.end()) { @@ -3609,19 +3644,30 @@ private: live.remove(opd); } foreach (const Temp &opd, collector.inputs) { - _intervals[opd].addRange(bb->statements.first()->id, s->id); + _intervals[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. foreach (const Temp &opd, live) - _intervals[opd].addRange(bb->statements.first()->id, loopEnd->statements.last()->id); + _intervals[opd].addRange(statements.first()->id, loopEnd->terminator()->id); } - _liveIn[bb] = live; + _liveIn[bb->index()] = live; } }; + +void removeUnreachleBlocks(IR::Function *function) +{ + QVector<BasicBlock *> newSchedule; + newSchedule.reserve(function->basicBlockCount()); + foreach (BasicBlock *bb, function->basicBlocks()) + if (!bb->isRemoved()) + newSchedule.append(bb); + function->setScheduledBlocks(newSchedule); + function->renumberBasicBlocks(); +} } // anonymous namespace void LifeTimeInterval::setFrom(Stmt *from) { @@ -3684,8 +3730,8 @@ LifeTimeInterval LifeTimeInterval::split(int atPosition, int newStart) // search where to split the interval for (int i = 0, ei = _ranges.size(); i < ei; ++i) { - if (_ranges[i].start <= atPosition) { - if (_ranges[i].end >= atPosition) { + if (_ranges.at(i).start <= atPosition) { + if (_ranges.at(i).end >= atPosition) { // split happens in the middle of a range. Keep this range in both the old and the // new interval, and correct the end/start later _ranges.resize(i + 1); @@ -3767,6 +3813,11 @@ bool LifeTimeInterval::lessThanForTemp(const LifeTimeInterval &r1, const LifeTim return r1.temp() < r2.temp(); } +Optimizer::Optimizer(IR::Function *function) + : function(function) + , inSSA(false) +{} + void Optimizer::run(QQmlEnginePrivate *qmlEngine) { #if defined(SHOW_SSA) @@ -3774,12 +3825,9 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine) << " with " << function->basicBlocks.size() << " basic blocks." << endl << flush; #endif - // Number all basic blocks, so we have nice numbers in the dumps: - for (int i = 0; i < function->basicBlocks.size(); ++i) - function->basicBlocks[i]->index = i; // showMeTheCode(function); - cleanupBasicBlocks(function, true); + cleanupBasicBlocks(function); function->removeSharedExpressions(); @@ -3791,7 +3839,7 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine) // qout << "SSA for " << (function->name ? qPrintable(*function->name) : "<anonymous>") << endl; // Calculate the dominator tree: - DominatorTree df(function->basicBlocks); + DominatorTree df(function); // qout << "Converting to SSA..." << endl; convertToSSA(function, df); @@ -3836,21 +3884,22 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine) // condition is calculated to be always false) are not yet removed. This will choke the // block scheduling, so remove those now. // qout << "Cleaning up unreachable basic blocks..." << endl; - cleanupBasicBlocks(function, false); + cleanupBasicBlocks(function); // showMeTheCode(function); // qout << "Doing block scheduling..." << endl; // df.dumpImmediateDominators(); startEndLoops = BlockScheduler(function, df).go(); -// showMeTheCode(function); + showMeTheCode(function); #ifndef QT_NO_DEBUG - checkCriticalEdges(function->basicBlocks); + checkCriticalEdges(function->basicBlocks()); #endif // qout << "Finished SSA." << endl; inSSA = true; } else { + removeUnreachleBlocks(function); inSSA = false; } } @@ -3861,13 +3910,13 @@ void Optimizer::convertOutOfSSA() { // There should be no critical edges at this point. - foreach (BasicBlock *bb, function->basicBlocks) { + foreach (BasicBlock *bb, function->basicBlocks()) { MoveMapping moves; foreach (BasicBlock *successor, bb->out) { const int inIdx = successor->in.indexOf(bb); Q_ASSERT(inIdx >= 0); - foreach (Stmt *s, successor->statements) { + foreach (Stmt *s, successor->statements()) { if (Phi *phi = s->asPhi()) { moves.add(clone(phi->d->incoming[inIdx], function), clone(phi->targetTemp, function)->asTemp()); @@ -3893,11 +3942,10 @@ void Optimizer::convertOutOfSSA() { moves.insertMoves(bb, function, true); } - foreach (BasicBlock *bb, function->basicBlocks) { - while (!bb->statements.isEmpty()) { - if (Phi *phi = bb->statements.first()->asPhi()) { - phi->destroyData(); - bb->statements.removeFirst(); + foreach (BasicBlock *bb, function->basicBlocks()) { + while (!bb->isEmpty()) { + if (bb->statements().first()->asPhi()) { + bb->removeStatement(0); } else { break; } @@ -3905,14 +3953,14 @@ void Optimizer::convertOutOfSSA() { } } -QVector<LifeTimeInterval> Optimizer::lifeRanges() const +QVector<LifeTimeInterval> Optimizer::lifeTimeIntervals() const { Q_ASSERT(isInSSA()); LifeRanges lifeRanges(function, startEndLoops); // lifeRanges.dump(); // showMeTheCode(function); - return lifeRanges.ranges(); + return lifeRanges.intervals(); } QSet<Jump *> Optimizer::calculateOptionalJumps() @@ -3920,16 +3968,18 @@ QSet<Jump *> Optimizer::calculateOptionalJumps() QSet<Jump *> optional; QSet<BasicBlock *> reachableWithoutJump; - const int maxSize = function->basicBlocks.size(); + const int maxSize = function->basicBlockCount(); optional.reserve(maxSize); reachableWithoutJump.reserve(maxSize); - for (int i = function->basicBlocks.size() - 1; i >= 0; --i) { - BasicBlock *bb = function->basicBlocks[i]; + for (int i = maxSize - 1; i >= 0; --i) { + BasicBlock *bb = function->basicBlock(i); + if (bb->isRemoved()) + continue; - if (Jump *jump = bb->statements.last()->asJump()) { + if (Jump *jump = bb->statements().last()->asJump()) { if (reachableWithoutJump.contains(jump->target)) { - if (bb->statements.size() > 1) + if (bb->statements().size() > 1) reachableWithoutJump.clear(); optional.insert(jump); reachableWithoutJump.insert(bb); @@ -4044,12 +4094,12 @@ QList<IR::Move *> MoveMapping::insertMoves(BasicBlock *bb, IR::Function *functio QList<IR::Move *> newMoves; newMoves.reserve(_moves.size()); - int insertionPoint = atEnd ? bb->statements.size() - 1 : 0; + int insertionPoint = atEnd ? bb->statements().size() - 1 : 0; foreach (const Move &m, _moves) { IR::Move *move = function->New<IR::Move>(); move->init(clone(m.to, function), clone(m.from, function)); move->swap = m.needsSwap; - bb->statements.insert(insertionPoint++, move); + bb->insertStatementBefore(insertionPoint++, move); newMoves.append(move); } |