~ubuntu-branches/ubuntu/vivid/qtdeclarative-opensource-src-gles/vivid

« back to all changes in this revision

Viewing changes to src/qml/compiler/qv4ssa.cpp

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2014-10-29 07:54:05 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20141029075405-gq1uzomnw3but9g2
Tags: 5.3.2-0ubuntu1
Sync package with qtdeclarative-opensource-src - 5.3.2-3ubuntu1 

Show diffs side-by-side

added added

removed removed

Lines of Context:
79
79
        QVector<Stmt *> code;
80
80
        QHash<Stmt *, BasicBlock *> leader;
81
81
 
82
 
        foreach (BasicBlock *block, function->basicBlocks) {
83
 
            if (block->statements.isEmpty())
 
82
        foreach (BasicBlock *block, function->basicBlocks()) {
 
83
            if (block->isRemoved() || block->isEmpty())
84
84
                continue;
85
 
            leader.insert(block->statements.first(), block);
86
 
            foreach (Stmt *s, block->statements) {
 
85
            leader.insert(block->statements().first(), block);
 
86
            foreach (Stmt *s, block->statements()) {
87
87
                code.append(s);
88
88
            }
89
89
        }
115
115
                qout << endl;
116
116
                QByteArray str;
117
117
                str.append('L');
118
 
                str.append(QByteArray::number(bb->index));
 
118
                str.append(QByteArray::number(bb->index()));
119
119
                str.append(':');
120
120
                if (bb->catchBlock) {
121
121
                    str.append(" (exception handler L");
122
 
                    str.append(QByteArray::number(bb->catchBlock->index));
 
122
                    str.append(QByteArray::number(bb->catchBlock->index()));
123
123
                    str.append(')');
124
124
                }
125
125
                for (int i = 66 - str.length(); i; --i)
127
127
                qout << str;
128
128
                qout << "// predecessor blocks:";
129
129
                foreach (BasicBlock *in, bb->in)
130
 
                    qout << " L" << in->index;
 
130
                    qout << " L" << in->index();
131
131
                if (bb->in.isEmpty())
132
132
                    qout << "(none)";
133
133
                if (BasicBlock *container = bb->containingGroup())
134
 
                    qout << "; container block: L" << container->index;
 
134
                    qout << "; container block: L" << container->index();
135
135
                if (bb->isGroupStart())
136
136
                    qout << "; group start";
137
137
                qout << endl;
158
158
            qout << endl;
159
159
 
160
160
            if (n && s->asCJump()) {
161
 
                qout << "    else goto L" << s->asCJump()->iffalse->index << ";" << endl;
 
161
                qout << "    else goto L" << s->asCJump()->iffalse->index() << ";" << endl;
162
162
            }
163
163
        }
164
164
 
172
172
    QBitArray processed;
173
173
 
174
174
public:
175
 
    ProcessedBlocks(const QVector<BasicBlock *> allBlocks)
 
175
    ProcessedBlocks(IR::Function *function)
176
176
    {
177
 
        int maxBB = 0;
178
 
        foreach (BasicBlock *bb, allBlocks)
179
 
            maxBB = qMax(maxBB, bb->index);
180
 
        processed = QBitArray(maxBB + 1, false);
 
177
        processed = QBitArray(function->basicBlockCount(), false);
181
178
    }
182
179
 
183
180
    bool alreadyProcessed(BasicBlock *bb) const
184
181
    {
185
182
        Q_ASSERT(bb);
186
183
 
187
 
        return processed.at(bb->index);
 
184
        return processed.at(bb->index());
188
185
    }
189
186
 
190
187
    void markAsProcessed(BasicBlock *bb)
191
188
    {
192
 
        processed.setBit(bb->index);
 
189
        processed.setBit(bb->index());
193
190
    }
194
191
};
195
192
 
223
220
 
224
221
    Numbers *blockNumbers;
225
222
    Flags *blockFlags;
226
 
    QVector<BasicBlock *> allBlocks;
 
223
    IR::Function *function;
227
224
    enum { MaxVectorCapacity = 8 };
228
225
 
229
226
    // Q_DISABLE_COPY(BasicBlockSet); disabled because MSVC wants assignment operator for std::vector
246
243
                else
247
244
                    flagIt = set.blockFlags->size();
248
245
            } else {
249
 
                if (set.blockNumbers) {
 
246
                if (set.blockNumbers)
250
247
                    numberIt = set.blockNumbers->begin();
251
 
                } else {
252
 
                    flagIt = 0;
253
 
                    size_t eIt = set.blockFlags->size();
254
 
                    while (flagIt != eIt) {
255
 
                        if (set.blockFlags->operator[](flagIt))
256
 
                            break;
257
 
                        else
258
 
                            ++flagIt;
259
 
                    }
260
 
                }
 
248
                else
 
249
                    findNextWithFlags(0);
261
250
            }
262
251
        }
263
252
 
 
253
        void findNextWithFlags(size_t start)
 
254
        {
 
255
            flagIt = std::distance(set.blockFlags->begin(),
 
256
                                   std::find(set.blockFlags->begin() + start,
 
257
                                             set.blockFlags->end(),
 
258
                                             true));
 
259
 
 
260
            // The ++operator of std::vector<bool>::iterator in libc++ has a bug when using it on an
 
261
            // iterator pointing to the last element. It will not be set to ::end(), but beyond
 
262
            // that. (It will be set to the first multiple of the native word size that is bigger
 
263
            // than size().)
 
264
            //
 
265
            // See http://llvm.org/bugs/show_bug.cgi?id=19663
 
266
            //
 
267
            // As we use the size to for our end() iterator, take the minimum of the size and the
 
268
            // distance for the flagIt:
 
269
            flagIt = qMin(flagIt, set.blockFlags->size());
 
270
 
 
271
            Q_ASSERT(flagIt <= set.blockFlags->size());
 
272
        }
 
273
 
264
274
    public:
265
275
        BasicBlock *operator*() const
266
276
        {
267
277
            if (set.blockNumbers) {
268
 
                return set.allBlocks.at(*numberIt);
 
278
                return set.function->basicBlock(*numberIt);
269
279
            } else {
270
280
                Q_ASSERT(flagIt <= INT_MAX);
271
 
                return set.allBlocks.at(static_cast<int>(flagIt));
 
281
                return set.function->basicBlock(static_cast<int>(flagIt));
272
282
            }
273
283
        }
274
284
 
287
297
 
288
298
        const_iterator &operator++()
289
299
        {
290
 
            if (set.blockNumbers) {
 
300
            if (set.blockNumbers)
291
301
                ++numberIt;
292
 
            } else {
293
 
                size_t eIt = set.blockFlags->size();
294
 
                while (flagIt != eIt) {
295
 
                     ++flagIt;
296
 
                    if (flagIt == eIt || set.blockFlags->operator[](flagIt))
297
 
                        break;
298
 
                }
299
 
            }
 
302
            else
 
303
                findNextWithFlags(flagIt + 1);
300
304
 
301
305
            return *this;
302
306
        }
305
309
    friend class const_iterator;
306
310
 
307
311
public:
308
 
    BasicBlockSet(): blockNumbers(0), blockFlags(0) {}
 
312
    BasicBlockSet(): blockNumbers(0), blockFlags(0), function(0) {}
309
313
#ifdef Q_COMPILER_RVALUE_REFS
310
314
    BasicBlockSet(BasicBlockSet &&other): blockNumbers(0), blockFlags(0)
311
315
    {
312
316
        std::swap(blockNumbers, other.blockNumbers);
313
317
        std::swap(blockFlags, other.blockFlags);
314
 
        std::swap(allBlocks, other.allBlocks);
 
318
        std::swap(function, other.function);
315
319
    }
316
320
 
317
321
#endif // Q_COMPILER_RVALUE_REFS
318
322
    ~BasicBlockSet() { delete blockNumbers; delete blockFlags; }
319
323
 
320
 
    void init(const QVector<BasicBlock *> &nodes)
 
324
    void init(IR::Function *f)
321
325
    {
322
 
        Q_ASSERT(allBlocks.isEmpty());
323
 
        allBlocks = nodes;
 
326
        Q_ASSERT(!function);
 
327
        Q_ASSERT(f);
 
328
        function = f;
324
329
        blockNumbers = new Numbers;
325
330
        blockNumbers->reserve(MaxVectorCapacity);
326
331
    }
328
333
    void insert(BasicBlock *bb)
329
334
    {
330
335
        if (blockFlags) {
331
 
            (*blockFlags)[bb->index] = true;
 
336
            (*blockFlags)[bb->index()] = true;
332
337
            return;
333
338
        }
334
339
 
335
340
        for (std::vector<int>::const_iterator i = blockNumbers->begin(), ei = blockNumbers->end();
336
341
             i != ei; ++i)
337
 
            if (*i == bb->index)
 
342
            if (*i == bb->index())
338
343
                return;
339
344
 
340
345
        if (blockNumbers->size() == MaxVectorCapacity) {
341
 
            blockFlags = new Flags(allBlocks.size(), false);
 
346
            blockFlags = new Flags(function->basicBlockCount(), false);
342
347
            for (std::vector<int>::const_iterator i = blockNumbers->begin(), ei = blockNumbers->end();
343
348
                 i != ei; ++i)
344
349
                blockFlags->operator[](*i) = true;
345
350
            delete blockNumbers;
346
351
            blockNumbers = 0;
347
 
            blockFlags->operator[](bb->index) = true;
 
352
            blockFlags->operator[](bb->index()) = true;
348
353
        } else {
349
 
            blockNumbers->push_back(bb->index);
 
354
            blockNumbers->push_back(bb->index());
350
355
        }
351
356
    }
