aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jit/qv4domtree.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jit/qv4domtree.cpp')
-rw-r--r--src/qml/jit/qv4domtree.cpp436
1 files changed, 0 insertions, 436 deletions
diff --git a/src/qml/jit/qv4domtree.cpp b/src/qml/jit/qv4domtree.cpp
deleted file mode 100644
index 9484f4e2dc..0000000000
--- a/src/qml/jit/qv4domtree.cpp
+++ /dev/null
@@ -1,436 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-#include <QtCore/qbuffer.h>
-
-#include "qv4domtree_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcDomTree, "qt.v4.ir.domTree")
-Q_LOGGING_CATEGORY(lcDomFrontier, "qt.v4.ir.domFrontier")
-
-DominatorTree::DominatorTree(MIFunction *f)
- : m_function(f)
- , m_data(new Data)
-{
- calculateIDoms();
- m_data.reset();
-}
-
-void DominatorTree::dumpImmediateDominators() const
-{
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream qout(&buf);
- qout << "Immediate dominators for " << m_function->irFunction()->name() << ":" << endl;
- for (MIBlock *to : m_function->blocks()) {
- MIBlock::Index from = m_idom.at(to->index());
- if (from != MIBlock::InvalidIndex)
- qout << " " << from;
- else
- qout << " (none)";
- qout << " dominates " << to->index() << endl;
- }
- qCDebug(lcDomTree, "%s", buf.data().constData());
-}
-
-void DominatorTree::setImmediateDominator(MIBlock::Index dominated, MIBlock::Index dominator)
-{
- if (m_idom.size() <= size_t(dominated))
- m_idom.resize(dominated + 1);
- m_idom[dominated] = dominator;
-}
-
-bool DominatorTree::dominates(MIBlock::Index dominator, MIBlock::Index dominated) const
-{
- // dominator can be Invalid when the dominated block has no dominator (i.e. the start node)
- Q_ASSERT(dominated != MIBlock::InvalidIndex);
-
- if (dominator == dominated)
- return false;
-
- for (MIBlock::Index it = m_idom[dominated]; it != MIBlock::InvalidIndex; it = m_idom[it]) {
- if (it == dominator)
- return true;
- }
-
- return false;
-}
-
-// Calculate a depth-first iteration order on the nodes of the dominator tree.
-//
-// The order of the nodes in the vector is not the same as one where a recursive depth-first
-// iteration is done on a tree. Rather, the nodes are (reverse) sorted on tree depth.
-// So for the:
-// 1 dominates 2
-// 2 dominates 3
-// 3 dominates 4
-// 2 dominates 5
-// the order will be:
-// 4, 3, 5, 2, 1
-// or:
-// 4, 5, 3, 2, 1
-// So the order of nodes on the same depth is undefined, but it will be after the nodes
-// they dominate, and before the nodes that dominate them.
-//
-// The reason for this order is that a proper DFS pre-/post-order would require inverting
-// the idom vector by either building a real tree datastructure or by searching the idoms
-// for siblings and children. Both have a higher time complexity than sorting by depth.
-std::vector<MIBlock *> DominatorTree::calculateDFNodeIterOrder() const
-{
- std::vector<int> depths = calculateNodeDepths();
- std::vector<MIBlock *> order = m_function->blocks();
- std::sort(order.begin(), order.end(), [&depths](MIBlock *one, MIBlock *two) -> bool {
- return depths.at(one->index()) > depths.at(two->index());
- });
- return order;
-}
-
-// Algorithm:
-// - for each node:
-// - get the depth of a node. If it's unknown (-1):
-// - get the depth of the immediate dominator.
-// - if that's unknown too, calculate it by calling calculateNodeDepth
-// - set the current node's depth to that of immediate dominator + 1
-std::vector<int> DominatorTree::calculateNodeDepths() const
-{
- std::vector<int> nodeDepths(size_t(m_function->blockCount()), -1);
- for (MIBlock *bb : m_function->blocks()) {
- int &bbDepth = nodeDepths[bb->index()];
- if (bbDepth == -1) {
- const int immDom = m_idom[bb->index()];
- if (immDom == -1) {
- // no immediate dominator, so it's either the start block, or an unreachable block
- bbDepth = 0;
- } else {
- int immDomDepth = nodeDepths[immDom];
- if (immDomDepth == -1)
- immDomDepth = calculateNodeDepth(immDom, nodeDepths);
- bbDepth = immDomDepth + 1;
- }
- }
- }
- return nodeDepths;
-}
-
-// Algorithm:
-// - search for the first dominator of a node that has a known depth. As all nodes are
-// reachable from the start node, and that node's depth is 0, this is finite.
-// - while doing that search, put all unknown nodes in the worklist
-// - pop all nodes from the worklist, and set their depth to the previous' (== dominating)
-// node's depth + 1
-// This way every node's depth is calculated once, and the complexity is O(n).
-int DominatorTree::calculateNodeDepth(MIBlock::Index nodeIdx, std::vector<int> &nodeDepths) const
-{
- std::vector<int> worklist;
- worklist.reserve(8);
- int depth = -1;
-
- do {
- worklist.push_back(nodeIdx);
- nodeIdx = m_idom[nodeIdx];
- depth = nodeDepths[nodeIdx];
- } while (depth == -1);
-
- for (auto it = worklist.rbegin(), eit = worklist.rend(); it != eit; ++it)
- nodeDepths[*it] = ++depth;
-
- return depth;
-}
-
-namespace {
-struct DFSTodo {
- MIBlock::Index node = MIBlock::InvalidIndex;
- MIBlock::Index parent = MIBlock::InvalidIndex;
-
- DFSTodo() = default;
- DFSTodo(MIBlock::Index node, MIBlock::Index parent)
- : node(node)
- , parent(parent)
- {}
-};
-} // anonymous namespace
-
-void DominatorTree::dfs(MIBlock::Index node)
-{
- std::vector<DFSTodo> worklist;
- worklist.reserve(m_data->vertex.capacity() / 2);
- DFSTodo todo(node, MIBlock::InvalidIndex);
-
- while (true) {
- MIBlock::Index n = todo.node;
-
- if (m_data->dfnum[n] == 0) {
- m_data->dfnum[n] = m_data->size;
- m_data->vertex[m_data->size] = n;
- m_data->parent[n] = todo.parent;
- ++m_data->size;
-
- MIBlock::OutEdges out = m_function->block(n)->outEdges();
- for (int i = out.size() - 1; i > 0; --i)
- worklist.emplace_back(out[i]->index(), n);
-
- if (!out.isEmpty()) {
- todo.node = out.first()->index();
- todo.parent = n;
- continue;
- }
- }
-
- if (worklist.empty())
- break;
-
- todo = worklist.back();
- worklist.pop_back();
- }
-}
-
-void DominatorTree::link(MIBlock::Index p, MIBlock::Index n)
-{
- m_data->ancestor[n] = p;
- m_data->best[n] = n;
-}
-
-void DominatorTree::calculateIDoms()
-{
- Q_ASSERT(m_function->block(0)->inEdges().count() == 0);
-
- const size_t bbCount = m_function->blockCount();
- m_data->vertex = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->parent = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->dfnum = std::vector<unsigned>(bbCount, 0);
- m_data->semi = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->ancestor = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_idom = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->samedom = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->best = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
-
- QHash<MIBlock::Index, std::vector<MIBlock::Index>> bucket;
- bucket.reserve(int(bbCount));
-
- dfs(m_function->block(0)->index());
-
- std::vector<MIBlock::Index> worklist;
- worklist.reserve(m_data->vertex.capacity() / 2);
-
- for (int i = m_data->size - 1; i > 0; --i) {
- MIBlock::Index n = m_data->vertex[i];
- MIBlock::Index p = m_data->parent[n];
- MIBlock::Index s = p;
-
- for (auto inEdge : m_function->block(n)->inEdges()) {
- if (inEdge->isDeoptBlock())
- continue;
- MIBlock::Index v = inEdge->index();
- MIBlock::Index ss = MIBlock::InvalidIndex;
- if (m_data->dfnum[v] <= m_data->dfnum[n])
- ss = v;
- else
- ss = m_data->semi[ancestorWithLowestSemi(v, worklist)];
- if (m_data->dfnum[ss] < m_data->dfnum[s])
- s = ss;
- }
- m_data->semi[n] = s;
- bucket[s].push_back(n);
- link(p, n);
- if (bucket.contains(p)) {
- for (MIBlock::Index v : bucket[p]) {
- MIBlock::Index y = ancestorWithLowestSemi(v, worklist);
- MIBlock::Index semi_v = m_data->semi[v];
- if (m_data->semi[y] == semi_v)
- m_idom[v] = semi_v;
- else
- m_data->samedom[v] = y;
- }
- bucket.remove(p);
- }
- }
-
- for (unsigned i = 1; i < m_data->size; ++i) {
- MIBlock::Index n = m_data->vertex[i];
- Q_ASSERT(n != MIBlock::InvalidIndex);
- Q_ASSERT(!bucket.contains(n));
- Q_ASSERT(m_data->ancestor[n] != MIBlock::InvalidIndex);
- Q_ASSERT((m_data->semi[n] != MIBlock::InvalidIndex
- && m_data->dfnum[m_data->ancestor[n]] <= m_data->dfnum[m_data->semi[n]])
- || m_data->semi[n] == n);
- MIBlock::Index sdn = m_data->samedom[n];
- if (sdn != MIBlock::InvalidIndex)
- m_idom[n] = m_idom[sdn];
- }
-
- if (lcDomTree().isDebugEnabled())
- dumpImmediateDominators();
-
- m_data.reset(nullptr);
-}
-
-MIBlock::Index DominatorTree::ancestorWithLowestSemi(MIBlock::Index v,
- std::vector<MIBlock::Index> &worklist)
-{
- worklist.clear();
- for (MIBlock::Index it = v; it != MIBlock::InvalidIndex; it = m_data->ancestor[it])
- worklist.push_back(it);
-
- if (worklist.size() < 2)
- return m_data->best[v];
-
- MIBlock::Index b = MIBlock::InvalidIndex;
- MIBlock::Index last = worklist.back();
- Q_ASSERT(worklist.size() <= INT_MAX);
- for (int it = static_cast<int>(worklist.size()) - 2; it >= 0; --it) {
- MIBlock::Index bbIt = worklist[it];
- m_data->ancestor[bbIt] = last;
- MIBlock::Index &best_it = m_data->best[bbIt];
- if (b != MIBlock::InvalidIndex
- && m_data->dfnum[m_data->semi[b]] < m_data->dfnum[m_data->semi[best_it]]) {
- best_it = b;
- } else {
- b = best_it;
- }
- }
- return b;
-}
-
-void DominatorFrontier::compute(const DominatorTree &domTree)
-{
- struct NodeProgress {
- std::vector<MIBlock::Index> children;
- std::vector<MIBlock::Index> todo;
- };
-
- MIFunction *function = domTree.function();
- m_df.resize(function->blockCount());
-
- // compute children of each node in the dominator tree
- std::vector<std::vector<MIBlock::Index> > children; // BasicBlock index -> children
- children.resize(function->blockCount());
- for (MIBlock *n : function->blocks()) {
- const MIBlock::Index nodeIndex = n->index();
- Q_ASSERT(function->block(nodeIndex) == n);
- const MIBlock::Index nodeDominator = domTree.immediateDominator(nodeIndex);
- if (nodeDominator == MIBlock::InvalidIndex)
- continue; // there is no dominator to add this node to as a child (e.g. the start node)
- children[nodeDominator].push_back(nodeIndex);
- }
-
- // Fill the worklist and initialize the node status for each basic-block
- std::vector<NodeProgress> nodeStatus;
- nodeStatus.resize(function->blockCount());
- std::vector<MIBlock::Index> worklist;
- worklist.reserve(function->blockCount());
- for (MIBlock *bb : function->blocks()) {
- MIBlock::Index nodeIndex = bb->index();
- worklist.push_back(nodeIndex);
- NodeProgress &np = nodeStatus[nodeIndex];
- np.children = children[nodeIndex];
- np.todo = children[nodeIndex];
- }
-
- BitVector DF_done(int(function->blockCount()), false);
-
- while (!worklist.empty()) {
- MIBlock::Index node = worklist.back();
-
- if (DF_done.at(node)) {
- worklist.pop_back();
- continue;
- }
-
- NodeProgress &np = nodeStatus[node];
- auto it = np.todo.begin();
- while (it != np.todo.end()) {
- if (DF_done.at(*it)) {
- it = np.todo.erase(it);
- } else {
- worklist.push_back(*it);
- break;
- }
- }
-
- if (np.todo.empty()) {
- MIBlockSet &miBlockSet = m_df[node];
- miBlockSet.init(function);
- for (MIBlock *y : function->block(node)->outEdges()) {
- if (domTree.immediateDominator(y->index()) != node)
- miBlockSet.insert(y);
- }
- for (MIBlock::Index child : np.children) {
- const MIBlockSet &ws = m_df[child];
- for (auto w : ws) {
- const MIBlock::Index wIndex = w->index();
- if (node == wIndex || !domTree.dominates(node, w->index()))
- miBlockSet.insert(w);
- }
- }
- DF_done.setBit(node);
- worklist.pop_back();
- }
- }
-
- if (lcDomFrontier().isDebugEnabled())
- dump(domTree.function());
-}
-
-void DominatorFrontier::dump(MIFunction *function)
-{
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream qout(&buf);
- qout << "Dominator Frontiers:" << endl;
- for (MIBlock *n : function->blocks()) {
- qout << "\tDF[" << n->index() << "]: {";
- const MIBlockSet &SList = m_df[n->index()];
- for (MIBlockSet::const_iterator i = SList.begin(), ei = SList.end(); i != ei; ++i) {
- if (i != SList.begin())
- qout << ", ";
- qout << (*i)->index();
- }
- qout << "}" << endl;
- }
- qCDebug(lcDomFrontier, "%s", buf.data().constData());
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE