diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2014-01-16 21:52:48 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@digia.com> | 2014-01-16 21:53:57 +0100 |
commit | 7030adff1869e850a7b983e88d7a773d5d594886 (patch) | |
tree | a3e8ef3ba29c9ea34ee00038595aaa1fe00afe2c /src | |
parent | 5ba070d305572a7e427a62042967d737bd4791ac (diff) | |
parent | 6ccb9f8f04ea257520e518b25999907c6a8421e1 (diff) |
Merge remote-tracking branch 'origin/release' into stable
Change-Id: Id18709cb0a4d85ffdadffa28aef98323367292d4
Diffstat (limited to 'src')
-rw-r--r-- | src/imports/dialogs/DefaultFileDialog.qml | 15 | ||||
-rw-r--r-- | src/imports/widgets/qquickqfiledialog.cpp | 4 | ||||
-rw-r--r-- | src/qml/compiler/qv4regalloc.cpp | 162 | ||||
-rw-r--r-- | src/qml/compiler/qv4ssa.cpp | 148 | ||||
-rw-r--r-- | src/qml/compiler/qv4ssa_p.h | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4context.cpp | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4context_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 3 | ||||
-rw-r--r-- | src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 11 |
9 files changed, 222 insertions, 134 deletions
diff --git a/src/imports/dialogs/DefaultFileDialog.qml b/src/imports/dialogs/DefaultFileDialog.qml index 0a5eabddf2..627a719f60 100644 --- a/src/imports/dialogs/DefaultFileDialog.qml +++ b/src/imports/dialogs/DefaultFileDialog.qml @@ -53,7 +53,13 @@ AbstractFileDialog { currentPathField.visible = false } } - onFolderChanged: view.model.folder = folder + onFolderChanged: { + var str = new String(folder) + if (str.indexOf("qrc:") === 0) + folder = "file:" + str.slice(4) + if (view.model.folder != folder) + view.model.folder = folder + } property real __textX: titleBar.height property SystemPalette __palette @@ -61,12 +67,15 @@ AbstractFileDialog { property int __lastClickedIdx: -1 function __dirDown(path) { - view.model.folder = path + view.model.folder = "file://" + path __lastClickedIdx = -1 __selectedIndices = [] } function __dirUp() { - view.model.folder = view.model.parentFolder + if (view.model.parentFolder == "") + view.model.folder = "file:///" + else + view.model.folder = view.model.parentFolder __lastClickedIdx = -1 __selectedIndices = [] } diff --git a/src/imports/widgets/qquickqfiledialog.cpp b/src/imports/widgets/qquickqfiledialog.cpp index c3991b4f3c..403577fabe 100644 --- a/src/imports/widgets/qquickqfiledialog.cpp +++ b/src/imports/widgets/qquickqfiledialog.cpp @@ -172,6 +172,10 @@ void QFileDialogHelper::setFilter() { m_dialog.setFileMode(QFileDialog::FileMode(QPlatformFileDialogHelper::options()->fileMode())); m_dialog.setOptions((QFileDialog::Options)((int)(QPlatformFileDialogHelper::options()->options()))); m_dialog.setAcceptMode(QFileDialog::AcceptMode(QPlatformFileDialogHelper::options()->acceptMode())); + + const QUrl initialDirectory = QPlatformFileDialogHelper::options()->initialDirectory(); + if (initialDirectory.isValid() && initialDirectory.isLocalFile()) + m_dialog.setDirectory(initialDirectory.toLocalFile()); } bool QFileDialogHelper::show(Qt::WindowFlags f, Qt::WindowModality m, QWindow *parent) { diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp index 93ecdb2602..3521d0c27a 100644 --- a/src/qml/compiler/qv4regalloc.cpp +++ b/src/qml/compiler/qv4regalloc.cpp @@ -124,7 +124,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) { @@ -658,13 +658,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; @@ -672,8 +673,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, @@ -691,6 +692,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() { @@ -704,6 +712,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) { @@ -754,22 +763,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)); } } } @@ -779,37 +788,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(); } } @@ -817,19 +826,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 @@ -848,17 +853,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; @@ -866,12 +875,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; } } @@ -886,18 +895,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; } @@ -906,20 +915,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. @@ -938,13 +947,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 @@ -1005,10 +1019,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 { @@ -1078,7 +1092,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); @@ -1114,7 +1128,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); @@ -1123,6 +1137,7 @@ static inline LifeTimeInterval createFixedInterval(int reg, bool isFP) i.setTemp(t); i.setReg(reg); i.setFixedInterval(true); + i.reserveRanges(rangeCount); return i; } @@ -1131,12 +1146,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) @@ -1448,9 +1464,9 @@ int RegisterAllocator::nextIntersection(const LifeTimeInterval ¤t, return -1; for (int currentEnd = currentRanges.size(); currentIt < currentEnd; ++currentIt) { - const LifeTimeInterval::Range ¤tRange = 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); @@ -1585,7 +1601,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); diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 31a1e4cdc4..7113dc7c26 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -308,9 +308,9 @@ public: BasicBlock *operator*() const { if (set.blockNumbers) - return set.allBlocks[*numberIt]; + return set.allBlocks.at(*numberIt); else - return set.allBlocks[flagIt]; + return set.allBlocks.at(flagIt); } bool operator==(const const_iterator &other) const @@ -409,7 +409,7 @@ class DominatorTree { typedef int BasicBlockIndex; enum { InvalidBasicBlockIndex = -1 }; - const QVector<BasicBlock *> nodes; + QVector<BasicBlock *> nodes; int N; std::vector<int> dfnum; // BasicBlock index -> dfnum std::vector<int> vertex; @@ -472,9 +472,8 @@ class DominatorTree { #endif // SHOW_SSA } - BasicBlockIndex ancestorWithLowestSemi(BasicBlockIndex v) { - std::vector<BasicBlockIndex> worklist; - worklist.reserve(vertex.capacity() / 2); + BasicBlockIndex ancestorWithLowestSemi(BasicBlockIndex v, std::vector<BasicBlockIndex> &worklist) { + worklist.clear(); for (BasicBlockIndex it = v; it != InvalidBasicBlockIndex; it = ancestor[it]) worklist.push_back(it); @@ -517,6 +516,9 @@ class DominatorTree { DFS(nodes.first()->index); Q_ASSERT(N == nodes.size()); // fails with unreachable nodes, but those should have been removed before. + std::vector<BasicBlockIndex> worklist; + worklist.reserve(vertex.capacity() / 2); + for (int i = N - 1; i > 0; --i) { BasicBlockIndex n = vertex[i]; BasicBlockIndex p = parent[n]; @@ -527,7 +529,7 @@ class DominatorTree { if (dfnum[v->index] <= dfnum[n]) ss = v->index; else - ss = semi[ancestorWithLowestSemi(v->index)]; + ss = semi[ancestorWithLowestSemi(v->index, worklist)]; if (dfnum[ss] < dfnum[s]) s = ss; } @@ -536,7 +538,7 @@ class DominatorTree { link(p, n); if (bucket.contains(p)) { foreach (BasicBlockIndex v, bucket[p]) { - BasicBlockIndex y = ancestorWithLowestSemi(v); + BasicBlockIndex y = ancestorWithLowestSemi(v, worklist); BasicBlockIndex semi_v = semi[v]; if (semi[y] == semi_v) idom[v] = semi_v; @@ -602,7 +604,7 @@ class DominatorTree { std::vector<BasicBlockIndex> worklist; worklist.reserve(nodes.size() * 2); for (int i = 0, ei = nodes.size(); i != ei; ++i) { - BasicBlockIndex nodeIndex = nodes[i]->index; + BasicBlockIndex nodeIndex = nodes.at(i)->index; worklist.push_back(nodeIndex); NodeProgress &np = nodeStatus[nodeIndex]; np.children = children[nodeIndex]; @@ -633,7 +635,7 @@ class DominatorTree { if (np.todo.empty()) { BasicBlockSet &S = DF[node]; S.init(nodes); - foreach (BasicBlock *y, nodes[node]->out) + foreach (BasicBlock *y, nodes.at(node)->out) if (idom[y->index] != node) S.insert(y); foreach (BasicBlockIndex child, np.children) { @@ -695,10 +697,6 @@ public: computeDF(); } -// QSet<BasicBlock *> operator[](BasicBlock *n) const { -// return DF[n->index]; -// } - const BasicBlockSet &dominatorFrontier(BasicBlock *n) const { return DF[n->index]; } @@ -707,14 +705,57 @@ public: return nodes[idom[bb->index]]; } + void dumpImmediateDominators() const + { + qDebug() << "Immediate dominators for" << idom.size() << "nodes:"; + for (size_t i = 0, ei = idom.size(); i != ei; ++i) + if (idom[i] == InvalidBasicBlockIndex) + qDebug("\tnone -> L%d", int(i)); + else + qDebug("\tL%d -> L%d", idom[i], int(i)); + } + + void updateImmediateDominator(BasicBlock *bb, BasicBlock *newDominator) + { + Q_ASSERT(bb->index >= 0); + + int blockIndex; + 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[blockIndex] = getBlockIndex(newDominator); + } + bool dominates(BasicBlock *dominator, BasicBlock *dominated) const { // The index of the basic blocks might have changed, or the nodes array might have changed, - // or the block got deleted, so get the index from our copy of the array. - return dominates(nodes.indexOf(dominator), nodes.indexOf(dominated)); + // so get the index from our copy of the array. + return dominates(getBlockIndex(dominator), getBlockIndex(dominated)); } 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 (it == dominator) return true; @@ -754,6 +795,8 @@ public: VariableCollector(Function *function) : variablesCanEscape(function->variablesCanEscape()) { + _defsites.reserve(function->tempCount); + #if defined(SHOW_SSA) qout << "Variables collected:" << endl; #endif // SHOW_SSA @@ -1018,6 +1061,9 @@ public: , tempCount(0) , processed(f->basicBlocks) { + localMapping.reserve(f->tempCount); + vregMapping.reserve(f->tempCount); + todo.reserve(f->basicBlocks.size()); } void run() { @@ -2463,11 +2509,10 @@ protected: } }; -void splitCriticalEdges(Function *f) +void splitCriticalEdges(Function *f, DominatorTree &df) { - const QVector<BasicBlock *> oldBBs = f->basicBlocks; - - foreach (BasicBlock *bb, oldBBs) { + 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]; @@ -2511,6 +2556,9 @@ void splitCriticalEdges(Function *f) } else { Q_ASSERT(!"Unknown terminator!"); } + + // Set the immediate dominator of the new block to inBB + df.updateImmediateDominator(newBB, inBB); } } } @@ -2660,6 +2708,12 @@ public: showMeTheCode(function); schedule(function->basicBlocks.first()); +#if defined(SHOW_SSA) + qDebug() << "Block sequence:"; + foreach (BasicBlock *bb, sequence) + qDebug("\tL%d", bb->index); +#endif // SHOW_SSA + Q_ASSERT(function->basicBlocks.size() == sequence.size()); function->basicBlocks = sequence; return loopsStartEnd; @@ -2895,7 +2949,8 @@ namespace { /// and removes unreachable staements from the worklist, so that optimiseSSA won't consider them /// anymore. /// Important: this assumes that there are no critical edges in the control-flow graph! -void purgeBB(BasicBlock *bb, Function *func, DefUsesCalculator &defUses, QVector<Stmt *> &W) +void purgeBB(BasicBlock *bb, Function *func, DefUsesCalculator &defUses, QVector<Stmt *> &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. @@ -2945,11 +3000,15 @@ void purgeBB(BasicBlock *bb, Function *func, DefUsesCalculator &defUses, QVector } } - // if a successor has no incoming edges after unlinking the current basic block, then - // it is unreachable, and can be purged too - if (out->in.isEmpty()) + if (out->in.isEmpty()) { + // if a successor has no incoming edges after unlinking the current basic block, then + // it is unreachable, and can be purged too toPurge.append(out); - + } else if (out->in.size() == 1) { + // if the successor now has only one incoming edge, we that edge is the new + // immediate dominator + df.updateImmediateDominator(out, out->in.first()); + } } // unlink all defs/uses from the statements in the basic block @@ -3032,7 +3091,7 @@ bool tryOptimizingComparison(Expr *&expr) } } // anonymous namespace -void optimizeSSA(Function *function, DefUsesCalculator &defUses) +void optimizeSSA(Function *function, DefUsesCalculator &defUses, DominatorTree &df) { const bool variablesCanEscape = function->variablesCanEscape(); @@ -3298,10 +3357,10 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses) Jump *jump = function->New<Jump>(); if (convertToValue(constantCondition).toBoolean()) { jump->target = cjump->iftrue; - purgeBB(cjump->iffalse, function, defUses, W); + purgeBB(cjump->iffalse, function, defUses, W, df); } else { jump->target = cjump->iffalse; - purgeBB(cjump->iftrue, function, defUses, W); + purgeBB(cjump->iftrue, function, defUses, W, df); } *ref[s] = jump; @@ -3648,9 +3707,6 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine) if (!function->hasTry && !function->hasWith && !function->module->debugMode && doSSA) { // qout << "SSA for " << (function->name ? qPrintable(*function->name) : "<anonymous>") << endl; -// qout << "Starting edge splitting..." << endl; - splitCriticalEdges(function); -// showMeTheCode(function); // Calculate the dominator tree: DominatorTree df(function->basicBlocks); @@ -3678,10 +3734,15 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine) TypePropagation(defUses).run(function); // showMeTheCode(function); + // Transform the CFG into edge-split SSA. +// qout << "Starting edge splitting..." << endl; + splitCriticalEdges(function, df); +// showMeTheCode(function); + static bool doOpt = qgetenv("QV4_NO_OPT").isEmpty(); if (doOpt) { // qout << "Running SSA optimization..." << endl; - optimizeSSA(function, defUses); + optimizeSSA(function, defUses, df); // showMeTheCode(function); } @@ -3697,6 +3758,7 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine) // showMeTheCode(function); // qout << "Doing block scheduling..." << endl; +// df.dumpImmediateDominators(); startEndLoops = BlockScheduler(function, df).go(); // showMeTheCode(function); @@ -3837,15 +3899,20 @@ static inline bool overlappingStorage(const Temp &t1, const Temp &t2) || (t1.type != DoubleType && t2.type != DoubleType); } -int MoveMapping::isUsedAsSource(Expr *e) const +MoveMapping::Moves MoveMapping::sourceUsages(Expr *e, const Moves &moves) { - if (Temp *t = e->asTemp()) - for (int i = 0, ei = _moves.size(); i != ei; ++i) - if (Temp *from = _moves[i].from->asTemp()) + Moves usages; + + if (Temp *t = e->asTemp()) { + for (int i = 0, ei = moves.size(); i != ei; ++i) { + const Move &move = moves[i]; + if (Temp *from = move.from->asTemp()) if (overlappingStorage(*from, *t)) - return i; + usages.append(move); + } + } - return -1; + return usages; } void MoveMapping::add(Expr *from, Temp *to, int id) { @@ -3924,9 +3991,8 @@ void MoveMapping::dump() const MoveMapping::Action MoveMapping::schedule(const Move &m, QList<Move> &todo, QList<Move> &delayed, QList<Move> &output, QList<Move> &swaps) const { - int useIdx = isUsedAsSource(m.to); - if (useIdx != -1) { - const Move &dependency = _moves[useIdx]; + Moves usages = sourceUsages(m.to, todo) + sourceUsages(m.to, delayed); + foreach (const Move &dependency, usages) { if (!output.contains(dependency)) { if (delayed.contains(dependency)) { // We have a cycle! Break it by swapping instead of assigning. diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h index dcbc83ae65..f90fc5b05b 100644 --- a/src/qml/compiler/qv4ssa_p.h +++ b/src/qml/compiler/qv4ssa_p.h @@ -93,6 +93,7 @@ public: void setFrom(Stmt *from); void addRange(int from, int to); Ranges ranges() const { return _ranges; } + void reserveRanges(int capacity) { _ranges.reserve(capacity); } int start() const { return _ranges.first().start; } int end() const { return _end; } @@ -165,10 +166,11 @@ class MoveMapping bool operator==(const Move &other) const { return from == other.from && to == other.to; } }; + typedef QList<Move> Moves; - QList<Move> _moves; + Moves _moves; - int isUsedAsSource(Expr *e) const; + static Moves sourceUsages(Expr *e, const Moves &moves); public: void add(Expr *from, Temp *to, int id = 0); diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 05a0e66e09..c2c9aefd5f 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -83,9 +83,6 @@ CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData c->strictMode = function->strictMode; c->outer = function->scope; -#ifndef QT_NO_DEBUG - assert(c->outer->next != (ExecutionContext *)0x1); -#endif c->activation = 0; @@ -229,9 +226,6 @@ CallContext::CallContext(ExecutionEngine *engine, ObjectRef qml, FunctionObject strictMode = true; outer = function->scope; -#ifndef QT_NO_DEBUG - assert(outer->next != (ExecutionContext *)0x1); -#endif activation = qml.getPointer(); diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 4eb89ad905..334d033193 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -106,7 +106,6 @@ struct Q_QML_EXPORT ExecutionContext : public Managed ExecutionContext *outer; Lookup *lookups; CompiledData::CompilationUnit *compilationUnit; - ExecutionContext *next; // used in the GC struct EvalCode { diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 6e5c137e0b..ce81282aa3 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -133,9 +133,6 @@ void FunctionObject::init(const StringRef n, bool createProto) type = Type_FunctionObject; needsActivation = true; strictMode = false; -#ifndef QT_NO_DEBUG - assert(scope->next != (ExecutionContext *)0x1); -#endif if (createProto) { Scoped<Object> proto(s, scope->engine->newObject(scope->engine->protoClass)); diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index b8fdb9c9f8..e9d883f248 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -106,8 +106,7 @@ bool qsg_sort_batch_is_valid(Batch *a, Batch *b) { return a->first && !b->first; bool qsg_sort_batch_increasing_order(Batch *a, Batch *b) { return a->first->order < b->first->order; } bool qsg_sort_batch_decreasing_order(Batch *a, Batch *b) { return a->first->order > b->first->order; } -QSGMaterial::Flag QSGMaterial_FullMatrix = (QSGMaterial::Flag) (QSGMaterial::RequiresFullMatrix & ~QSGMaterial::RequiresFullMatrixExceptTranslate); -QSGMaterial::Flag QSGMaterial_FullExceptTranslate = (QSGMaterial::Flag) (QSGMaterial::RequiresFullMatrixExceptTranslate & ~QSGMaterial::RequiresDeterminant); +QSGMaterial::Flag QSGMaterial_RequiresFullMatrixBit = (QSGMaterial::Flag) (QSGMaterial::RequiresFullMatrix & ~QSGMaterial::RequiresFullMatrixExceptTranslate); struct QMatrix4x4_Accessor { @@ -1704,12 +1703,14 @@ void Renderer::uploadBatch(Batch *b) QSGGeometryNode *gn = b->first->node; QSGGeometry *g = gn->geometry(); - QSGMaterial::Flags flags = gn->activeMaterial()->flags(); + bool canMerge = (g->drawingMode() == GL_TRIANGLES || g->drawingMode() == GL_TRIANGLE_STRIP) && b->positionAttribute >= 0 && g->indexType() == GL_UNSIGNED_SHORT - && (flags & (QSGMaterial::CustomCompileStep | QSGMaterial_FullMatrix)) == 0 - && ((flags & QSGMaterial_FullExceptTranslate) == 0 || b->isTranslateOnlyToRoot()) + && (gn->activeMaterial()->flags() & QSGMaterial::CustomCompileStep) == 0 + && (((gn->activeMaterial()->flags() & QSGMaterial::RequiresDeterminant) == 0) + || (((gn->activeMaterial()->flags() & QSGMaterial_RequiresFullMatrixBit) == 0) && b->isTranslateOnlyToRoot()) + ) && b->isSafeToBatch(); b->merged = canMerge; |