352
357
 
368
373
    typedef int BasicBlockIndex;
369
374
    enum { InvalidBasicBlockIndex = -1 };
370
375
 
371
 
    QVector<BasicBlock *> nodes;
 
376
    IR::Function *function;
372
377
    int N;
373
378
    std::vector<int> dfnum; // BasicBlock index -> dfnum
374
379
    std::vector<int> vertex;
407
412
                vertex[N] = n;
408
413
                parent[n] = todo.parent;
409
414
                ++N;
410
 
                const QVector<BasicBlock *> &out = nodes[n]->out;
 
415
                const QVector<BasicBlock *> &out = function->basicBlock(n)->out;
411
416
                for (int i = out.size() - 1; i > 0; --i)
412
 
                    worklist.push_back(DFSTodo(out[i]->index, n));
 
417
                    worklist.push_back(DFSTodo(out[i]->index(), n));
413
418
 
414
419
                if (out.size() > 0) {
415
 
                    todo.node = out.first()->index;
 
420
                    todo.node = out.first()->index();
416
421
                    todo.parent = n;
417
422
                    continue;
418
423
                }
460
465
    }
461
466
 
462
467
    void calculateIDoms() {
463
 
        Q_ASSERT(nodes.first()->in.isEmpty());
 
468
        Q_ASSERT(function->basicBlock(0)->in.isEmpty());
464
469
 
465
 
        vertex = std::vector<int>(nodes.size(), InvalidBasicBlockIndex);
466
 
        parent = std::vector<int>(nodes.size(), InvalidBasicBlockIndex);
467
 
        dfnum = std::vector<int>(nodes.size(), 0);
468
 
        semi = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
469
 
        ancestor = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
470
 
        idom = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
471
 
        samedom = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
472
 
        best = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
 
470
        const int bbCount = function->basicBlockCount();
 
471
        vertex = std::vector<int>(bbCount, InvalidBasicBlockIndex);
 
472
        parent = std::vector<int>(bbCount, InvalidBasicBlockIndex);
 
473
        dfnum = std::vector<int>(bbCount, 0);
 
474
        semi = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
 
475
        ancestor = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
 
476
        idom = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
 
477
        samedom = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
 
478
        best = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
473
479
 
474
480
        QHash<BasicBlockIndex, std::vector<BasicBlockIndex> > bucket;
 
481
        bucket.reserve(bbCount);
475
482
 
476
 
        DFS(nodes.first()->index);
477
 
        Q_ASSERT(N == nodes.size()); // fails with unreachable nodes, but those should have been removed before.
 
483
        DFS(function->basicBlock(0)->index());
 
484
        Q_ASSERT(N == function->liveBasicBlocksCount());
478
485
 
479
486
        std::vector<BasicBlockIndex> worklist;
480
487
        worklist.reserve(vertex.capacity() / 2);
484
491
            BasicBlockIndex p = parent[n];
485
492
            BasicBlockIndex s = p;
486
493
 
487
 
            foreach (BasicBlock *v, nodes.at(n)->in) {
 
494
            foreach (BasicBlock *v, function->basicBlock(n)->in) {
488
495
                BasicBlockIndex ss = InvalidBasicBlockIndex;
489
 
                if (dfnum[v->index] <= dfnum[n])
490
 
                    ss = v->index;
 
496
                if (dfnum[v->index()] <= dfnum[n])
 
497
                    ss = v->index();
491
498
                else
492
 
                    ss = semi[ancestorWithLowestSemi(v->index, worklist)];
 
499
                    ss = semi[ancestorWithLowestSemi(v->index(), worklist)];
493
500
                if (dfnum[ss] < dfnum[s])
494
501
                    s = ss;
495
502
            }
537
544
                qout << "(none)";
538
545
            qout << " -> " << to->index << endl;
539
546
        }
 
547
        qout << "N = " << N << endl;
540
548
#endif // SHOW_SSA
541
549
    }
542
550
 
548
556
    void computeDF() {
549
557
        // compute children of each node in the dominator tree
550
558
        std::vector<std::vector<BasicBlockIndex> > children; // BasicBlock index -> children
551
 
        children.resize(nodes.size());
552
 
        foreach (BasicBlock *n, nodes) {
553
 
            const BasicBlockIndex nodeIndex = n->index;
554
 
            Q_ASSERT(nodes.at(nodeIndex) == n);
 
559
        children.resize(function->basicBlockCount());
 
560
        foreach (BasicBlock *n, function->basicBlocks()) {
 
561
            if (n->isRemoved())
 
562
                continue;
 
563
            const BasicBlockIndex nodeIndex = n->index();
 
564
            Q_ASSERT(function->basicBlock(nodeIndex) == n);
555
565
            const BasicBlockIndex nodeDominator = idom[nodeIndex];
556
566
            if (nodeDominator == InvalidBasicBlockIndex)
557
567
                continue; // there is no dominator to add this node to as a child (e.g. the start node)
560
570
 
561
571
        // Fill the worklist and initialize the node status for each basic-block
562
572
        QHash<BasicBlockIndex, NodeProgress> nodeStatus;
563
 
        nodeStatus.reserve(nodes.size());
 
573
        nodeStatus.reserve(function->basicBlockCount());
564
574
        std::vector<BasicBlockIndex> worklist;
565
 
        worklist.reserve(nodes.size() * 2);
566
 
        for (int i = 0, ei = nodes.size(); i != ei; ++i) {
567
 
            BasicBlockIndex nodeIndex = nodes.at(i)->index;
 
575
        worklist.reserve(function->basicBlockCount() * 2);
 
576
        foreach (BasicBlock *bb, function->basicBlocks()) {
 
577
            if (bb->isRemoved())
 
578
                continue;
 
579
            BasicBlockIndex nodeIndex = bb->index();
568
580
            worklist.push_back(nodeIndex);
569
581
            NodeProgress &np = nodeStatus[nodeIndex];
570
582
            np.children = children[nodeIndex];
571
583
            np.todo = children[nodeIndex];
572
584
        }
573
585
 
574
 
        std::vector<bool> DF_done(nodes.size(), false);
 
586
        std::vector<bool> DF_done(function->basicBlockCount(), false);
575
587
 
576
588
        while (!worklist.empty()) {
577
589
            BasicBlockIndex node = worklist.back();
594
606
 
595
607
            if (np.todo.empty()) {
596
608
                BasicBlockSet &S = DF[node];
597
 
                S.init(nodes);
598
 
                foreach (BasicBlock *y, nodes.at(node)->out)
599
 
                    if (idom[y->index] != node)
 
609
                S.init(function);
 
610
                foreach (BasicBlock *y, function->basicBlock(node)->out)
 
611
                    if (idom[y->index()] != node)
600
612
                        S.insert(y);
601
613
                foreach (BasicBlockIndex child, np.children) {
602
614
                    const BasicBlockSet &ws = DF[child];
603
615
                    for (BasicBlockSet::const_iterator it = ws.begin(), eit = ws.end(); it != eit; ++it) {
604
616
                        BasicBlock *w = *it;
605
 
                        const BasicBlockIndex wIndex = w->index;
606
 
                        if (node == wIndex || !dominates(node, w->index))
 
617
                        const BasicBlockIndex wIndex = w->index();
 
618
                        if (node == wIndex || !dominates(node, w->index()))
607
619
                            S.insert(w);
608
620
                    }
609
621
                }
648
660
    }
649
661
 
650
662
public:
651
 
    DominatorTree(const QVector<BasicBlock *> &nodes)
652
 
        : nodes(nodes)
 
663
    DominatorTree(IR::Function *function)
 
664
        : function(function)
653
665
        , N(0)
654
666
    {
655
 
        DF.resize(nodes.size());
 
667
        DF.resize(function->basicBlockCount());
656
668
        calculateIDoms();
657
669
        computeDF();
658
670
    }
659
671
 
660
672
    const BasicBlockSet &dominatorFrontier(BasicBlock *n) const {
661
 
        return DF[n->index];
 
673
        return DF[n->index()];
662
674
    }
663
675
 
664
676
    BasicBlock *immediateDominator(BasicBlock *bb) const {
665
 
        return nodes[idom[bb->index]];
 
677
        return function->basicBlock(idom[bb->index()]);
666
678
    }
667
679
 
668
680
    void dumpImmediateDominators() const
677
689
 
678
690
    void updateImmediateDominator(BasicBlock *bb, BasicBlock *newDominator)
679
691
    {
680
 
        Q_ASSERT(bb->index >= 0);
 
692
        Q_ASSERT(bb->index() >= 0);
681
693
 
682
 
        int blockIndex;
683
 
        if (static_cast<std::vector<BasicBlockIndex>::size_type>(bb->index) >= idom.size()) {
 
694
        if (static_cast<std::vector<BasicBlockIndex>::size_type>(bb->index()) >= idom.size()) {
684
695
            // This is a new block, probably introduced by edge splitting. So, we'll have to grow
685
696
            // the array before inserting the immediate dominator.
686
 
            nodes.append(bb);
687
 
            idom.resize(nodes.size(), InvalidBasicBlockIndex);
688
 
            blockIndex = nodes.size() - 1;
689
 
        } else {
690
 
            blockIndex = getBlockIndex(bb);
 
697
            idom.resize(function->basicBlockCount(), InvalidBasicBlockIndex);
691
698
        }
692
699
 
693
 
        idom[blockIndex] = getBlockIndex(newDominator);
 
700
        idom[bb->index()] = newDominator->index();
694
701
    }
695
702
 
696
703
    bool dominates(BasicBlock *dominator, BasicBlock *dominated) const {
697
 
        // The index of the basic blocks might have changed, or the nodes array might have changed,
698
 
        // so get the index from our copy of the array.
699
 
        return dominates(getBlockIndex(dominator), getBlockIndex(dominated));
 
704
        return dominates(dominator->index(), dominated->index());
700
705
    }
701
706
 
702
707
private:
703
 
    int getBlockIndex(BasicBlock *bb) const {
704
 
        if (!bb)
705
 
            return InvalidBasicBlockIndex;
706
 
 
707
 
        if (bb->index >= 0 && bb->index < nodes.size()) {
708
 
            if (nodes.at(bb->index) == bb)
709
 
                return bb->index;
710
 
        }
711
 
 
712
 
        return nodes.indexOf(bb);
713
 
    }
714
 
 
715
708
    bool dominates(BasicBlockIndex dominator, BasicBlockIndex dominated) const {
716
709
        // dominator can be Invalid when the dominated block has no dominator (i.e. the start node)
717
710
        Q_ASSERT(dominated != InvalidBasicBlockIndex);
718
711
 
719
 
        for (BasicBlockIndex it = dominated; it != InvalidBasicBlockIndex; it = idom[it]) {
 
712
        if (dominator == dominated)
 
713
            return false;
 
714
 
 
715
        for (BasicBlockIndex it = idom[dominated]; it != InvalidBasicBlockIndex; it = idom[it]) {
720
716
            if (it == dominator)
721
717
                return true;
722
718
        }
726
722
};
727
723
 
728
724
class VariableCollector: public StmtVisitor, ExprVisitor {
729
 
    QHash<Temp, QSet<BasicBlock *> > _defsites;
730
 
    QHash<BasicBlock *, QSet<Temp> > A_orig;
 
725
    typedef QHash<Temp, QSet<BasicBlock *> > DefSites;
 
726
    DefSites _defsites;
 
727
    QVector<QSet<Temp> > A_orig;
731
728
    QSet<Temp> nonLocals;
732
729
    QSet<Temp> killed;
733
730
 
744
741
        : function(function)
745
742
    {
746
743
        _defsites.reserve(function->tempCount);
 
744
        A_orig.resize(function->basicBlockCount());
 
745
        for (int i = 0, ei = A_orig.size(); i != ei; ++i)
 
746
            A_orig[i].reserve(8);
747
747
 
748
748
#if defined(SHOW_SSA)
749
749
        qout << "Variables collected:" << endl;
750
750
#endif // SHOW_SSA
751
751
 
752
 
        foreach (BasicBlock *bb, function->basicBlocks) {
 
752
        foreach (BasicBlock *bb, function->basicBlocks()) {
 
753
            if (bb->isRemoved())
 
754
                continue;
 
755
 
753
756
            currentBB = bb;
754
757
            killed.clear();
755
 
            killed.reserve(bb->statements.size() / 2);
756
 
            foreach (Stmt *s, bb->statements) {
 
758
            killed.reserve(bb->statements().size() / 2);
 
759
            foreach (Stmt *s, bb->statements()) {
757
760
                s->accept(this);
758
761
            }
759
762
        }
779
782
    }
780
783
 
781
784
    QSet<Temp> inBlock(BasicBlock *n) const {
782
 
        return A_orig[n];
 
785
        return A_orig.at(n->index());
783
786
    }
784
787
 
785
788
    bool isNonLocal(const Temp &var) const { return nonLocals.contains(var); }
825
828
                qout << " -> L" << currentBB->index << endl;
826
829
#endif // SHOW_SSA
827
830
 
828
 
                _defsites[*t].insert(currentBB);
829
 
                A_orig[currentBB].insert(*t);
 
831
                DefSites::iterator defsitesIt = _defsites.find(*t);
 
832
                if (defsitesIt == _defsites.end()) {
 
833
                    QSet<BasicBlock *> bbs;
 
834
                    bbs.reserve(4);
 
835
                    defsitesIt = _defsites.insert(*t, bbs);
 
836
                }
 
837
                defsitesIt->insert(currentBB);
 
838
 
 
839
                A_orig[currentBB->index()].insert(*t);
830
840
 
831
841
                // For semi-pruned SSA:
832
842
                killed.insert(*t);
855
865
    phiNode->d = new Stmt::Data;
856
866
    phiNode->targetTemp = f->New<Temp>();
857
867
    phiNode->targetTemp->init(a.kind, a.index, 0);
858
 
    y->statements.prepend(phiNode);
 
868
    y->prependStatement(phiNode);
859
869
 
860
870
    phiNode->d->incoming.resize(y->in.size());
861
871
    for (int i = 0, ei = y->in.size(); i < ei; ++i) {
994
1004
    VariableRenamer(IR::Function *f)
995
1005
        : function(f)
996
1006
        , tempCount(0)
997
 
        , processed(f->basicBlocks)
 
1007
        , processed(f)
998
1008
    {
999
1009
        localMapping.reserve(f->tempCount);
1000
1010
        vregMapping.reserve(f->tempCount);
1001
 
        todo.reserve(f->basicBlocks.size());
 
1011
        todo.reserve(f->basicBlockCount());
1002
1012
    }
1003
1013
 
1004
1014
    void run() {
1005
 
        todo.append(TodoAction(function->basicBlocks.first()));
 
1015
        todo.append(TodoAction(function->basicBlock(0)));
1006
1016
 
1007
1017
        while (!todo.isEmpty()) {
1008
1018
            TodoAction todoAction = todo.back();
1057
1067
 
1058
1068
    void renameStatementsAndPhis(BasicBlock *bb)
1059
1069
    {
1060
 
        foreach (Stmt *s, bb->statements)
 
1070
        foreach (Stmt *s, bb->statements())
1061
1071
            s->accept(this);
1062
1072
 
1063
1073
        foreach (BasicBlock *Y, bb->out) {
1064
1074
            const int j = Y->in.indexOf(bb);
1065
1075
            Q_ASSERT(j >= 0 && j < Y->in.size());
1066
 
            foreach (Stmt *s, Y->statements) {
 
1076
            foreach (Stmt *s, Y->statements()) {
1067
1077
                if (Phi *phi = s->asPhi()) {
1068
1078
                    Temp *t = phi->d->incoming[j]->asTemp();
1069
1079
                    unsigned newTmp = currentNumber(*t);
1198
1208
 
1199
1209
void convertToSSA(IR::Function *function, const DominatorTree &df)
1200
1210
{
1201
 
#ifdef SHOW_SSA
 
1211
#if defined(SHOW_SSA)
1202
1212
    qout << "Converting function ";
1203
1213
    if (function->name)
1204
1214
        qout << *function->name;
1210
1220
    // Collect all applicable variables:
1211
1221
    VariableCollector variables(function);
1212
1222
 
 
1223
    // Prepare for phi node insertion:
 
1224
    QVector<QSet<Temp> > A_phi;
 
1225
    A_phi.resize(function->basicBlockCount());
 
1226
    for (int i = 0, ei = A_phi.size(); i != ei; ++i) {
 
1227
        QSet<Temp> temps;
 
1228
        temps.reserve(4);
 
1229
        A_phi[i] = temps;
 
1230
    }
 
1231
 
1213
1232
    // Place phi functions:
1214
 
    QHash<BasicBlock *, QSet<Temp> > A_phi;
1215
1233
    foreach (Temp a, variables.vars()) {
1216
1234
        if (!variables.isNonLocal(a))
1217
1235
            continue; // for semi-pruned SSA
1224
1242
            for (BasicBlockSet::const_iterator it = dominatorFrontierForN.begin(), eit = dominatorFrontierForN.end();
1225
1243
                 it != eit; ++it) {
1226
1244
                BasicBlock *y = *it;
1227
 
                if (!A_phi[y].contains(a)) {
 
1245
                if (!A_phi.at(y->index()).contains(a)) {
1228
1246
                    insertPhiNode(a, y, function);
1229
 
                    A_phi[y].insert(a);
 
1247
                    A_phi[y->index()].insert(a);
1230
1248
                    if (!variables.inBlock(y).contains(a))
1231
1249
                        W.append(y);
1232
1250
                }
1264
1282
 
1265
1283
private:
1266
1284
    IR::Function *function;
1267
 
    QHash<UntypedTemp, DefUse> _defUses;
 
1285
    typedef QHash<UntypedTemp, DefUse> DefUses;
 
1286
    DefUses _defUses;
1268
1287
    QHash<Stmt *, QList<Temp> > _usesPerStatement;
1269
1288
 
1270
1289
    BasicBlock *_block;
1299
1318
    DefUsesCalculator(IR::Function *function)
1300
1319
        : function(function)
1301
1320
    {
1302
 
        foreach (BasicBlock *bb, function->basicBlocks) {
 
1321
        foreach (BasicBlock *bb, function->basicBlocks()) {
 
1322
            if (bb->isRemoved())
 
1323
                continue;
 
1324
 
1303
1325
            _block = bb;
1304
 
            foreach (Stmt *stmt, bb->statements) {
 
1326
            foreach (Stmt *stmt, bb->statements()) {
1305
1327
                _stmt = stmt;
1306
1328
                stmt->accept(this);
1307
1329
            }
1357
1379
    QList<Temp> usedVars(Stmt *s) const
1358
1380
    { return _usesPerStatement[s]; }
1359
1381
 
1360
 
    QList<Stmt *> uses(const UntypedTemp &var) const
1361
 
    { return _defUses[var].uses; }
 
1382
    const QList<Stmt *> &uses(const UntypedTemp &var) const
 
1383
    {
 
1384
        static const QList<Stmt *> noUses;
 
1385
 
 
1386
        DefUses::const_iterator it = _defUses.find(var);
 
1387
        if (it == _defUses.end())
 
1388
            return noUses;
 
1389
        else
 
1390
            return it->uses;
 
1391
    }
1362
1392
 
1363
1393
    QVector<Stmt*> removeDefUses(Stmt *s)
1364
1394
    {
1383
1413
        foreach (const UntypedTemp &var, _defUses.keys()) {
1384
1414
            const DefUse &du = _defUses[var];
1385
1415
            var.temp.dump(qout);
1386
 
            qout<<" -> defined in block "<<du.blockOfStatement->index<<", statement: ";
 
1416
            qout<<" -> defined in block "<<du.blockOfStatement->index()<<", statement: ";
1387
1417
            du.defStmt->dump(qout);
1388
1418
            qout<<endl<<"     uses:"<<endl;
1389
1419
            foreach (Stmt *s, du.uses) {
1475
1505
    foreach (Phi *phi, toRemove) {
1476
1506
        Temp targetVar = *phi->targetTemp;
1477
1507
 
1478
 
        BasicBlock *bb = defUses.defStmtBlock(targetVar);
1479
 
        int idx = bb->statements.indexOf(phi);
1480
 
        bb->statements[idx]->destroyData();
1481
 
        bb->statements.remove(idx);
 
1508
        defUses.defStmtBlock(targetVar)->removeStatement(phi);
1482
1509
 
1483
1510
        foreach (const Temp &usedVar, defUses.usedVars(phi))
1484
1511
            defUses.removeUse(phi, usedVar);
1490
1517
{
1491
1518
    QVector<Stmt *> worklist;
1492
1519
    QBitArray inWorklist;
1493
 
    QHash<Stmt*,Stmt**> ref;
 
1520
    QSet<Stmt *> removed;
 
1521
    QHash<Stmt*,Stmt*> replaced;
 
1522
 
 
1523
    Q_DISABLE_COPY(StatementWorklist)
1494
1524
 
1495
1525
public:
1496
1526
    StatementWorklist(IR::Function *function)
1500
1530
 
1501
1531
        // Put in all statements, and number them on the fly. The numbering is used to index the
1502
1532
        // bit array.
1503
 
        foreach (BasicBlock *bb, function->basicBlocks) {
1504
 
            for (int i = 0, ei = bb->statements.size(); i != ei; ++i) {
1505
 
                Stmt **s = &bb->statements[i];
1506
 
                (*s)->id = stmtCount++;
1507
 
                w.append(*s);
1508
 
                ref.insert(*s, s);
 
1533
        foreach (BasicBlock *bb, function->basicBlocks()) {
 
1534
            if (bb->isRemoved())
 
1535
                continue;
 
1536
 
 
1537
            foreach (Stmt *s, bb->statements()) {
 
1538
                s->id = stmtCount++;
 
1539
                w.append(s);
1509
1540
            }
1510
1541
        }
1511
1542
 
1524
1555
    void clear(Stmt *stmt)
1525
1556
    {
1526
1557
        Q_ASSERT(!inWorklist.at(stmt->id));
1527
 
        *ref[stmt] = 0;
 
1558
        removed.insert(stmt);
1528
1559
    }
1529
1560
 
1530
1561
    void replace(Stmt *oldStmt, Stmt *newStmt)
1531
1562
    {
1532
1563
        Q_ASSERT(oldStmt);
1533
1564
        Q_ASSERT(newStmt);
 
1565
        Q_ASSERT(!removed.contains(oldStmt));
1534
1566
 
1535
1567
        if (newStmt->id == -1)
1536
1568
            newStmt->id = oldStmt->id;
1537
 
        *ref[oldStmt] = newStmt;
 
1569
        QHash<Stmt *, Stmt *>::const_iterator it = replaced.find(oldStmt);
 
1570
        if (it != replaced.end())
 
1571
            oldStmt = it.key();
 
1572
        replaced[oldStmt] = newStmt;
1538
1573
    }
1539
1574
 
1540
1575
    void cleanup(IR::Function *function)
1541
1576
    {
1542
 
        foreach (BasicBlock *bb, function->basicBlocks) {
1543
 
            for (int i = 0; i < bb->statements.size();) {
1544
 
                if (bb->statements[i]) {
1545
 
                    bb->statements[i]->id = -1;
1546
 
                    ++i;
1547
 
                } else {
1548
 
                    bb->statements.remove(i);
 
1577
        foreach (BasicBlock *bb, function->basicBlocks()) {
 
1578
            if (bb->isRemoved())
 
1579
                continue;
 
1580
 
 
1581
            for (int i = 0; i < bb->statementCount();) {
 
1582
                Stmt *stmt = bb->statements()[i];
 
1583
                QHash<Stmt *, Stmt *>::const_iterator it = replaced.find(stmt);
 
1584
                if (it != replaced.end() && !removed.contains(it.value())) {
 
1585
                    bb->replaceStatement(i, it.value());
 
1586
                } else if (removed.contains(stmt)) {
 
1587
                    bb->removeStatement(i);
 
1588
                    continue;
1549
1589
                }
 
1590
 
 
1591
                ++i;
1550
1592
            }
1551
1593
        }
1552
1594
    }
1846
1888
    QQmlEnginePrivate *qmlEngine;
1847
1889
    IR::Function *function;
1848
1890
    const DefUsesCalculator &_defUses;
1849
 
    QHash<Temp, DiscoveredType> _tempTypes;
1850
 
    QSet<Stmt *> _worklist;
 
1891
    typedef QHash<Temp, DiscoveredType> TempTypes;
 
1892
    TempTypes _tempTypes;
 
1893
    QList<Stmt *> _worklist;
1851
1894
    struct TypingResult {
1852
1895
        DiscoveredType type;
1853
1896
        bool fullyTyped;
1869
1912
 
1870
1913
        // TODO: the worklist handling looks a bit inefficient... check if there is something better
1871
1914
        _worklist.clear();
1872
 
        for (int i = 0, ei = function->basicBlocks.size(); i != ei; ++i) {
1873
 
            BasicBlock *bb = function->basicBlocks[i];
 
1915
        for (int i = 0, ei = function->basicBlockCount(); i != ei; ++i) {
 
1916
            BasicBlock *bb = function->basicBlock(i);
 
1917
            if (bb->isRemoved())
 
1918
                continue;
1874
1919
            if (i == 0 || !bb->in.isEmpty())
1875
 
                foreach (Stmt *s, bb->statements)
1876
 
                    if (!s->asJump())
1877
 
                        _worklist.insert(s);
 
1920
                _worklist += bb->statements().toList();
1878
1921
        }
1879
1922
 
1880
1923
        while (!_worklist.isEmpty()) {
1881
 
            QList<Stmt *> worklist = _worklist.values();
 
1924
            QList<Stmt *> worklist = QSet<Stmt *>::fromList(_worklist).toList();
1882
1925
            _worklist.clear();
1883
1926
            while (!worklist.isEmpty()) {
1884
1927
                Stmt *s = worklist.first();
1885
1928
                worklist.removeFirst();
 
1929
                if (s->asJump())
 
1930
                    continue;
 
1931
 
1886
1932
#if defined(SHOW_SSA)
1887
1933
                qout<<"Typing stmt ";s->dump(qout);qout<<endl;
1888
1934
#endif
1889
1935
 
1890
1936
                if (!run(s)) {
1891
 
                    _worklist.insert(s);
 
1937
                    _worklist += s;
1892
1938
#if defined(SHOW_SSA)
1893
1939
                    qout<<"Pushing back stmt: ";
1894
1940
                    s->dump(qout);qout<<endl;
1939
1985
#endif
1940
1986
            if (isAlwaysVar(t))
1941
1987
                ty = DiscoveredType(VarType);
1942
 
            if (_tempTypes[*t] != ty) {
1943
 
                _tempTypes[*t] = ty;
 
1988
            TempTypes::iterator it = _tempTypes.find(*t);
 
1989
            if (it == _tempTypes.end())
 
1990
                it = _tempTypes.insert(*t, DiscoveredType());
 
1991
            if (it.value() != ty) {
 
1992
                it.value() = ty;
1944
1993
 
1945
1994
#if defined(SHOW_SSA)
1946
1995
                foreach (Stmt *s, _defUses.uses(*t)) {
1950
1999
                }
1951
2000
#endif
1952
2001
 
1953
 
                _worklist += QSet<Stmt *>::fromList(_defUses.uses(*t));
 
2002
                _worklist += _defUses.uses(*t);
1954
2003
            }
1955
2004
        } else {
1956
2005
            e->type = (Type) ty.type;
2240
2289
private:
2241
2290
    bool isUsedAsInt32(const UntypedTemp &t, const QVector<UntypedTemp> &knownOk) const
2242
2291
    {
2243
 
        QList<Stmt *> uses = _defUses.uses(t);
 
2292
        const QList<Stmt *> &uses = _defUses.uses(t);
2244
2293
        if (uses.isEmpty())
2245
2294
            return false;
2246
2295
 
2370
2419
 
2371
2420
    void run(IR::Function *f) {
2372
2421
        _f = f;
2373
 
        foreach (BasicBlock *bb, f->basicBlocks) {
 
2422
        foreach (BasicBlock *bb, f->basicBlocks()) {
 
2423
            if (bb->isRemoved())
 
2424
                continue;
2374
2425
            _conversions.clear();
2375
2426
 
2376
 
            foreach (Stmt *s, bb->statements) {
 
2427
            foreach (Stmt *s, bb->statements()) {
2377
2428
                _currStmt = s;
2378
2429
                s->accept(this);
2379
2430
            }
2404
2455
                    if (Phi *phi = conversion.stmt->asPhi()) {
2405
2456
                        int idx = phi->d->incoming.indexOf(t);
2406
2457
                        Q_ASSERT(idx != -1);
2407
 
                        QVector<Stmt *> &stmts = bb->in[idx]->statements;
2408
 
                        stmts.insert(stmts.size() - 1, convCall);
 
2458
                        bb->in[idx]->insertStatementBeforeTerminator(convCall);
2409
2459
                    } else {
2410
 
                        int idx = bb->statements.indexOf(conversion.stmt);
2411
 
                        bb->statements.insert(idx, convCall);
 
2460
                        bb->insertStatementBefore(conversion.stmt, convCall);
2412
2461
                    }
2413
2462
 
2414
2463
                    *conversion.expr = source;
2429
2478
                        _defUses.removeUse(move, *unopOperand);
2430
2479
                    }
2431
2480
 
2432
 
                    int idx = bb->statements.indexOf(conversion.stmt);
2433
 
                    Q_ASSERT(idx != -1);
2434
 
                    bb->statements.insert(idx, extraMove);
 
2481
                    bb->insertStatementBefore(conversion.stmt, extraMove);
2435
2482
 
2436
2483
                    *conversion.expr = bb->CONVERT(tmp, conversion.targetType);
2437
2484
                    _defUses.addUse(*tmp, move);
2563
2610
 
2564
2611
void splitCriticalEdges(IR::Function *f, DominatorTree &df)
2565
2612
{
2566
 
    for (int i = 0, ei = f->basicBlocks.size(); i != ei; ++i) {
2567
 
        BasicBlock *bb = f->basicBlocks[i];
2568
 
        if (bb->in.size() > 1) {
2569
 
            for (int inIdx = 0, eInIdx = bb->in.size(); inIdx != eInIdx; ++inIdx) {
2570
 
                BasicBlock *inBB = bb->in[inIdx];
2571
 
                if (inBB->out.size() > 1) { // this should have been split!
2572
 
                    int newIndex = f->basicBlocks.last()->index + 1;
2573
 
#if defined(SHOW_SSA)
2574
 
                    qDebug() << "Splitting edge from block" << inBB->index << "to block" << bb->index << "by introducing block" << newIndex;
2575
 
#endif
2576
 
 
2577
 
                    BasicBlock *containingGroup = inBB->isGroupStart() ? inBB : inBB->containingGroup();
2578
 
 
2579
 
                    // create the basic block:
2580
 
                    BasicBlock *newBB = new BasicBlock(f, containingGroup, bb->catchBlock);
2581
 
                    newBB->index = newIndex;
2582
 
                    f->basicBlocks.append(newBB);
2583
 
                    Jump *s = f->New<Jump>();
2584
 
                    s->init(bb);
2585
 
                    newBB->statements.append(s);
2586
 
 
2587
 
                    // rewire the old outgoing edge
2588
 
                    int outIdx = inBB->out.indexOf(bb);
2589
 
                    inBB->out[outIdx] = newBB;
2590
 
                    newBB->in.append(inBB);
2591
 
 
2592
 
                    // rewire the old incoming edge
2593
 
                    bb->in[inIdx] = newBB;
2594
 
                    newBB->out.append(bb);
2595
 
 
2596
 
                    // patch the terminator
2597
 
                    Stmt *terminator = inBB->terminator();
2598
 
                    if (Jump *j = terminator->asJump()) {
2599
 
                        Q_ASSERT(outIdx == 0);
2600
 
                        j->target = newBB;
2601
 
                    } else if (CJump *j = terminator->asCJump()) {
2602
 
                        if (outIdx == 0)
2603
 
                            j->iftrue = newBB;
2604
 
                        else if (outIdx == 1)
2605
 
                            j->iffalse = newBB;
2606
 
                        else
2607
 
                            Q_ASSERT(!"Invalid out edge index for CJUMP!");
2608
 
                    } else {
2609
 
                        Q_ASSERT(!"Unknown terminator!");
2610
 
                    }
2611
 
 
2612
 
                    // Set the immediate dominator of the new block to inBB
2613
 
                    df.updateImmediateDominator(newBB, inBB);
2614
 
                }
 
2613
    foreach (BasicBlock *bb, f->basicBlocks()) {
 
2614
        if (bb->isRemoved())
 
2615
            continue;
 
2616
        if (bb->in.size() < 2)
 
2617
            continue;
 
2618
 
 
2619
        for (int inIdx = 0, eInIdx = bb->in.size(); inIdx != eInIdx; ++inIdx) {
 
2620
            BasicBlock *inBB = bb->in[inIdx];
 
2621
            if (inBB->out.size() < 2)
 
2622
                continue;
 
2623
 
 
2624
            // We found a critical edge.
 
2625
            BasicBlock *containingGroup = inBB->isGroupStart() ? inBB : inBB->containingGroup();
 
2626
 
 
2627
            // create the basic block:
 
2628
            BasicBlock *newBB = f->newBasicBlock(containingGroup, bb->catchBlock);
 
2629
            Jump *s = f->New<Jump>();
 
2630
            s->init(bb);
 
2631
            newBB->appendStatement(s);
 
2632
 
 
2633
            // rewire the old outgoing edge
 
2634
            int outIdx = inBB->out.indexOf(bb);
 
2635
            inBB->out[outIdx] = newBB;
 
2636
            newBB->in.append(inBB);
 
2637
 
 
2638
            // rewire the old incoming edge
 
2639
            bb->in[inIdx] = newBB;
 
2640
            newBB->out.append(bb);
 
2641
 
 
2642
            // patch the terminator
 
2643
            Stmt *terminator = inBB->terminator();
 
2644
            if (Jump *j = terminator->asJump()) {
 
2645
                Q_ASSERT(outIdx == 0);
 
2646
                j->target = newBB;
 
2647
            } else if (CJump *j = terminator->asCJump()) {
 
2648
                if (outIdx == 0)
 
2649
                    j->iftrue = newBB;
 
2650
                else if (outIdx == 1)
 
2651
                    j->iffalse = newBB;
 
2652
                else
 
2653
                    Q_ASSERT(!"Invalid out edge index for CJUMP!");
 
2654
            } else if (terminator->asRet()) {
 
2655
                Q_ASSERT(!"A block with a RET at the end cannot have outgoing edges.");
 
2656
            } else {
 
2657
                Q_ASSERT(!"Unknown terminator!");
2615
2658
            }
 
2659
 
 
2660
            // Set the immediate dominator of the new block to inBB
 
2661
            df.updateImmediateDominator(newBB, inBB);
2616
2662
        }
2617
2663
    }
2618
2664
}
2705
2751
 
2706
2752
    void emitBlock(BasicBlock *bb)
2707
2753
    {
 
2754
        Q_ASSERT(!bb->isRemoved());
2708
2755
        if (emitted.alreadyProcessed(bb))
2709
2756
            return;
2710
2757
 
2752
2799
    BlockScheduler(IR::Function *function, const DominatorTree &dominatorTree)
2753
2800
        : function(function)
2754
2801
        , dominatorTree(dominatorTree)
2755
 
        , emitted(function->basicBlocks)
 
2802
        , sequence(0)
 
2803
        , emitted(function)
2756
2804
    {}
2757
2805
 
2758
2806
    QHash<BasicBlock *, BasicBlock *> go()
2759
2807
    {
2760
2808
        showMeTheCode(function);
2761
 
        schedule(function->basicBlocks.first());
 
2809
        schedule(function->basicBlock(0));
2762
2810
 
2763
2811
#if defined(SHOW_SSA)
2764
2812
        qDebug() << "Block sequence:";
2765
2813
        foreach (BasicBlock *bb, sequence)
2766
 
            qDebug("\tL%d", bb->index);
 
2814
            qDebug("\tL%d", bb->index());
2767
2815
#endif // SHOW_SSA
2768
2816
 
2769
 
        Q_ASSERT(function->basicBlocks.size() == sequence.size());
2770
 
        function->basicBlocks = sequence;
 
2817
        Q_ASSERT(function->liveBasicBlocksCount() == sequence.size());
 
2818
        function->setScheduledBlocks(sequence);
 
2819
        function->renumberBasicBlocks();
2771
2820
        return loopsStartEnd;
2772
2821
    }
2773
2822
};
2779
2828
            foreach (BasicBlock *bb2, bb->out) {
2780
2829
                if (bb2 && bb2->in.size() > 1) {
2781
2830
                    qout << "found critical edge between block "
2782
 
                         << bb->index << " and block " << bb2->index;
 
2831
                         << bb->index() << " and block " << bb2->index();
2783
2832
                    Q_ASSERT(false);
2784
2833
                }
2785
2834
            }
2788
2837
}
2789
2838
#endif
2790
2839
 
2791
 
void cleanupBasicBlocks(IR::Function *function, bool renumber)
 
2840
void cleanupBasicBlocks(IR::Function *function)
2792
2841
{
2793
2842
    showMeTheCode(function);
2794
2843
 
2795
2844
    // Algorithm: this is the iterative version of a depth-first search for all blocks that are
2796
2845
    // reachable through outgoing edges, starting with the start block and all exception handler
2797
2846
    // blocks.
2798
 
    QSet<BasicBlock *> postponed, done;
2799
 
    QSet<BasicBlock *> toRemove;
2800
 
    toRemove.reserve(function->basicBlocks.size());
2801
 
    done.reserve(function->basicBlocks.size());
2802
 
    postponed.reserve(8);
2803
 
    for (int i = 0, ei = function->basicBlocks.size(); i != ei; ++i) {
2804
 
        BasicBlock *bb = function->basicBlocks[i];
2805
 
        if (i == 0 || bb->isExceptionHandler)
2806
 
            postponed.insert(bb);
2807
 
        else
2808
 
            toRemove.insert(bb);
 
2847
    QBitArray reachableBlocks(function->basicBlockCount());
 
2848
    QVector<BasicBlock *> postponed;
 
2849
    postponed.reserve(16);
 
2850
    for (int i = 0, ei = function->basicBlockCount(); i != ei; ++i) {
 
2851
        BasicBlock *bb = function->basicBlock(i);
 
2852
        if (i == 0 || bb->isExceptionHandler())
 
2853
            postponed.append(bb);
2809
2854
    }
2810
2855
 
2811
2856
    while (!postponed.isEmpty()) {
2812
 
        QSet<BasicBlock *>::iterator it = postponed.begin();
2813
 
        BasicBlock *bb = *it;
2814
 
        postponed.erase(it);
2815
 
        done.insert(bb);
 
2857
        BasicBlock *bb = postponed.back();
 
2858
        postponed.pop_back();
 
2859
        if (bb->isRemoved()) // this block was removed before, we don't need to clean it up.
 
2860
            continue;
 
2861
 
 
2862
        reachableBlocks.setBit(bb->index());
2816
2863
 
2817
2864
        foreach (BasicBlock *outBB, bb->out) {
2818
 
            if (!done.contains(outBB)) {
2819
 
                postponed.insert(outBB);
2820
 
                toRemove.remove(outBB);
2821
 
            }
 
2865
            if (!reachableBlocks.at(outBB->index()))
 
2866
                postponed.append(outBB);
2822
2867
        }
2823
2868
    }
2824
2869
 
2825
 
    foreach (BasicBlock *bb, toRemove) {
 
2870
    foreach (BasicBlock *bb, function->basicBlocks()) {
 
2871
        if (bb->isRemoved()) // the block has already been removed, so ignore it
 
2872
            continue;
 
2873
        if (reachableBlocks.at(bb->index())) // the block is reachable, so ignore it
 
2874
            continue;
 
2875
 
2826
2876
        foreach (BasicBlock *outBB, bb->out) {
2827
 
            if (toRemove.contains(outBB))
 
2877
            if (outBB->isRemoved() || !reachableBlocks.at(outBB->index()))
2828
2878
                continue; // We do not need to unlink from blocks that are scheduled to be removed.
2829
 
                          // Actually, it is potentially dangerous: if that block was already
2830
 
                          // destroyed, this could result in a use-after-free.
2831
2879
 
2832
2880
            int idx = outBB->in.indexOf(bb);
2833
2881
            if (idx != -1) {
2834
2882
                outBB->in.remove(idx);
2835
 
                foreach (Stmt *s, outBB->statements) {
 
2883
                foreach (Stmt *s, outBB->statements()) {
2836
2884
                    if (Phi *phi = s->asPhi())
2837
2885
                        phi->d->incoming.remove(idx);
2838
2886
                    else
2841
2889
            }
2842
2890
        }
2843
2891
 
2844
 
        foreach (Stmt *s, bb->statements)
2845
 
            s->destroyData();
2846
 
        int idx = function->basicBlocks.indexOf(bb);
2847
 
        if (idx != -1)
2848
 
            function->basicBlocks.remove(idx);
2849
 
        delete bb;
 
2892
        function->removeBasicBlock(bb);
2850
2893
    }
2851
2894
 
2852
 
    if (renumber)
2853
 
        for (int i = 0; i < function->basicBlocks.size(); ++i)
2854
 
            function->basicBlocks[i]->index = i;
2855
 
 
2856
2895
    showMeTheCode(function);
2857
2896
}
2858
2897
 
2905
2944
        , _replacement(0)
2906
2945
    {}
2907
2946
 
2908
 
    QVector<Stmt *> operator()(Temp *toReplace, Expr *replacement)
 
2947
    void operator()(Temp *toReplace, Expr *replacement, StatementWorklist &W, QList<Stmt *> *newUses = 0)
2909
2948
    {
2910
2949
        Q_ASSERT(replacement->asTemp() || replacement->asConst() || replacement->asName());
2911
2950
 
2914
2953
        qSwap(_toReplace, toReplace);
2915
2954
        qSwap(_replacement, replacement);
2916
2955
 
2917
 
        QList<Stmt *> uses = _defUses.uses(*_toReplace);
 
2956
        const QList<Stmt *> &uses = _defUses.uses(*_toReplace);
 
2957
        if (newUses)
 
2958
            newUses->reserve(uses.size());
 
2959
 
2918
2960
//        qout << "        " << uses.size() << " uses:"<<endl;
2919
 
        QVector<Stmt *> result;
2920
 
        result.reserve(uses.size());
2921
2961
        foreach (Stmt *use, uses) {
2922
2962
//            qout<<"        ";use->dump(qout);qout<<"\n";
2923
2963
            use->accept(this);
2924
2964
//            qout<<"     -> ";use->dump(qout);qout<<"\n";
2925
 
            result.append(use);
 
2965
            W += use;
 
2966
            if (newUses)
 
2967
                newUses->append(use);
2926
2968
        }
2927
2969
 
2928
2970
        qSwap(_replacement, replacement);
2929
2971
        qSwap(_toReplace, toReplace);
2930
 
        return result;
2931
2972
    }
2932
2973
 
2933
2974
protected:
3009
3050
void purgeBB(BasicBlock *bb, IR::Function *func, DefUsesCalculator &defUses, StatementWorklist &W,
3010
3051
             DominatorTree &df)
3011
3052
{
3012
 
    // TODO: change this to mark the block as deleted, but leave it alone so that other references
3013
 
    //       won't be dangling pointers.
3014
3053
    // TODO: after the change above: if we keep on detaching the block from predecessors or
3015
3054
    //       successors, update the DominatorTree too.
3016
3055
 
3017
3056
    // don't purge blocks that are entry points for catch statements. They might not be directly
3018
3057
    // connected, but are required anyway
3019
 
    if (bb->isExceptionHandler)
 
3058
    if (bb->isExceptionHandler())
3020
3059
        return;
3021
3060
 
3022
3061
    QVector<BasicBlock *> toPurge;
 
3062
    toPurge.reserve(8);
3023
3063
    toPurge.append(bb);
3024
3064
 
3025
3065
    while (!toPurge.isEmpty()) {
3026
3066
        bb = toPurge.first();
3027
3067
        toPurge.removeFirst();
3028
3068
 
3029
 
        int bbIdx = func->basicBlocks.indexOf(bb);
3030
 
        if (bbIdx == -1)
 
3069
        if (bb->isRemoved())
3031
3070
            continue;
3032
 
        else
3033
 
            func->basicBlocks.remove(bbIdx);
3034
3071
 
3035
3072
        // unlink all incoming edges
3036
3073
        foreach (BasicBlock *in, bb->in) {
3044
3081
            int idx = out->in.indexOf(bb);
3045
3082
            if (idx != -1) {
3046
3083
                out->in.remove(idx);
3047
 
                foreach (Stmt *outStmt, out->statements) {
 
3084
                foreach (Stmt *outStmt, out->statements()) {
3048
3085
                    if (!outStmt)
3049
3086
                        continue;
3050
3087
                    if (Phi *phi = outStmt->asPhi()) {
3069
3106
        }
3070
3107
 
3071
3108
        // unlink all defs/uses from the statements in the basic block
3072
 
        foreach (Stmt *s, bb->statements) {
 
3109
        foreach (Stmt *s, bb->statements()) {
3073
3110
            if (!s)
3074
3111
                continue;
3075
3112
 
3076
3113
            W += defUses.removeDefUses(s);
3077
3114
            W -= s;
3078
 
 
3079
 
            // clean-up the statement's data
3080
 
            s->destroyData();
3081
3115
        }
3082
 
        bb->statements.clear();
3083
3116
 
3084
 
        delete bb;
 
3117
        func->removeBasicBlock(bb);
3085
3118
    }
3086
3119
}
3087
3120
 
3162
3195
        if (Phi *phi = s->asPhi()) {
3163
3196
            // constant propagation:
3164
3197
            if (Const *c = isConstPhi(phi)) {
3165
 
                W += replaceUses(phi->targetTemp, c);
 
3198
                replaceUses(phi->targetTemp, c, W);
3166
3199
                defUses.removeDef(*phi->targetTemp);
3167
3200
                W.clear(s);
3168
3201
                continue;
3173
3206
                Temp *t = phi->targetTemp;
3174
3207
                Expr *e = phi->d->incoming.first();
3175
3208
 
3176
 
                QVector<Stmt *> newT2Uses = replaceUses(t, e);
3177
 
                W += newT2Uses;
 
3209
                QList<Stmt *> newT2Uses;
 
3210
                replaceUses(t, e, W, &newT2Uses);
3178
3211
                if (Temp *t2 = e->asTemp()) {
3179
3212
                    defUses.removeUse(s, *t2);
3180
 
                    defUses.addUses(*t2, QList<Stmt*>::fromVector(newT2Uses));
 
3213
                    defUses.addUses(*t2, newT2Uses);
3181
3214
                }
3182
3215
                defUses.removeDef(*t);
3183
3216
                W.clear(s);
3222
3255
 
3223
3256
                // constant propagation:
3224
3257
                if (Const *sourceConst = m->source->asConst()) {
3225
 
                    W += replaceUses(targetTemp, sourceConst);
 
3258
                    replaceUses(targetTemp, sourceConst, W);
3226
3259
                    defUses.removeDef(*targetTemp);
3227
3260
                    W.clear(s);
3228
3261
                    continue;
3232
3265
                        Const *c = function->New<Const>();
3233
3266
                        const int enumValue = member->attachedPropertiesIdOrEnumValue;
3234
3267
                        c->init(SInt32Type, enumValue);
3235
 
                        W += replaceUses(targetTemp, c);
 
3268
                        replaceUses(targetTemp, c, W);
3236
3269
                        defUses.removeDef(*targetTemp);
3237
3270
                        W.clear(s);
3238
3271
                        defUses.removeUse(s, *member->base->asTemp());
3250
3283
 
3251
3284
                // copy propagation:
3252
3285
                if (Temp *sourceTemp = unescapableTemp(m->source, function)) {
3253
 
                    QVector<Stmt *> newT2Uses = replaceUses(targetTemp, sourceTemp);
3254
 
                    W += newT2Uses;
 
3286
                    QList<Stmt *> newT2Uses;
 
3287
                    replaceUses(targetTemp, sourceTemp, W, &newT2Uses);
3255
3288
                    defUses.removeUse(s, *sourceTemp);
3256
 
                    defUses.addUses(*sourceTemp, QList<Stmt*>::fromVector(newT2Uses));
 
3289
                    defUses.addUses(*sourceTemp, newT2Uses);
3257
3290
                    defUses.removeDef(*targetTemp);
3258
3291
                    W.clear(s);
3259
3292
                    continue;
3518
3551
class LifeRanges {
3519
3552
    typedef QSet<Temp> LiveRegs;
3520
3553
 
3521
 
    QHash<BasicBlock *, LiveRegs> _liveIn;
 
3554
    QVector<LiveRegs> _liveIn;
3522
3555
    QHash<Temp, LifeTimeInterval> _intervals;
3523
 
    QVector<LifeTimeInterval> _sortedRanges;
 
3556
    typedef QVector<LifeTimeInterval> LifeTimeIntervals;
 
3557
    LifeTimeIntervals _sortedIntervals;
3524
3558
 
3525
3559
public:
3526
3560
    LifeRanges(IR::Function *function, const QHash<BasicBlock *, BasicBlock *> &startEndLoops)
3527
3561
    {
 
3562
        _liveIn.resize(function->basicBlockCount());
 
3563
 
3528
3564
        int id = 0;
3529
 
        foreach (BasicBlock *bb, function->basicBlocks) {
3530
 
            foreach (Stmt *s, bb->statements) {
 
3565
        foreach (BasicBlock *bb, function->basicBlocks()) {
 
3566
            foreach (Stmt *s, bb->statements()) {
3531
3567
                if (s->asPhi())
3532
3568
                    s->id = id + 1;
3533
3569
                else
3535
3571
            }
3536
3572
        }
3537
3573
 
3538
 
        for (int i = function->basicBlocks.size() - 1; i >= 0; --i) {
3539
 
            BasicBlock *bb = function->basicBlocks[i];
 
3574
        for (int i = function->basicBlockCount() - 1; i >= 0; --i) {
 
3575
            BasicBlock *bb = function->basicBlock(i);
3540
3576
            buildIntervals(bb, startEndLoops.value(bb, 0), function);
3541
3577
        }
3542
3578
 
3543
 
        _sortedRanges.reserve(_intervals.size());
 
3579
        _sortedIntervals.reserve(_intervals.size());
3544
3580
        for (QHash<Temp, LifeTimeInterval>::const_iterator i = _intervals.begin(), ei = _intervals.end(); i != ei; ++i) {
3545
 
            LifeTimeInterval range = i.value();
3546
 
            range.setTemp(i.key());
3547
 
            _sortedRanges.append(range);
 
3581
            LifeTimeIntervals::iterator lti = _sortedIntervals.insert(_sortedIntervals.end(), i.value());
 
3582
            lti->setTemp(i.key());
3548
3583
        }
3549
 
        std::sort(_sortedRanges.begin(), _sortedRanges.end(), LifeTimeInterval::lessThan);
 
3584
        std::sort(_sortedIntervals.begin(), _sortedIntervals.end(), LifeTimeInterval::lessThan);
 
3585
        _intervals.clear();
3550
3586
    }
3551
3587
 
3552
 
    QVector<LifeTimeInterval> ranges() const { return _sortedRanges; }
 
3588
    QVector<LifeTimeInterval> intervals() const { return _sortedIntervals; }
3553
3589
 
3554
3590
    void dump() const
3555
3591
    {
3556
3592
        qout << "Life ranges:" << endl;
3557
3593
        qout << "Intervals:" << endl;
3558
 
        foreach (const LifeTimeInterval &range, _sortedRanges) {
 
3594
        foreach (const LifeTimeInterval &range, _sortedIntervals) {
3559
3595
            range.dump(qout);
3560
3596
            qout << endl;
3561
3597
        }
3562
3598
 
3563
 
        foreach (BasicBlock *bb, _liveIn.keys()) {
3564
 
            qout << "L" << bb->index <<" live-in: ";
3565
 
            QList<Temp> live = QList<Temp>::fromSet(_liveIn.value(bb));
 
3599
        for (int i = 0, ei = _liveIn.size(); i != ei; ++i) {
 
3600
            qout << "L" << i <<" live-in: ";
 
3601
            QList<Temp> live = QList<Temp>::fromSet(_liveIn.at(i));
3566
3602
            std::sort(live.begin(), live.end());
3567
3603
            for (int i = 0; i < live.size(); ++i) {
3568
3604
                if (i > 0) qout << ", ";
3577
3613
    {
3578
3614
        LiveRegs live;
3579
3615
        foreach (BasicBlock *successor, bb->out) {
3580
 
            live.unite(_liveIn[successor]);
 
3616
            live.unite(_liveIn[successor->index()]);
3581
3617
            const int bbIndex = successor->in.indexOf(bb);
3582
3618
            Q_ASSERT(bbIndex >= 0);
3583
3619
 
3584
 
            foreach (Stmt *s, successor->statements) {
 
3620
            foreach (Stmt *s, successor->statements()) {
3585
3621
                if (Phi *phi = s->asPhi()) {
3586
3622
                    if (Temp *t = phi->d->incoming[bbIndex]->asTemp())
3587
3623
                        live.insert(*t);
3591
3627
            }
3592
3628
        }
3593
3629
 
 
3630
        QVector<Stmt *> statements = bb->statements();
 
3631
 
3594
3632
        foreach (const Temp &opd, live)
3595
 
            _intervals[opd].addRange(bb->statements.first()->id, bb->statements.last()->id);
 
3633
            _intervals[opd].addRange(statements.first()->id, statements.last()->id);
3596
3634
 
3597
3635
        InputOutputCollector collector(function);
3598
 
        for (int i = bb->statements.size() - 1; i >= 0; --i) {
3599
 
            Stmt *s = bb->statements[i];
 
3636
        for (int i = statements.size() - 1; i >= 0; --i) {
 
3637
            Stmt *s = statements[i];
3600
3638
            if (Phi *phi = s->asPhi()) {
3601
3639
                LiveRegs::iterator it = live.find(*phi->targetTemp);
3602
3640
                if (it == live.end()) {
3613
3651
                live.remove(opd);
3614
3652
            }
3615
3653
            foreach (const Temp &opd, collector.inputs) {
3616
 
                _intervals[opd].addRange(bb->statements.first()->id, s->id);
 
3654
                _intervals[opd].addRange(statements.first()->id, s->id);
3617
3655
                live.insert(opd);
3618
3656
            }
3619
3657
        }
3620
3658
 
3621
3659
        if (loopEnd) { // Meaning: bb is a loop header, because loopEnd is set to non-null.
3622
3660
            foreach (const Temp &opd, live)
3623
 
                _intervals[opd].addRange(bb->statements.first()->id, loopEnd->statements.last()->id);
 
3661
                _intervals[opd].addRange(statements.first()->id, loopEnd->terminator()->id);
3624
3662
        }
3625
3663
 
3626
 
        _liveIn[bb] = live;
 
3664
        _liveIn[bb->index()] = live;
3627
3665
    }
3628
3666
};
 
3667
 
 
3668
void removeUnreachleBlocks(IR::Function *function)
 
3669
{
 
3670
    QVector<BasicBlock *> newSchedule;
 
3671
    newSchedule.reserve(function->basicBlockCount());
 
3672
    foreach (BasicBlock *bb, function->basicBlocks())
 
3673
        if (!bb->isRemoved())
 
3674
            newSchedule.append(bb);
 
3675
    function->setScheduledBlocks(newSchedule);
 
3676
    function->renumberBasicBlocks();
 
3677
}
3629
3678
} // anonymous namespace
3630
3679
 
3631
3680
void LifeTimeInterval::setFrom(Stmt *from) {
3688
3737
 
3689
3738
    // search where to split the interval
3690
3739
    for (int i = 0, ei = _ranges.size(); i < ei; ++i) {
3691
 
        if (_ranges[i].start <= atPosition) {
3692
 
            if (_ranges[i].end >= atPosition) {
 
3740
        if (_ranges.at(i).start <= atPosition) {
 
3741
            if (_ranges.at(i).end >= atPosition) {
3693
3742
                // split happens in the middle of a range. Keep this range in both the old and the
3694
3743
                // new interval, and correct the end/start later
3695
3744
                _ranges.resize(i + 1);
3771
3820
    return r1.temp() < r2.temp();
3772
3821
}
3773
3822
 
 
3823
Optimizer::Optimizer(IR::Function *function)
 
3824
    : function(function)
 
3825
    , inSSA(false)
 
3826
{}
 
3827
 
3774
3828
void Optimizer::run(QQmlEnginePrivate *qmlEngine)
3775
3829
{
3776
3830
#if defined(SHOW_SSA)
3778
3832
         << " with " << function->basicBlocks.size() << " basic blocks." << endl << flush;
3779
3833
#endif
3780
3834
 
3781
 
    // Number all basic blocks, so we have nice numbers in the dumps:
3782
 
    for (int i = 0; i < function->basicBlocks.size(); ++i)
3783
 
        function->basicBlocks[i]->index = i;
3784
3835
//    showMeTheCode(function);
3785
3836
 
3786
 
    cleanupBasicBlocks(function, true);
 
3837
    cleanupBasicBlocks(function);
3787
3838
 
3788
3839
    function->removeSharedExpressions();
3789
3840
 
3795
3846
//        qout << "SSA for " << (function->name ? qPrintable(*function->name) : "<anonymous>") << endl;
3796
3847
 
3797
3848
        // Calculate the dominator tree:
3798
 
        DominatorTree df(function->basicBlocks);
 
3849
        DominatorTree df(function);
3799
3850
 
3800
3851
//        qout << "Converting to SSA..." << endl;
3801
3852
        convertToSSA(function, df);
3840
3891
        // condition is calculated to be always false) are not yet removed. This will choke the
3841
3892
        // block scheduling, so remove those now.
3842
3893
//        qout << "Cleaning up unreachable basic blocks..." << endl;
3843
 
        cleanupBasicBlocks(function, false);
 
3894
        cleanupBasicBlocks(function);
3844
3895
//        showMeTheCode(function);
3845
3896
 
3846
3897
//        qout << "Doing block scheduling..." << endl;
3847
3898
//        df.dumpImmediateDominators();
3848
3899
        startEndLoops = BlockScheduler(function, df).go();
3849
 
//        showMeTheCode(function);
 
3900
        showMeTheCode(function);
3850
3901
 
3851
3902
#ifndef QT_NO_DEBUG
3852
 
        checkCriticalEdges(function->basicBlocks);
 
3903
        checkCriticalEdges(function->basicBlocks());
3853
3904
#endif
3854
3905
 
3855
3906
//        qout << "Finished SSA." << endl;
3856
3907
        inSSA = true;
3857
3908
    } else {
 
3909
        removeUnreachleBlocks(function);
3858
3910
        inSSA = false;
3859
3911
    }
3860
3912
}
3865
3917
 
3866
3918
    // There should be no critical edges at this point.
3867
3919
 
3868
 
    foreach (BasicBlock *bb, function->basicBlocks) {
 
3920
    foreach (BasicBlock *bb, function->basicBlocks()) {
3869
3921
        MoveMapping moves;
3870
3922
 
3871
3923
        foreach (BasicBlock *successor, bb->out) {
3872
3924
            const int inIdx = successor->in.indexOf(bb);
3873
3925
            Q_ASSERT(inIdx >= 0);
3874
 
            foreach (Stmt *s, successor->statements) {
 
3926
            foreach (Stmt *s, successor->statements()) {
3875
3927
                if (Phi *phi = s->asPhi()) {
3876
3928
                    moves.add(clone(phi->d->incoming[inIdx], function),
3877
3929
                              clone(phi->targetTemp, function)->asTemp());
3897
3949
        moves.insertMoves(bb, function, true);
3898
3950
    }
3899
3951
 
3900
 
    foreach (BasicBlock *bb, function->basicBlocks) {
3901
 
        while (!bb->statements.isEmpty()) {
3902
 
            if (Phi *phi = bb->statements.first()->asPhi()) {
3903
 
                phi->destroyData();
3904
 
                bb->statements.removeFirst();
 
3952
    foreach (BasicBlock *bb, function->basicBlocks()) {
 
3953
        while (!bb->isEmpty()) {
 
3954
            if (bb->statements().first()->asPhi()) {
 
3955
                bb->removeStatement(0);
3905
3956
            } else {
3906
3957
                break;
3907
3958
            }
3909
3960
    }
3910
3961
}
3911
3962
 
3912
 
QVector<LifeTimeInterval> Optimizer::lifeRanges() const
 
3963
QVector<LifeTimeInterval> Optimizer::lifeTimeIntervals() const
3913
3964
{
3914
3965
    Q_ASSERT(isInSSA());
3915
3966
 
3916
3967
    LifeRanges lifeRanges(function, startEndLoops);
3917
3968
//    lifeRanges.dump();
3918
3969
//    showMeTheCode(function);
3919
 
    return lifeRanges.ranges();
 
3970
    return lifeRanges.intervals();
3920
3971
}
3921
3972
 
3922
3973
QSet<Jump *> Optimizer::calculateOptionalJumps()
3924
3975
    QSet<Jump *> optional;
3925
3976
    QSet<BasicBlock *> reachableWithoutJump;
3926
3977
 
3927
 
    const int maxSize = function->basicBlocks.size();
 
3978
    const int maxSize = function->basicBlockCount();
3928
3979
    optional.reserve(maxSize);
3929
3980
    reachableWithoutJump.reserve(maxSize);
3930
3981
 
3931
 
    for (int i = function->basicBlocks.size() - 1; i >= 0; --i) {
3932
 
        BasicBlock *bb = function->basicBlocks[i];
 
3982
    for (int i = maxSize - 1; i >= 0; --i) {
 
3983
        BasicBlock *bb = function->basicBlock(i);
 
3984
        if (bb->isRemoved())
 
3985
            continue;
3933
3986
 
3934
 
        if (Jump *jump = bb->statements.last()->asJump()) {
 
3987
        if (Jump *jump = bb->statements().last()->asJump()) {
3935
3988
            if (reachableWithoutJump.contains(jump->target)) {
3936
 
                if (bb->statements.size() > 1)
 
3989
                if (bb->statements().size() > 1)
3937
3990
                    reachableWithoutJump.clear();
3938
3991
                optional.insert(jump);
3939
3992
                reachableWithoutJump.insert(bb);
4048
4101
    QList<IR::Move *> newMoves;
4049
4102
    newMoves.reserve(_moves.size());
4050
4103
 
4051
 
    int insertionPoint = atEnd ? bb->statements.size() - 1 : 0;
 
4104
    int insertionPoint = atEnd ? bb->statements().size() - 1 : 0;
4052
4105
    foreach (const Move &m, _moves) {
4053
4106
        IR::Move *move = function->New<IR::Move>();
4054
4107
        move->init(clone(m.to, function), clone(m.from, function));
4055
4108
        move->swap = m.needsSwap;
4056
 
        bb->statements.insert(insertionPoint++, move);
 
4109
        bb->insertStatementBefore(insertionPoint++, move);
4057
4110
        newMoves.append(move);
4058
4111
    }
4059
4112