From 83583f3448c767fd05a2a9361a079e63cc23448a Mon Sep 17 00:00:00 2001 From: r0qs Date: Wed, 7 Jun 2023 12:17:10 +0200 Subject: [PATCH 01/28] Implementation of Lengauer-Tarjan algorithm to find dominators --- libyul/CMakeLists.txt | 1 + libyul/backends/evm/Dominator.h | 271 +++++++++++++++++++ test/CMakeLists.txt | 1 + test/libyul/DominatorTest.cpp | 465 ++++++++++++++++++++++++++++++++ 4 files changed, 738 insertions(+) create mode 100644 libyul/backends/evm/Dominator.h create mode 100644 test/libyul/DominatorTest.cpp diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt index 811a6239b..25b6950c7 100644 --- a/libyul/CMakeLists.txt +++ b/libyul/CMakeLists.txt @@ -45,6 +45,7 @@ add_library(yul backends/evm/ControlFlowGraph.h backends/evm/ControlFlowGraphBuilder.cpp backends/evm/ControlFlowGraphBuilder.h + backends/evm/Dominator.h backends/evm/EthAssemblyAdapter.cpp backends/evm/EthAssemblyAdapter.h backends/evm/EVMCodeTransform.cpp diff --git a/libyul/backends/evm/Dominator.h b/libyul/backends/evm/Dominator.h new file mode 100644 index 000000000..ae5ba670c --- /dev/null +++ b/libyul/backends/evm/Dominator.h @@ -0,0 +1,271 @@ + +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** + * Dominator analysis of a control flow graph. + * The implementation is based on the following paper: + * https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf + * See appendix B pg. 139. + */ +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace solidity::yul +{ + +template +class Dominator +{ +public: + + Dominator(Vertex _entry, size_t _numVertices) + { + m_vertex = std::vector(_numVertices); + m_immediateDominator = lengauerTarjanDominator(_entry, _numVertices); + buildDominatorTree(); + } + + std::vector vertices() const + { + return m_vertex; + } + + std::map vertexIndices() const + { + return m_vertexIndex; + } + + std::vector immediateDominators() const + { + return m_immediateDominator; + } + + std::map> dominatorTree() const + { + return m_dominatorTree; + } + + // Checks whether ``_a`` dominates ``_b`` by going + // through the path from ``_b`` to the entry node. + // If ``_a`` is found, then it dominates ``_b`` + // otherwise it doesn't. + bool dominates(Vertex _a, Vertex _b) + { + size_t aIdx = m_vertexIndex[_a]; + size_t bIdx = m_vertexIndex[_b]; + + if (aIdx == bIdx) + return true; + + size_t idomIdx = m_immediateDominator[bIdx]; + while (idomIdx != 0) + { + if (idomIdx == aIdx) + return true; + idomIdx = m_immediateDominator[idomIdx]; + } + // Now that we reach the entry node (i.e. idx = 0), + // either ``aIdx == 0`` or it does not dominates other node. + return idomIdx == aIdx; + } + + // Find all dominators of a node _v + // @note for a vertex ``_v``, the _v’s inclusion in the set of dominators of ``_v`` is implicit. + std::vector dominatorsOf(Vertex _v) + { + assert(m_vertex.size() > 0); + // The entry node always dominates all other nodes + std::vector dominators = std::vector{m_vertex[0]}; + + size_t idomIdx = m_immediateDominator[m_vertexIndex[_v]]; + if (idomIdx == 0) + return std::move(dominators); + + while (idomIdx != 0) + { + dominators.emplace_back(m_vertex[idomIdx]); + idomIdx = m_immediateDominator[idomIdx]; + } + return std::move(dominators); + } + + void buildDominatorTree() { + assert(m_vertex.size() > 0); + assert(m_immediateDominator.size() > 0); + + //Ignoring the entry node since no one dominates it. + for (size_t i = 1; i < m_immediateDominator.size(); ++i) + m_dominatorTree[m_immediateDominator[i]].emplace_back(i); + } + + // Path compression updates the ancestors of vertices along + // the path to the ancestor with the minimum label value. + void compressPath( + std::vector &_ancestor, + std::vector &_label, + std::vector &_semi, + size_t _v + ) + { + assert(_ancestor[_v] != std::numeric_limits::max()); + size_t u = _ancestor[_v]; + if (_ancestor[u] != std::numeric_limits::max()) + { + compressPath(_ancestor, _label, _semi, u); + if (_semi[_label[u]] < _semi[_label[_v]]) + _label[_v] = _label[u]; + _ancestor[_v] = _ancestor[u]; + } + } + + std::vector lengauerTarjanDominator(Vertex _entry, size_t numVertices) + { + assert(numVertices > 0); + // semi(w): The dfs index of the semidominator of ``w``. + std::vector semi(numVertices, std::numeric_limits::max()); + // parent(w): The index of the vertex which is the parent of ``w`` in the spanning + // tree generated by the dfs. + std::vector parent(numVertices, std::numeric_limits::max()); + // ancestor(w): The highest ancestor of a vertex ``w`` in the dominator tree used + // for path compression. + std::vector ancestor(numVertices, std::numeric_limits::max()); + // label(w): The index of the vertex ``w`` with the minimum semidominator in the path + // to its parent. + std::vector label(numVertices, 0); + + // ``link`` adds an edge to the virtual forest. + // It copies the parent of w to the ancestor array to limit the search path upwards. + // TODO: implement sophisticated link-eval algorithm as shown in pg 132 + // See: https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf + auto link = [&](size_t _parent, size_t _w) + { + ancestor[_w] = _parent; + }; + + // ``eval`` computes the path compression. + // Finds ancestor with lowest semi-dominator dfs number (i.e. index). + auto eval = [&](size_t _v) -> size_t + { + if (ancestor[_v] != std::numeric_limits::max()) + { + compressPath(ancestor, label, semi, _v); + return label[_v]; + } + return _v; + }; + + // step 1 + std::set visited; + // predecessors(w): The set of vertices ``v`` such that (``v``, ``w``) is an edge of the graph. + std::vector> predecessors(numVertices); + // bucket(w): a set of vertices whose semidominator is ``w`` + // The index of the array represents the vertex's ``dfIdx`` + std::vector> bucket(numVertices); + // idom(w): the index of the immediate dominator of ``w`` + std::vector idom(numVertices, std::numeric_limits::max()); + // The number of vertices reached during the dfs. + // The vertices are indexed based on this number. + size_t dfIdx = 0; + auto dfs = [&](Vertex _v, auto _dfs) -> void { + if (visited.count(_v)) + return; + visited.insert(_v); + m_vertex[dfIdx] = _v; + m_vertexIndex[_v] = dfIdx; + semi[dfIdx] = dfIdx; + label[dfIdx] = dfIdx; + dfIdx++; + ForEachSuccessor{}(_v, [&](Vertex w) { + if (semi[dfIdx] == std::numeric_limits::max()) + { + parent[dfIdx] = m_vertexIndex[_v]; + _dfs(w, _dfs); + } + predecessors[m_vertexIndex[w]].insert(m_vertexIndex[_v]); + }); + }; + dfs(_entry, dfs); + + // Process the vertices in decreasing order of the dfs number + for (auto it = m_vertex.rbegin(); it != m_vertex.rend(); ++it) + { + auto w = m_vertexIndex[*it]; + // step 3 + // NOTE: this is an optimization, i.e. performing the step 3 before step 2. + // The goal is to process the bucket in the beginning of the loop for the vertex ``w`` + // instead of ``parent[w]`` in the end of the loop as described in the original paper. + // Inverting those steps ensures that a bucket is only processed once and + // it does not need to be erased. + // The optimization proposal is available here: https://jgaa.info/accepted/2006/GeorgiadisTarjanWerneck2006.10.1.pdf pg.77 + for_each( + bucket[w].begin(), + bucket[w].end(), + [&](size_t v) + { + size_t u = eval(v); + idom[v] = (semi[u] < semi[v]) ? u : w; + } + ); + + // step 2 + for (auto v: predecessors[w]) + { + size_t u = eval(v); + if (semi[u] < semi[w]) + semi[w] = semi[u]; + } + bucket[semi[w]].emplace_back(w); + link(parent[w], w); + } + + // step 4 + idom[0] = 0; + for (auto it = m_vertex.begin() + 1; it != m_vertex.end(); ++it) + { + size_t w = m_vertexIndex[*it]; + if (idom[w] != semi[w]) + idom[w] = idom[idom[w]]; + } + return idom; + } +private: + // Keep the list of vertices in the dfs order. + // i.e. m_vertex[i]: the vertex whose dfs index is i. + std::vector m_vertex; + // Maps Vertex to their dfs index. + std::map m_vertexIndex; + // Immediate dominators by index. + // Maps a Vertex based on its dfs index (i.e. array index) to its immediate dominator dfs index. + // + // e.g. to get the immediate dominator of a Vertex w: + // idomIdx = m_immediateDominator[m_vertexIndex[w]] + // idomVertex = m_vertex[domIdx] + std::vector m_immediateDominator; + + // Maps a Vertex to all vertices that it dominates. + // If the vertex does not dominates any other vertex it has no entry in the map. + std::map> m_dominatorTree; +}; +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f8242db7a..af358ac2a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -138,6 +138,7 @@ set(libyul_sources libyul/ControlFlowGraphTest.h libyul/ControlFlowSideEffectsTest.cpp libyul/ControlFlowSideEffectsTest.h + libyul/DominatorTest.cpp libyul/EVMCodeTransformTest.cpp libyul/EVMCodeTransformTest.h libyul/FunctionSideEffects.cpp diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp new file mode 100644 index 000000000..0fbf56722 --- /dev/null +++ b/test/libyul/DominatorTest.cpp @@ -0,0 +1,465 @@ +/* + This file is part of solidity. + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +/** + * Unit tests for the algorithm to find dominators from a graph. + */ +#include + +#include + +using namespace solidity::yul; + +namespace solidity::yul::test +{ + +struct ImmediateDominatorTest +{ + struct Vertex { + std::string data; + std::vector successors; + + bool operator<(Vertex const& _other) const + { + return data < _other.data; + } + }; + + typedef std::pair edge; + + struct ForEachVertexSuccessorTest { + template + void operator()(Vertex _v, Callable&& _callable) const + { + for (auto w: _v.successors) + _callable(*w); + } + }; + + size_t numVertices; + Vertex* entry; + std::map vertices; + std::vector expectedIdom; + std::map expectedDFSIndices; +}; + +class DominatorFixture +{ + typedef ImmediateDominatorTest::Vertex Vertex; +protected: + static ImmediateDominatorTest const* generateGraph( + std::vector _vertices, + std::vector _edges, + std::vector _expectedIdom, + std::map _expectedDFSIndices + ) + { + assert(_edges.size() > 0); + + ImmediateDominatorTest* graph = new ImmediateDominatorTest(); + for (std::string v: _vertices) + graph->vertices.insert(make_pair(v, new Vertex{v, std::vector{}})); + graph->entry = graph->vertices[_vertices[0]]; + + assert(_vertices.size() > 0 && _vertices.size() == graph->vertices.size()); + + graph->numVertices = _vertices.size(); + for (auto [from, to]: _edges) + graph->vertices[from]->successors.push_back(graph->vertices[to]); + + graph->expectedIdom = _expectedIdom; + graph->expectedDFSIndices = _expectedDFSIndices; + return graph; + } +}; + +BOOST_AUTO_TEST_SUITE(Dominators) + +BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) +{ + typedef ImmediateDominatorTest::edge edge; + std::vector inputGraph(9); + + // A + // │ + // ▼ + // ┌───B + // │ │ + // ▼ │ + // C ──┼───┐ + // │ │ │ + // ▼ │ ▼ + // D◄──┘ G + // │ │ + // ▼ ▼ + // E H + // │ │ + // └──►F◄──┘ + inputGraph[0] = generateGraph( + { "A", "B", "C", "D", "E", "F", "G", "H" }, + { + edge("A", "B"), + edge("B", "C"), + edge("B", "D"), + edge("C", "D"), + edge("C", "G"), + edge("D", "E"), + edge("E", "F"), + edge("G", "H"), + edge("H", "F") + }, + {0, 0, 1, 1, 3, 1, 2, 6}, + { + {"A", 0}, + {"B", 1}, + {"C", 2}, + {"D", 3}, + {"E", 4}, + {"F", 5}, + {"G", 6}, + {"H", 7} + } + ); + + // ┌────►A──────┐ + // │ │ ▼ + // │ B◄──┘ ┌──D──┐ + // │ │ │ │ + // │ ▼ ▼ ▼ + // └─C◄───┐ E F + // │ │ │ │ + // └───►G◄─┴─────┘ + inputGraph[1] = generateGraph( + { "A", "B", "C", "D", "E", "F", "G" }, + { + edge("A", "B"), + edge("B", "C"), + edge("C", "G"), + edge("C", "A"), + edge("A", "D"), + edge("D", "E"), + edge("D", "F"), + edge("E", "G"), + edge("F", "G"), + edge("G", "C") + }, + {0, 0, 0, 0, 0, 4, 4}, + { + {"A", 0}, + {"B", 1}, + {"C", 2}, + {"G", 3}, + {"D", 4}, + {"E", 5}, + {"F", 6} + } + ); + + // ┌─────────┐ + // │ ▼ + // │ ┌───A───┐ + // │ │ │ + // │ ▼ ▼ + // │ ┌──►C◄───── B──┬──────┐ + // │ │ │ ▲ │ │ + // │ │ │ ┌────┘ │ │ + // │ │ ▼ │ ▼ ▼ + // │ │ D──┘ ┌───►E◄─────I + // │ │ ▲ │ │ │ + // │ │ │ │ ├───┐ │ + // │ │ │ │ │ │ │ + // │ │ │ │ ▼ │ ▼ + // │ └───┼─────┼────F └─►H + // │ │ │ │ │ + // │ │ │ │ │ + // │ │ │ │ │ + // │ └─────┴─G◄─┴──────┘ + // │ │ + // └─────────────┘ + inputGraph[2] = generateGraph( + { "A", "B", "C", "D", "E", "F", "G", "H", "I" }, + { + edge("A", "B"), + edge("A", "C"), + edge("B", "C"), + edge("B", "I"), + edge("B", "E"), + edge("C", "D"), + edge("D", "B"), + edge("E", "H"), + edge("E", "F"), + edge("F", "G"), + edge("F", "C"), + edge("G", "E"), + edge("G", "A"), + edge("G", "D"), + edge("H", "G"), + edge("I", "E"), + edge("I", "H") + }, + {0, 0, 0, 0, 1, 1, 1, 1, 5}, + { + {"A", 0}, + {"B", 1}, + {"C", 2}, + {"D", 3}, + {"I", 4}, + {"E", 5}, + {"H", 6}, + {"G", 7}, + {"F", 8} + } + ); + + // T. Lengauer and R. E. Tarjan pg. 122 fig. 1 + // ref: https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf + inputGraph[3] = generateGraph( + { "R", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "L", "K" }, + { + edge("R", "B"), + edge("R", "A"), + edge("R", "C"), + edge("B", "A"), + edge("B", "D"), + edge("B", "E"), + edge("A", "D"), + edge("D", "L"), + edge("L", "H"), + edge("E", "H"), + edge("H", "E"), + edge("H", "K"), + edge("K", "I"), + edge("K", "R"), + edge("C", "F"), + edge("C", "G"), + edge("F", "I"), + edge("G", "I"), + edge("G", "J"), + edge("J", "I"), + edge("I", "K"), + }, + {0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 9, 9, 11}, + { + {"R", 0}, + {"B", 1}, + {"A", 2}, + {"D", 3}, + {"L", 4}, + {"H", 5}, + {"E", 6}, + {"K", 7}, + {"I", 8}, + {"C", 9}, + {"F", 10}, + {"G", 11}, + {"J", 12} + } + ); + + // Extracted from Loukas Georgiadis Dissertation - Linear-Time Algorithms for Dominators and Related Problems + // pg. 12 Fig. 2.2 + // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf + inputGraph[4] = generateGraph( + { "R", "W", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "Y" }, + { + edge("R", "W"), + edge("R", "Y"), + edge("W", "X1"), + edge("Y", "X7"), + edge("X1", "X2"), + edge("X2", "X1"), + edge("X2", "X3"), + edge("X3", "X2"), + edge("X3", "X4"), + edge("X4", "X3"), + edge("X4", "X5"), + edge("X5", "X4"), + edge("X5", "X6"), + edge("X6", "X5"), + edge("X6", "X7"), + edge("X7", "X6") + }, + {0, 0, 0, 0, 0, 0, 0, 0, 0 , 0}, + { + {"R", 0}, + {"W", 1}, + {"X1", 2}, + {"X2", 3}, + {"X3", 4}, + {"X4", 5}, + {"X5", 6}, + {"X6", 7}, + {"X7", 8}, + {"Y", 9} + } + ); + + // Worst-case families for k = 3 + // Example itworst(3) pg. 26 fig. 2.9 + // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf + inputGraph[5] = generateGraph( + { "R", "W1", "W2", "W3", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3" }, + { + edge("R", "W1"), + edge("R", "X1"), + edge("R", "Z3"), + edge("W1", "W2"), + edge("W2", "W3"), + edge("X1", "X2"), + edge("X2", "X3"), + edge("X3", "Y1"), + edge("Y1", "W1"), + edge("Y1", "W2"), + edge("Y1", "W3"), + edge("Y1", "Y2"), + edge("Y2", "W1"), + edge("Y2", "W2"), + edge("Y2", "W3"), + edge("Y2", "Y3"), + edge("Y3", "W1"), + edge("Y3", "W2"), + edge("Y3", "W3"), + edge("Y3", "Z1"), + edge("Z1", "Z2"), + edge("Z2", "Z1"), + edge("Z2", "Z3"), + edge("Z3", "Z2") + }, + {0, 0, 0, 0, 0, 4, 5, 6, 7, 8, 0, 0, 0}, + { + {"R", 0}, + {"W1", 1}, + {"W2", 2}, + {"W3", 3}, + {"X1", 4}, + {"X2", 5}, + {"X3", 6}, + {"Y1", 7}, + {"Y2", 8}, + {"Y3", 9}, + {"Z1", 10}, + {"Z2", 11}, + {"Z3", 12} + } + ); + + + // Worst-case families for k = 3 + // Example idfsquad(3) pg. 26 fig. 2.9 + // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf + inputGraph[6] = generateGraph( + { "R", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3" }, + { + edge("R", "X1"), + edge("R", "Z1"), + edge("X1", "Y1"), + edge("X1", "X2"), + edge("X2", "X3"), + edge("X2", "Y2"), + edge("X3", "Y3"), + edge("Y1", "Z1"), + edge("Y1", "Z2"), + edge("Z1", "Y1"), + edge("Y2", "Z2"), + edge("Y2", "Z3"), + edge("Z2", "Y2"), + edge("Y3", "Z3"), + edge("Z3", "Y3") + }, + {0, 0, 0, 0, 0, 0, 0, 0, 1, 8}, + { + {"R", 0}, + {"X1", 1}, + {"Y1", 2}, + {"Z1", 3}, + {"Z2", 4}, + {"Y2", 5}, + {"Z3", 6}, + {"Y3", 7}, + {"X2", 8}, + {"X3", 9} + } + ); + + // Worst-case families for k = 3 + // Example ibfsquad(3) pg. 26 fig. 2.9 + // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf + inputGraph[7] = generateGraph( + { "R", "W", "X1", "X2", "X3", "Y", "Z" }, + { + edge("R", "W"), + edge("R", "Y"), + edge("W", "X1"), + edge("W", "X2"), + edge("W", "X3"), + edge("Y", "Z"), + edge("Z", "X3"), + edge("X3", "X2"), + edge("X2", "X1") + }, + {0, 0, 0, 0, 0, 0, 5}, + { + {"R", 0}, + {"W", 1}, + {"X1", 2}, + {"X2", 3}, + {"X3", 4}, + {"Y", 5}, + {"Z", 6} + } + ); + + // Worst-case families for k = 3 + // Example sncaworst(3) pg. 26 fig. 2.9 + // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf + inputGraph[8] = generateGraph( + { "R", "X1", "X2", "X3", "Y1", "Y2", "Y3" }, + { + edge("R", "X1"), + edge("R", "Y1"), + edge("R", "Y2"), + edge("R", "Y3"), + edge("X1", "X2"), + edge("X2", "X3"), + edge("X3", "Y1"), + edge("X3", "Y2"), + edge("X3", "Y3") + }, + {0, 0, 1, 2, 0, 0, 0}, + { + {"R", 0}, + {"X1", 1}, + {"X2", 2}, + {"X3", 3}, + {"Y1", 4}, + {"Y2", 5}, + {"Y3", 6}, + } + ); + + for (ImmediateDominatorTest const* g: inputGraph) + { + Dominator< + ImmediateDominatorTest::Vertex, + ImmediateDominatorTest::ForEachVertexSuccessorTest + > dom(*g->entry, g->numVertices); + + for (auto [v, idx]: dom.vertexIndices()) + BOOST_CHECK(g->expectedDFSIndices.at(v.data) == idx); + BOOST_TEST(dom.immediateDominators() == g->expectedIdom); + } + +} + +BOOST_AUTO_TEST_SUITE_END() +} From 66b95967e600d3c1ba71e513f5c22db9ac488066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 17:12:30 +0200 Subject: [PATCH 02/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- libyul/backends/evm/Dominator.h | 10 +++++----- test/libyul/DominatorTest.cpp | 6 ++++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/libyul/backends/evm/Dominator.h b/libyul/backends/evm/Dominator.h index ae5ba670c..7de1f1410 100644 --- a/libyul/backends/evm/Dominator.h +++ b/libyul/backends/evm/Dominator.h @@ -95,7 +95,7 @@ public: // @note for a vertex ``_v``, the _v’s inclusion in the set of dominators of ``_v`` is implicit. std::vector dominatorsOf(Vertex _v) { - assert(m_vertex.size() > 0); + solAssert(m_vertex.size() > 0); // The entry node always dominates all other nodes std::vector dominators = std::vector{m_vertex[0]}; @@ -112,8 +112,8 @@ public: } void buildDominatorTree() { - assert(m_vertex.size() > 0); - assert(m_immediateDominator.size() > 0); + solAssert(m_vertex.size() > 0); + solAssert(m_immediateDominator.size() > 0); //Ignoring the entry node since no one dominates it. for (size_t i = 1; i < m_immediateDominator.size(); ++i) @@ -129,7 +129,7 @@ public: size_t _v ) { - assert(_ancestor[_v] != std::numeric_limits::max()); + solAssert(_ancestor[_v] != std::numeric_limits::max()); size_t u = _ancestor[_v]; if (_ancestor[u] != std::numeric_limits::max()) { @@ -142,7 +142,7 @@ public: std::vector lengauerTarjanDominator(Vertex _entry, size_t numVertices) { - assert(numVertices > 0); + solAssert(numVertices > 0); // semi(w): The dfs index of the semidominator of ``w``. std::vector semi(numVertices, std::numeric_limits::max()); // parent(w): The index of the vertex which is the parent of ``w`` in the spanning diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index 0fbf56722..1196e7605 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -16,6 +16,8 @@ */ #include +#include + #include using namespace solidity::yul; @@ -64,14 +66,14 @@ protected: std::map _expectedDFSIndices ) { - assert(_edges.size() > 0); + soltestAssert(_edges.size() > 0); ImmediateDominatorTest* graph = new ImmediateDominatorTest(); for (std::string v: _vertices) graph->vertices.insert(make_pair(v, new Vertex{v, std::vector{}})); graph->entry = graph->vertices[_vertices[0]]; - assert(_vertices.size() > 0 && _vertices.size() == graph->vertices.size()); + soltestAssert(_vertices.size() > 0 && _vertices.size() == graph->vertices.size()); graph->numVertices = _vertices.size(); for (auto [from, to]: _edges) From 7888ff424ef57766e33746294e38c2ec5e6f9da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 17:13:28 +0200 Subject: [PATCH 03/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- test/libyul/DominatorTest.cpp | 804 +++++++++++++++++----------------- 1 file changed, 402 insertions(+), 402 deletions(-) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index 1196e7605..8c7e20390 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -27,439 +27,439 @@ namespace solidity::yul::test struct ImmediateDominatorTest { - struct Vertex { - std::string data; - std::vector successors; + struct Vertex { + std::string data; + std::vector successors; - bool operator<(Vertex const& _other) const - { - return data < _other.data; - } - }; + bool operator<(Vertex const& _other) const + { + return data < _other.data; + } + }; - typedef std::pair edge; + typedef std::pair edge; - struct ForEachVertexSuccessorTest { - template - void operator()(Vertex _v, Callable&& _callable) const - { - for (auto w: _v.successors) - _callable(*w); - } - }; + struct ForEachVertexSuccessorTest { + template + void operator()(Vertex _v, Callable&& _callable) const + { + for (auto w: _v.successors) + _callable(*w); + } + }; - size_t numVertices; - Vertex* entry; - std::map vertices; - std::vector expectedIdom; - std::map expectedDFSIndices; + size_t numVertices; + Vertex* entry; + std::map vertices; + std::vector expectedIdom; + std::map expectedDFSIndices; }; class DominatorFixture { - typedef ImmediateDominatorTest::Vertex Vertex; + typedef ImmediateDominatorTest::Vertex Vertex; protected: - static ImmediateDominatorTest const* generateGraph( - std::vector _vertices, - std::vector _edges, - std::vector _expectedIdom, - std::map _expectedDFSIndices - ) - { - soltestAssert(_edges.size() > 0); + static ImmediateDominatorTest const* generateGraph( + std::vector _vertices, + std::vector _edges, + std::vector _expectedIdom, + std::map _expectedDFSIndices + ) + { + soltestAssert(_edges.size() > 0); - ImmediateDominatorTest* graph = new ImmediateDominatorTest(); - for (std::string v: _vertices) - graph->vertices.insert(make_pair(v, new Vertex{v, std::vector{}})); - graph->entry = graph->vertices[_vertices[0]]; + ImmediateDominatorTest* graph = new ImmediateDominatorTest(); + for (std::string v: _vertices) + graph->vertices.insert(make_pair(v, new Vertex{v, std::vector{}})); + graph->entry = graph->vertices[_vertices[0]]; - soltestAssert(_vertices.size() > 0 && _vertices.size() == graph->vertices.size()); + soltestAssert(_vertices.size() > 0 && _vertices.size() == graph->vertices.size()); - graph->numVertices = _vertices.size(); - for (auto [from, to]: _edges) - graph->vertices[from]->successors.push_back(graph->vertices[to]); + graph->numVertices = _vertices.size(); + for (auto [from, to]: _edges) + graph->vertices[from]->successors.push_back(graph->vertices[to]); - graph->expectedIdom = _expectedIdom; - graph->expectedDFSIndices = _expectedDFSIndices; - return graph; - } + graph->expectedIdom = _expectedIdom; + graph->expectedDFSIndices = _expectedDFSIndices; + return graph; + } }; BOOST_AUTO_TEST_SUITE(Dominators) BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) { - typedef ImmediateDominatorTest::edge edge; - std::vector inputGraph(9); + typedef ImmediateDominatorTest::edge edge; + std::vector inputGraph(9); - // A - // │ - // ▼ - // ┌───B - // │ │ - // ▼ │ - // C ──┼───┐ - // │ │ │ - // ▼ │ ▼ - // D◄──┘ G - // │ │ - // ▼ ▼ - // E H - // │ │ - // └──►F◄──┘ - inputGraph[0] = generateGraph( - { "A", "B", "C", "D", "E", "F", "G", "H" }, - { - edge("A", "B"), - edge("B", "C"), - edge("B", "D"), - edge("C", "D"), - edge("C", "G"), - edge("D", "E"), - edge("E", "F"), - edge("G", "H"), - edge("H", "F") - }, - {0, 0, 1, 1, 3, 1, 2, 6}, - { - {"A", 0}, - {"B", 1}, - {"C", 2}, - {"D", 3}, - {"E", 4}, - {"F", 5}, - {"G", 6}, - {"H", 7} - } - ); + // A + // │ + // ▼ + // ┌───B + // │ │ + // ▼ │ + // C ──┼───┐ + // │ │ │ + // ▼ │ ▼ + // D◄──┘ G + // │ │ + // ▼ ▼ + // E H + // │ │ + // └──►F◄──┘ + inputGraph[0] = generateGraph( + { "A", "B", "C", "D", "E", "F", "G", "H" }, + { + edge("A", "B"), + edge("B", "C"), + edge("B", "D"), + edge("C", "D"), + edge("C", "G"), + edge("D", "E"), + edge("E", "F"), + edge("G", "H"), + edge("H", "F") + }, + {0, 0, 1, 1, 3, 1, 2, 6}, + { + {"A", 0}, + {"B", 1}, + {"C", 2}, + {"D", 3}, + {"E", 4}, + {"F", 5}, + {"G", 6}, + {"H", 7} + } + ); - // ┌────►A──────┐ - // │ │ ▼ - // │ B◄──┘ ┌──D──┐ - // │ │ │ │ - // │ ▼ ▼ ▼ - // └─C◄───┐ E F - // │ │ │ │ - // └───►G◄─┴─────┘ - inputGraph[1] = generateGraph( - { "A", "B", "C", "D", "E", "F", "G" }, - { - edge("A", "B"), - edge("B", "C"), - edge("C", "G"), - edge("C", "A"), - edge("A", "D"), - edge("D", "E"), - edge("D", "F"), - edge("E", "G"), - edge("F", "G"), - edge("G", "C") - }, - {0, 0, 0, 0, 0, 4, 4}, - { - {"A", 0}, - {"B", 1}, - {"C", 2}, - {"G", 3}, - {"D", 4}, - {"E", 5}, - {"F", 6} - } - ); + // ┌────►A──────┐ + // │ │ ▼ + // │ B◄──┘ ┌──D──┐ + // │ │ │ │ + // │ ▼ ▼ ▼ + // └─C◄───┐ E F + // │ │ │ │ + // └───►G◄─┴─────┘ + inputGraph[1] = generateGraph( + { "A", "B", "C", "D", "E", "F", "G" }, + { + edge("A", "B"), + edge("B", "C"), + edge("C", "G"), + edge("C", "A"), + edge("A", "D"), + edge("D", "E"), + edge("D", "F"), + edge("E", "G"), + edge("F", "G"), + edge("G", "C") + }, + {0, 0, 0, 0, 0, 4, 4}, + { + {"A", 0}, + {"B", 1}, + {"C", 2}, + {"G", 3}, + {"D", 4}, + {"E", 5}, + {"F", 6} + } + ); - // ┌─────────┐ - // │ ▼ - // │ ┌───A───┐ - // │ │ │ - // │ ▼ ▼ - // │ ┌──►C◄───── B──┬──────┐ - // │ │ │ ▲ │ │ - // │ │ │ ┌────┘ │ │ - // │ │ ▼ │ ▼ ▼ - // │ │ D──┘ ┌───►E◄─────I - // │ │ ▲ │ │ │ - // │ │ │ │ ├───┐ │ - // │ │ │ │ │ │ │ - // │ │ │ │ ▼ │ ▼ - // │ └───┼─────┼────F └─►H - // │ │ │ │ │ - // │ │ │ │ │ - // │ │ │ │ │ - // │ └─────┴─G◄─┴──────┘ - // │ │ - // └─────────────┘ - inputGraph[2] = generateGraph( - { "A", "B", "C", "D", "E", "F", "G", "H", "I" }, - { - edge("A", "B"), - edge("A", "C"), - edge("B", "C"), - edge("B", "I"), - edge("B", "E"), - edge("C", "D"), - edge("D", "B"), - edge("E", "H"), - edge("E", "F"), - edge("F", "G"), - edge("F", "C"), - edge("G", "E"), - edge("G", "A"), - edge("G", "D"), - edge("H", "G"), - edge("I", "E"), - edge("I", "H") - }, - {0, 0, 0, 0, 1, 1, 1, 1, 5}, - { - {"A", 0}, - {"B", 1}, - {"C", 2}, - {"D", 3}, - {"I", 4}, - {"E", 5}, - {"H", 6}, - {"G", 7}, - {"F", 8} - } - ); + // ┌─────────┐ + // │ ▼ + // │ ┌───A───┐ + // │ │ │ + // │ ▼ ▼ + // │ ┌──►C◄───── B──┬──────┐ + // │ │ │ ▲ │ │ + // │ │ │ ┌────┘ │ │ + // │ │ ▼ │ ▼ ▼ + // │ │ D──┘ ┌───►E◄─────I + // │ │ ▲ │ │ │ + // │ │ │ │ ├───┐ │ + // │ │ │ │ │ │ │ + // │ │ │ │ ▼ │ ▼ + // │ └───┼─────┼────F └─►H + // │ │ │ │ │ + // │ │ │ │ │ + // │ │ │ │ │ + // │ └─────┴─G◄─┴──────┘ + // │ │ + // └─────────────┘ + inputGraph[2] = generateGraph( + { "A", "B", "C", "D", "E", "F", "G", "H", "I" }, + { + edge("A", "B"), + edge("A", "C"), + edge("B", "C"), + edge("B", "I"), + edge("B", "E"), + edge("C", "D"), + edge("D", "B"), + edge("E", "H"), + edge("E", "F"), + edge("F", "G"), + edge("F", "C"), + edge("G", "E"), + edge("G", "A"), + edge("G", "D"), + edge("H", "G"), + edge("I", "E"), + edge("I", "H") + }, + {0, 0, 0, 0, 1, 1, 1, 1, 5}, + { + {"A", 0}, + {"B", 1}, + {"C", 2}, + {"D", 3}, + {"I", 4}, + {"E", 5}, + {"H", 6}, + {"G", 7}, + {"F", 8} + } + ); - // T. Lengauer and R. E. Tarjan pg. 122 fig. 1 - // ref: https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf - inputGraph[3] = generateGraph( - { "R", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "L", "K" }, - { - edge("R", "B"), - edge("R", "A"), - edge("R", "C"), - edge("B", "A"), - edge("B", "D"), - edge("B", "E"), - edge("A", "D"), - edge("D", "L"), - edge("L", "H"), - edge("E", "H"), - edge("H", "E"), - edge("H", "K"), - edge("K", "I"), - edge("K", "R"), - edge("C", "F"), - edge("C", "G"), - edge("F", "I"), - edge("G", "I"), - edge("G", "J"), - edge("J", "I"), - edge("I", "K"), - }, - {0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 9, 9, 11}, - { - {"R", 0}, - {"B", 1}, - {"A", 2}, - {"D", 3}, - {"L", 4}, - {"H", 5}, - {"E", 6}, - {"K", 7}, - {"I", 8}, - {"C", 9}, - {"F", 10}, - {"G", 11}, - {"J", 12} - } - ); + // T. Lengauer and R. E. Tarjan pg. 122 fig. 1 + // ref: https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf + inputGraph[3] = generateGraph( + { "R", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "L", "K" }, + { + edge("R", "B"), + edge("R", "A"), + edge("R", "C"), + edge("B", "A"), + edge("B", "D"), + edge("B", "E"), + edge("A", "D"), + edge("D", "L"), + edge("L", "H"), + edge("E", "H"), + edge("H", "E"), + edge("H", "K"), + edge("K", "I"), + edge("K", "R"), + edge("C", "F"), + edge("C", "G"), + edge("F", "I"), + edge("G", "I"), + edge("G", "J"), + edge("J", "I"), + edge("I", "K"), + }, + {0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 9, 9, 11}, + { + {"R", 0}, + {"B", 1}, + {"A", 2}, + {"D", 3}, + {"L", 4}, + {"H", 5}, + {"E", 6}, + {"K", 7}, + {"I", 8}, + {"C", 9}, + {"F", 10}, + {"G", 11}, + {"J", 12} + } + ); - // Extracted from Loukas Georgiadis Dissertation - Linear-Time Algorithms for Dominators and Related Problems - // pg. 12 Fig. 2.2 - // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - inputGraph[4] = generateGraph( - { "R", "W", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "Y" }, - { - edge("R", "W"), - edge("R", "Y"), - edge("W", "X1"), - edge("Y", "X7"), - edge("X1", "X2"), - edge("X2", "X1"), - edge("X2", "X3"), - edge("X3", "X2"), - edge("X3", "X4"), - edge("X4", "X3"), - edge("X4", "X5"), - edge("X5", "X4"), - edge("X5", "X6"), - edge("X6", "X5"), - edge("X6", "X7"), - edge("X7", "X6") - }, - {0, 0, 0, 0, 0, 0, 0, 0, 0 , 0}, - { - {"R", 0}, - {"W", 1}, - {"X1", 2}, - {"X2", 3}, - {"X3", 4}, - {"X4", 5}, - {"X5", 6}, - {"X6", 7}, - {"X7", 8}, - {"Y", 9} - } - ); + // Extracted from Loukas Georgiadis Dissertation - Linear-Time Algorithms for Dominators and Related Problems + // pg. 12 Fig. 2.2 + // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf + inputGraph[4] = generateGraph( + { "R", "W", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "Y" }, + { + edge("R", "W"), + edge("R", "Y"), + edge("W", "X1"), + edge("Y", "X7"), + edge("X1", "X2"), + edge("X2", "X1"), + edge("X2", "X3"), + edge("X3", "X2"), + edge("X3", "X4"), + edge("X4", "X3"), + edge("X4", "X5"), + edge("X5", "X4"), + edge("X5", "X6"), + edge("X6", "X5"), + edge("X6", "X7"), + edge("X7", "X6") + }, + {0, 0, 0, 0, 0, 0, 0, 0, 0 , 0}, + { + {"R", 0}, + {"W", 1}, + {"X1", 2}, + {"X2", 3}, + {"X3", 4}, + {"X4", 5}, + {"X5", 6}, + {"X6", 7}, + {"X7", 8}, + {"Y", 9} + } + ); - // Worst-case families for k = 3 - // Example itworst(3) pg. 26 fig. 2.9 - // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - inputGraph[5] = generateGraph( - { "R", "W1", "W2", "W3", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3" }, - { - edge("R", "W1"), - edge("R", "X1"), - edge("R", "Z3"), - edge("W1", "W2"), - edge("W2", "W3"), - edge("X1", "X2"), - edge("X2", "X3"), - edge("X3", "Y1"), - edge("Y1", "W1"), - edge("Y1", "W2"), - edge("Y1", "W3"), - edge("Y1", "Y2"), - edge("Y2", "W1"), - edge("Y2", "W2"), - edge("Y2", "W3"), - edge("Y2", "Y3"), - edge("Y3", "W1"), - edge("Y3", "W2"), - edge("Y3", "W3"), - edge("Y3", "Z1"), - edge("Z1", "Z2"), - edge("Z2", "Z1"), - edge("Z2", "Z3"), - edge("Z3", "Z2") - }, - {0, 0, 0, 0, 0, 4, 5, 6, 7, 8, 0, 0, 0}, - { - {"R", 0}, - {"W1", 1}, - {"W2", 2}, - {"W3", 3}, - {"X1", 4}, - {"X2", 5}, - {"X3", 6}, - {"Y1", 7}, - {"Y2", 8}, - {"Y3", 9}, - {"Z1", 10}, - {"Z2", 11}, - {"Z3", 12} - } - ); + // Worst-case families for k = 3 + // Example itworst(3) pg. 26 fig. 2.9 + // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf + inputGraph[5] = generateGraph( + { "R", "W1", "W2", "W3", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3" }, + { + edge("R", "W1"), + edge("R", "X1"), + edge("R", "Z3"), + edge("W1", "W2"), + edge("W2", "W3"), + edge("X1", "X2"), + edge("X2", "X3"), + edge("X3", "Y1"), + edge("Y1", "W1"), + edge("Y1", "W2"), + edge("Y1", "W3"), + edge("Y1", "Y2"), + edge("Y2", "W1"), + edge("Y2", "W2"), + edge("Y2", "W3"), + edge("Y2", "Y3"), + edge("Y3", "W1"), + edge("Y3", "W2"), + edge("Y3", "W3"), + edge("Y3", "Z1"), + edge("Z1", "Z2"), + edge("Z2", "Z1"), + edge("Z2", "Z3"), + edge("Z3", "Z2") + }, + {0, 0, 0, 0, 0, 4, 5, 6, 7, 8, 0, 0, 0}, + { + {"R", 0}, + {"W1", 1}, + {"W2", 2}, + {"W3", 3}, + {"X1", 4}, + {"X2", 5}, + {"X3", 6}, + {"Y1", 7}, + {"Y2", 8}, + {"Y3", 9}, + {"Z1", 10}, + {"Z2", 11}, + {"Z3", 12} + } + ); - // Worst-case families for k = 3 - // Example idfsquad(3) pg. 26 fig. 2.9 - // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - inputGraph[6] = generateGraph( - { "R", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3" }, - { - edge("R", "X1"), - edge("R", "Z1"), - edge("X1", "Y1"), - edge("X1", "X2"), - edge("X2", "X3"), - edge("X2", "Y2"), - edge("X3", "Y3"), - edge("Y1", "Z1"), - edge("Y1", "Z2"), - edge("Z1", "Y1"), - edge("Y2", "Z2"), - edge("Y2", "Z3"), - edge("Z2", "Y2"), - edge("Y3", "Z3"), - edge("Z3", "Y3") - }, - {0, 0, 0, 0, 0, 0, 0, 0, 1, 8}, - { - {"R", 0}, - {"X1", 1}, - {"Y1", 2}, - {"Z1", 3}, - {"Z2", 4}, - {"Y2", 5}, - {"Z3", 6}, - {"Y3", 7}, - {"X2", 8}, - {"X3", 9} - } - ); + // Worst-case families for k = 3 + // Example idfsquad(3) pg. 26 fig. 2.9 + // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf + inputGraph[6] = generateGraph( + { "R", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3" }, + { + edge("R", "X1"), + edge("R", "Z1"), + edge("X1", "Y1"), + edge("X1", "X2"), + edge("X2", "X3"), + edge("X2", "Y2"), + edge("X3", "Y3"), + edge("Y1", "Z1"), + edge("Y1", "Z2"), + edge("Z1", "Y1"), + edge("Y2", "Z2"), + edge("Y2", "Z3"), + edge("Z2", "Y2"), + edge("Y3", "Z3"), + edge("Z3", "Y3") + }, + {0, 0, 0, 0, 0, 0, 0, 0, 1, 8}, + { + {"R", 0}, + {"X1", 1}, + {"Y1", 2}, + {"Z1", 3}, + {"Z2", 4}, + {"Y2", 5}, + {"Z3", 6}, + {"Y3", 7}, + {"X2", 8}, + {"X3", 9} + } + ); - // Worst-case families for k = 3 - // Example ibfsquad(3) pg. 26 fig. 2.9 - // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - inputGraph[7] = generateGraph( - { "R", "W", "X1", "X2", "X3", "Y", "Z" }, - { - edge("R", "W"), - edge("R", "Y"), - edge("W", "X1"), - edge("W", "X2"), - edge("W", "X3"), - edge("Y", "Z"), - edge("Z", "X3"), - edge("X3", "X2"), - edge("X2", "X1") - }, - {0, 0, 0, 0, 0, 0, 5}, - { - {"R", 0}, - {"W", 1}, - {"X1", 2}, - {"X2", 3}, - {"X3", 4}, - {"Y", 5}, - {"Z", 6} - } - ); + // Worst-case families for k = 3 + // Example ibfsquad(3) pg. 26 fig. 2.9 + // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf + inputGraph[7] = generateGraph( + { "R", "W", "X1", "X2", "X3", "Y", "Z" }, + { + edge("R", "W"), + edge("R", "Y"), + edge("W", "X1"), + edge("W", "X2"), + edge("W", "X3"), + edge("Y", "Z"), + edge("Z", "X3"), + edge("X3", "X2"), + edge("X2", "X1") + }, + {0, 0, 0, 0, 0, 0, 5}, + { + {"R", 0}, + {"W", 1}, + {"X1", 2}, + {"X2", 3}, + {"X3", 4}, + {"Y", 5}, + {"Z", 6} + } + ); - // Worst-case families for k = 3 - // Example sncaworst(3) pg. 26 fig. 2.9 - // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - inputGraph[8] = generateGraph( - { "R", "X1", "X2", "X3", "Y1", "Y2", "Y3" }, - { - edge("R", "X1"), - edge("R", "Y1"), - edge("R", "Y2"), - edge("R", "Y3"), - edge("X1", "X2"), - edge("X2", "X3"), - edge("X3", "Y1"), - edge("X3", "Y2"), - edge("X3", "Y3") - }, - {0, 0, 1, 2, 0, 0, 0}, - { - {"R", 0}, - {"X1", 1}, - {"X2", 2}, - {"X3", 3}, - {"Y1", 4}, - {"Y2", 5}, - {"Y3", 6}, - } - ); + // Worst-case families for k = 3 + // Example sncaworst(3) pg. 26 fig. 2.9 + // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf + inputGraph[8] = generateGraph( + { "R", "X1", "X2", "X3", "Y1", "Y2", "Y3" }, + { + edge("R", "X1"), + edge("R", "Y1"), + edge("R", "Y2"), + edge("R", "Y3"), + edge("X1", "X2"), + edge("X2", "X3"), + edge("X3", "Y1"), + edge("X3", "Y2"), + edge("X3", "Y3") + }, + {0, 0, 1, 2, 0, 0, 0}, + { + {"R", 0}, + {"X1", 1}, + {"X2", 2}, + {"X3", 3}, + {"Y1", 4}, + {"Y2", 5}, + {"Y3", 6}, + } + ); - for (ImmediateDominatorTest const* g: inputGraph) - { - Dominator< - ImmediateDominatorTest::Vertex, - ImmediateDominatorTest::ForEachVertexSuccessorTest - > dom(*g->entry, g->numVertices); + for (ImmediateDominatorTest const* g: inputGraph) + { + Dominator< + ImmediateDominatorTest::Vertex, + ImmediateDominatorTest::ForEachVertexSuccessorTest + > dom(*g->entry, g->numVertices); - for (auto [v, idx]: dom.vertexIndices()) - BOOST_CHECK(g->expectedDFSIndices.at(v.data) == idx); - BOOST_TEST(dom.immediateDominators() == g->expectedIdom); - } + for (auto [v, idx]: dom.vertexIndices()) + BOOST_CHECK(g->expectedDFSIndices.at(v.data) == idx); + BOOST_TEST(dom.immediateDominators() == g->expectedIdom); + } } From 5170f33f53e478647aa95183eeff840c2bc4ed2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 17:15:49 +0200 Subject: [PATCH 04/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- test/libyul/DominatorTest.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index 8c7e20390..9e80c98ad 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -449,16 +449,16 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) } ); - for (ImmediateDominatorTest const* g: inputGraph) + for (ImmediateDominatorTest const* test: inputGraph) { Dominator< ImmediateDominatorTest::Vertex, ImmediateDominatorTest::ForEachVertexSuccessorTest - > dom(*g->entry, g->numVertices); + > dominatorFinder(*test->entry, test->numVertices); - for (auto [v, idx]: dom.vertexIndices()) - BOOST_CHECK(g->expectedDFSIndices.at(v.data) == idx); - BOOST_TEST(dom.immediateDominators() == g->expectedIdom); + for (auto [v, idx]: dominatorFinder.vertexIndices()) + BOOST_CHECK(test->expectedDFSIndices.at(v.data) == idx); + BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); } } From edd4e1c95230ecbf398521e77656f45e7e27588e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 17:22:37 +0200 Subject: [PATCH 05/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- test/libyul/DominatorTest.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index 9e80c98ad..ffb295c29 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -43,7 +43,7 @@ struct ImmediateDominatorTest template void operator()(Vertex _v, Callable&& _callable) const { - for (auto w: _v.successors) + for (auto const& w: _v.successors) _callable(*w); } }; @@ -76,7 +76,7 @@ protected: soltestAssert(_vertices.size() > 0 && _vertices.size() == graph->vertices.size()); graph->numVertices = _vertices.size(); - for (auto [from, to]: _edges) + for (auto const& [from, to]: _edges) graph->vertices[from]->successors.push_back(graph->vertices[to]); graph->expectedIdom = _expectedIdom; @@ -456,7 +456,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) ImmediateDominatorTest::ForEachVertexSuccessorTest > dominatorFinder(*test->entry, test->numVertices); - for (auto [v, idx]: dominatorFinder.vertexIndices()) + for (auto const&[v, idx]: dominatorFinder.vertexIndices()) BOOST_CHECK(test->expectedDFSIndices.at(v.data) == idx); BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); } From d5dbab0b91c1d56865913116625ab1836d27b3e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 17:26:51 +0200 Subject: [PATCH 06/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- test/libyul/DominatorTest.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index ffb295c29..abc9862a1 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -108,7 +108,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // │ │ // └──►F◄──┘ inputGraph[0] = generateGraph( - { "A", "B", "C", "D", "E", "F", "G", "H" }, + {"A", "B", "C", "D", "E", "F", "G", "H"}, { edge("A", "B"), edge("B", "C"), @@ -142,7 +142,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // │ │ │ │ // └───►G◄─┴─────┘ inputGraph[1] = generateGraph( - { "A", "B", "C", "D", "E", "F", "G" }, + {"A", "B", "C", "D", "E", "F", "G"}, { edge("A", "B"), edge("B", "C"), @@ -189,7 +189,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // │ │ // └─────────────┘ inputGraph[2] = generateGraph( - { "A", "B", "C", "D", "E", "F", "G", "H", "I" }, + {"A", "B", "C", "D", "E", "F", "G", "H", "I"}, { edge("A", "B"), edge("A", "C"), @@ -226,7 +226,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // T. Lengauer and R. E. Tarjan pg. 122 fig. 1 // ref: https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf inputGraph[3] = generateGraph( - { "R", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "L", "K" }, + {"R", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "L", "K"}, { edge("R", "B"), edge("R", "A"), @@ -272,7 +272,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // pg. 12 Fig. 2.2 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf inputGraph[4] = generateGraph( - { "R", "W", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "Y" }, + {"R", "W", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "Y"}, { edge("R", "W"), edge("R", "Y"), @@ -291,7 +291,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) edge("X6", "X7"), edge("X7", "X6") }, - {0, 0, 0, 0, 0, 0, 0, 0, 0 , 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { {"R", 0}, {"W", 1}, @@ -310,7 +310,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // Example itworst(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf inputGraph[5] = generateGraph( - { "R", "W1", "W2", "W3", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3" }, + {"R", "W1", "W2", "W3", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3"}, { edge("R", "W1"), edge("R", "X1"), @@ -360,7 +360,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // Example idfsquad(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf inputGraph[6] = generateGraph( - { "R", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3" }, + {"R", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3"}, { edge("R", "X1"), edge("R", "Z1"), @@ -397,7 +397,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // Example ibfsquad(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf inputGraph[7] = generateGraph( - { "R", "W", "X1", "X2", "X3", "Y", "Z" }, + {"R", "W", "X1", "X2", "X3", "Y", "Z"}, { edge("R", "W"), edge("R", "Y"), @@ -425,7 +425,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // Example sncaworst(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf inputGraph[8] = generateGraph( - { "R", "X1", "X2", "X3", "Y1", "Y2", "Y3" }, + {"R", "X1", "X2", "X3", "Y1", "Y2", "Y3"}, { edge("R", "X1"), edge("R", "Y1"), @@ -460,7 +460,6 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) BOOST_CHECK(test->expectedDFSIndices.at(v.data) == idx); BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); } - } BOOST_AUTO_TEST_SUITE_END() From bf938d2712ffd1c88158bcb61cff151946e94849 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 17:27:04 +0200 Subject: [PATCH 07/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- test/libyul/DominatorTest.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index abc9862a1..995699e03 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -28,12 +28,12 @@ namespace solidity::yul::test struct ImmediateDominatorTest { struct Vertex { - std::string data; + std::string name; std::vector successors; bool operator<(Vertex const& _other) const { - return data < _other.data; + return name < _other.name; } }; @@ -457,7 +457,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) > dominatorFinder(*test->entry, test->numVertices); for (auto const&[v, idx]: dominatorFinder.vertexIndices()) - BOOST_CHECK(test->expectedDFSIndices.at(v.data) == idx); + BOOST_CHECK(test->expectedDFSIndices.at(v.name) == idx); BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); } } From db5b657bd2b1aeb9a5750ae15f0edac3aea6438a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 17:27:39 +0200 Subject: [PATCH 08/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- test/libyul/DominatorTest.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index 995699e03..f98b80973 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -463,4 +463,5 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) } BOOST_AUTO_TEST_SUITE_END() -} + +} // namespace solidity::yul::test From 0bf0d1943aeccd0547d44c7d1b9bd5fcf22e4527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 18:00:38 +0200 Subject: [PATCH 09/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- test/libyul/DominatorTest.cpp | 266 +++++++++++++++++----------------- 1 file changed, 133 insertions(+), 133 deletions(-) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index f98b80973..371fc025f 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -37,7 +37,7 @@ struct ImmediateDominatorTest } }; - typedef std::pair edge; + typedef std::pair Edge; struct ForEachVertexSuccessorTest { template @@ -61,7 +61,7 @@ class DominatorFixture protected: static ImmediateDominatorTest const* generateGraph( std::vector _vertices, - std::vector _edges, + std::vector _edges, std::vector _expectedIdom, std::map _expectedDFSIndices ) @@ -89,7 +89,7 @@ BOOST_AUTO_TEST_SUITE(Dominators) BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) { - typedef ImmediateDominatorTest::edge edge; + typedef ImmediateDominatorTest::Edge Edge; std::vector inputGraph(9); // A @@ -110,15 +110,15 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) inputGraph[0] = generateGraph( {"A", "B", "C", "D", "E", "F", "G", "H"}, { - edge("A", "B"), - edge("B", "C"), - edge("B", "D"), - edge("C", "D"), - edge("C", "G"), - edge("D", "E"), - edge("E", "F"), - edge("G", "H"), - edge("H", "F") + Edge("A", "B"), + Edge("B", "C"), + Edge("B", "D"), + Edge("C", "D"), + Edge("C", "G"), + Edge("D", "E"), + Edge("E", "F"), + Edge("G", "H"), + Edge("H", "F") }, {0, 0, 1, 1, 3, 1, 2, 6}, { @@ -144,16 +144,16 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) inputGraph[1] = generateGraph( {"A", "B", "C", "D", "E", "F", "G"}, { - edge("A", "B"), - edge("B", "C"), - edge("C", "G"), - edge("C", "A"), - edge("A", "D"), - edge("D", "E"), - edge("D", "F"), - edge("E", "G"), - edge("F", "G"), - edge("G", "C") + Edge("A", "B"), + Edge("B", "C"), + Edge("C", "G"), + Edge("C", "A"), + Edge("A", "D"), + Edge("D", "E"), + Edge("D", "F"), + Edge("E", "G"), + Edge("F", "G"), + Edge("G", "C") }, {0, 0, 0, 0, 0, 4, 4}, { @@ -191,23 +191,23 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) inputGraph[2] = generateGraph( {"A", "B", "C", "D", "E", "F", "G", "H", "I"}, { - edge("A", "B"), - edge("A", "C"), - edge("B", "C"), - edge("B", "I"), - edge("B", "E"), - edge("C", "D"), - edge("D", "B"), - edge("E", "H"), - edge("E", "F"), - edge("F", "G"), - edge("F", "C"), - edge("G", "E"), - edge("G", "A"), - edge("G", "D"), - edge("H", "G"), - edge("I", "E"), - edge("I", "H") + Edge("A", "B"), + Edge("A", "C"), + Edge("B", "C"), + Edge("B", "I"), + Edge("B", "E"), + Edge("C", "D"), + Edge("D", "B"), + Edge("E", "H"), + Edge("E", "F"), + Edge("F", "G"), + Edge("F", "C"), + Edge("G", "E"), + Edge("G", "A"), + Edge("G", "D"), + Edge("H", "G"), + Edge("I", "E"), + Edge("I", "H") }, {0, 0, 0, 0, 1, 1, 1, 1, 5}, { @@ -228,27 +228,27 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) inputGraph[3] = generateGraph( {"R", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "L", "K"}, { - edge("R", "B"), - edge("R", "A"), - edge("R", "C"), - edge("B", "A"), - edge("B", "D"), - edge("B", "E"), - edge("A", "D"), - edge("D", "L"), - edge("L", "H"), - edge("E", "H"), - edge("H", "E"), - edge("H", "K"), - edge("K", "I"), - edge("K", "R"), - edge("C", "F"), - edge("C", "G"), - edge("F", "I"), - edge("G", "I"), - edge("G", "J"), - edge("J", "I"), - edge("I", "K"), + Edge("R", "B"), + Edge("R", "A"), + Edge("R", "C"), + Edge("B", "A"), + Edge("B", "D"), + Edge("B", "E"), + Edge("A", "D"), + Edge("D", "L"), + Edge("L", "H"), + Edge("E", "H"), + Edge("H", "E"), + Edge("H", "K"), + Edge("K", "I"), + Edge("K", "R"), + Edge("C", "F"), + Edge("C", "G"), + Edge("F", "I"), + Edge("G", "I"), + Edge("G", "J"), + Edge("J", "I"), + Edge("I", "K"), }, {0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 9, 9, 11}, { @@ -274,22 +274,22 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) inputGraph[4] = generateGraph( {"R", "W", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "Y"}, { - edge("R", "W"), - edge("R", "Y"), - edge("W", "X1"), - edge("Y", "X7"), - edge("X1", "X2"), - edge("X2", "X1"), - edge("X2", "X3"), - edge("X3", "X2"), - edge("X3", "X4"), - edge("X4", "X3"), - edge("X4", "X5"), - edge("X5", "X4"), - edge("X5", "X6"), - edge("X6", "X5"), - edge("X6", "X7"), - edge("X7", "X6") + Edge("R", "W"), + Edge("R", "Y"), + Edge("W", "X1"), + Edge("Y", "X7"), + Edge("X1", "X2"), + Edge("X2", "X1"), + Edge("X2", "X3"), + Edge("X3", "X2"), + Edge("X3", "X4"), + Edge("X4", "X3"), + Edge("X4", "X5"), + Edge("X5", "X4"), + Edge("X5", "X6"), + Edge("X6", "X5"), + Edge("X6", "X7"), + Edge("X7", "X6") }, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { @@ -312,30 +312,30 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) inputGraph[5] = generateGraph( {"R", "W1", "W2", "W3", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3"}, { - edge("R", "W1"), - edge("R", "X1"), - edge("R", "Z3"), - edge("W1", "W2"), - edge("W2", "W3"), - edge("X1", "X2"), - edge("X2", "X3"), - edge("X3", "Y1"), - edge("Y1", "W1"), - edge("Y1", "W2"), - edge("Y1", "W3"), - edge("Y1", "Y2"), - edge("Y2", "W1"), - edge("Y2", "W2"), - edge("Y2", "W3"), - edge("Y2", "Y3"), - edge("Y3", "W1"), - edge("Y3", "W2"), - edge("Y3", "W3"), - edge("Y3", "Z1"), - edge("Z1", "Z2"), - edge("Z2", "Z1"), - edge("Z2", "Z3"), - edge("Z3", "Z2") + Edge("R", "W1"), + Edge("R", "X1"), + Edge("R", "Z3"), + Edge("W1", "W2"), + Edge("W2", "W3"), + Edge("X1", "X2"), + Edge("X2", "X3"), + Edge("X3", "Y1"), + Edge("Y1", "W1"), + Edge("Y1", "W2"), + Edge("Y1", "W3"), + Edge("Y1", "Y2"), + Edge("Y2", "W1"), + Edge("Y2", "W2"), + Edge("Y2", "W3"), + Edge("Y2", "Y3"), + Edge("Y3", "W1"), + Edge("Y3", "W2"), + Edge("Y3", "W3"), + Edge("Y3", "Z1"), + Edge("Z1", "Z2"), + Edge("Z2", "Z1"), + Edge("Z2", "Z3"), + Edge("Z3", "Z2") }, {0, 0, 0, 0, 0, 4, 5, 6, 7, 8, 0, 0, 0}, { @@ -362,21 +362,21 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) inputGraph[6] = generateGraph( {"R", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3"}, { - edge("R", "X1"), - edge("R", "Z1"), - edge("X1", "Y1"), - edge("X1", "X2"), - edge("X2", "X3"), - edge("X2", "Y2"), - edge("X3", "Y3"), - edge("Y1", "Z1"), - edge("Y1", "Z2"), - edge("Z1", "Y1"), - edge("Y2", "Z2"), - edge("Y2", "Z3"), - edge("Z2", "Y2"), - edge("Y3", "Z3"), - edge("Z3", "Y3") + Edge("R", "X1"), + Edge("R", "Z1"), + Edge("X1", "Y1"), + Edge("X1", "X2"), + Edge("X2", "X3"), + Edge("X2", "Y2"), + Edge("X3", "Y3"), + Edge("Y1", "Z1"), + Edge("Y1", "Z2"), + Edge("Z1", "Y1"), + Edge("Y2", "Z2"), + Edge("Y2", "Z3"), + Edge("Z2", "Y2"), + Edge("Y3", "Z3"), + Edge("Z3", "Y3") }, {0, 0, 0, 0, 0, 0, 0, 0, 1, 8}, { @@ -399,15 +399,15 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) inputGraph[7] = generateGraph( {"R", "W", "X1", "X2", "X3", "Y", "Z"}, { - edge("R", "W"), - edge("R", "Y"), - edge("W", "X1"), - edge("W", "X2"), - edge("W", "X3"), - edge("Y", "Z"), - edge("Z", "X3"), - edge("X3", "X2"), - edge("X2", "X1") + Edge("R", "W"), + Edge("R", "Y"), + Edge("W", "X1"), + Edge("W", "X2"), + Edge("W", "X3"), + Edge("Y", "Z"), + Edge("Z", "X3"), + Edge("X3", "X2"), + Edge("X2", "X1") }, {0, 0, 0, 0, 0, 0, 5}, { @@ -427,15 +427,15 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) inputGraph[8] = generateGraph( {"R", "X1", "X2", "X3", "Y1", "Y2", "Y3"}, { - edge("R", "X1"), - edge("R", "Y1"), - edge("R", "Y2"), - edge("R", "Y3"), - edge("X1", "X2"), - edge("X2", "X3"), - edge("X3", "Y1"), - edge("X3", "Y2"), - edge("X3", "Y3") + Edge("R", "X1"), + Edge("R", "Y1"), + Edge("R", "Y2"), + Edge("R", "Y3"), + Edge("X1", "X2"), + Edge("X2", "X3"), + Edge("X3", "Y1"), + Edge("X3", "Y2"), + Edge("X3", "Y3") }, {0, 0, 1, 2, 0, 0, 0}, { From d33f8f951d758537514bd3f76d1d7a31f3a5159f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 18:14:08 +0200 Subject: [PATCH 10/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- test/libyul/DominatorTest.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index 371fc025f..0bc0c7fd2 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -20,6 +20,9 @@ #include +#include +#include + using namespace solidity::yul; namespace solidity::yul::test @@ -83,6 +86,15 @@ protected: graph->expectedDFSIndices = _expectedDFSIndices; return graph; } + + std::map toDFSIndices(std::map const& _vertexIndices) + { + auto convertIndex = [](std::pair const& _pair) -> std::pair + { + return {_pair.first.name, _pair.second}; + }; + return _vertexIndices | ranges::views::transform(convertIndex) | ranges::to; + } }; BOOST_AUTO_TEST_SUITE(Dominators) @@ -456,8 +468,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) ImmediateDominatorTest::ForEachVertexSuccessorTest > dominatorFinder(*test->entry, test->numVertices); - for (auto const&[v, idx]: dominatorFinder.vertexIndices()) - BOOST_CHECK(test->expectedDFSIndices.at(v.name) == idx); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); } } From 83abb3b8ab7b1d8c1872d2c3db470769aabe1c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 18:28:31 +0200 Subject: [PATCH 11/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- test/libyul/DominatorTest.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index 0bc0c7fd2..844e96164 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -62,7 +62,7 @@ class DominatorFixture { typedef ImmediateDominatorTest::Vertex Vertex; protected: - static ImmediateDominatorTest const* generateGraph( + static ImmediateDominatorTest const* prepareTestDefinition( std::vector _vertices, std::vector _edges, std::vector _expectedIdom, @@ -102,7 +102,7 @@ BOOST_AUTO_TEST_SUITE(Dominators) BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) { typedef ImmediateDominatorTest::Edge Edge; - std::vector inputGraph(9); + std::vector testDefinitions(9); // A // │ @@ -119,7 +119,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // E H // │ │ // └──►F◄──┘ - inputGraph[0] = generateGraph( + testDefinitions[0] = prepareTestDefinition( {"A", "B", "C", "D", "E", "F", "G", "H"}, { Edge("A", "B"), @@ -153,7 +153,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // └─C◄───┐ E F // │ │ │ │ // └───►G◄─┴─────┘ - inputGraph[1] = generateGraph( + testDefinitions[1] = prepareTestDefinition( {"A", "B", "C", "D", "E", "F", "G"}, { Edge("A", "B"), @@ -200,7 +200,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // │ └─────┴─G◄─┴──────┘ // │ │ // └─────────────┘ - inputGraph[2] = generateGraph( + testDefinitions[2] = prepareTestDefinition( {"A", "B", "C", "D", "E", "F", "G", "H", "I"}, { Edge("A", "B"), @@ -237,7 +237,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // T. Lengauer and R. E. Tarjan pg. 122 fig. 1 // ref: https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf - inputGraph[3] = generateGraph( + testDefinitions[3] = prepareTestDefinition( {"R", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "L", "K"}, { Edge("R", "B"), @@ -283,7 +283,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // Extracted from Loukas Georgiadis Dissertation - Linear-Time Algorithms for Dominators and Related Problems // pg. 12 Fig. 2.2 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - inputGraph[4] = generateGraph( + testDefinitions[4] = prepareTestDefinition( {"R", "W", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "Y"}, { Edge("R", "W"), @@ -321,7 +321,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // Worst-case families for k = 3 // Example itworst(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - inputGraph[5] = generateGraph( + testDefinitions[5] = prepareTestDefinition( {"R", "W1", "W2", "W3", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3"}, { Edge("R", "W1"), @@ -371,7 +371,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // Worst-case families for k = 3 // Example idfsquad(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - inputGraph[6] = generateGraph( + testDefinitions[6] = prepareTestDefinition( {"R", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3"}, { Edge("R", "X1"), @@ -408,7 +408,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // Worst-case families for k = 3 // Example ibfsquad(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - inputGraph[7] = generateGraph( + testDefinitions[7] = prepareTestDefinition( {"R", "W", "X1", "X2", "X3", "Y", "Z"}, { Edge("R", "W"), @@ -436,7 +436,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // Worst-case families for k = 3 // Example sncaworst(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - inputGraph[8] = generateGraph( + testDefinitions[8] = prepareTestDefinition( {"R", "X1", "X2", "X3", "Y1", "Y2", "Y3"}, { Edge("R", "X1"), @@ -461,7 +461,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) } ); - for (ImmediateDominatorTest const* test: inputGraph) + for (ImmediateDominatorTest const* test: testDefinitions) { Dominator< ImmediateDominatorTest::Vertex, From bb55b7cfe5d3abe9d9e1e130c372314acd76fa37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 18:36:33 +0200 Subject: [PATCH 12/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- test/libyul/DominatorTest.cpp | 92 +++++++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 25 deletions(-) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index 844e96164..46c5ee312 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -97,13 +97,16 @@ protected: } }; +typedef ImmediateDominatorTest::Edge Edge; +typedef Dominator< + ImmediateDominatorTest::Vertex, + ImmediateDominatorTest::ForEachVertexSuccessorTest +> DominatorFinder; + BOOST_AUTO_TEST_SUITE(Dominators) -BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) +BOOST_FIXTURE_TEST_CASE(immediate_dominator_1, DominatorFixture) { - typedef ImmediateDominatorTest::Edge Edge; - std::vector testDefinitions(9); - // A // │ // ▼ @@ -119,7 +122,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // E H // │ │ // └──►F◄──┘ - testDefinitions[0] = prepareTestDefinition( + ImmediateDominatorTest const* test = prepareTestDefinition( {"A", "B", "C", "D", "E", "F", "G", "H"}, { Edge("A", "B"), @@ -144,7 +147,13 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) {"H", 7} } ); + DominatorFinder dominatorFinder(*test->entry, test->numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); +} +BOOST_FIXTURE_TEST_CASE(immediate_dominator_2, DominatorFixture) +{ // ┌────►A──────┐ // │ │ ▼ // │ B◄──┘ ┌──D──┐ @@ -153,7 +162,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // └─C◄───┐ E F // │ │ │ │ // └───►G◄─┴─────┘ - testDefinitions[1] = prepareTestDefinition( + ImmediateDominatorTest const* test = prepareTestDefinition( {"A", "B", "C", "D", "E", "F", "G"}, { Edge("A", "B"), @@ -178,7 +187,13 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) {"F", 6} } ); + DominatorFinder dominatorFinder(*test->entry, test->numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); +} +BOOST_FIXTURE_TEST_CASE(immediate_dominator_3, DominatorFixture) +{ // ┌─────────┐ // │ ▼ // │ ┌───A───┐ @@ -200,7 +215,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) // │ └─────┴─G◄─┴──────┘ // │ │ // └─────────────┘ - testDefinitions[2] = prepareTestDefinition( + ImmediateDominatorTest const* test = prepareTestDefinition( {"A", "B", "C", "D", "E", "F", "G", "H", "I"}, { Edge("A", "B"), @@ -234,10 +249,16 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) {"F", 8} } ); + DominatorFinder dominatorFinder(*test->entry, test->numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); +} +BOOST_FIXTURE_TEST_CASE(langauer_tarjan_p122_fig1, DominatorFixture) +{ // T. Lengauer and R. E. Tarjan pg. 122 fig. 1 // ref: https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf - testDefinitions[3] = prepareTestDefinition( + ImmediateDominatorTest const* test = prepareTestDefinition( {"R", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "L", "K"}, { Edge("R", "B"), @@ -279,11 +300,17 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) {"J", 12} } ); + DominatorFinder dominatorFinder(*test->entry, test->numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); +} +BOOST_FIXTURE_TEST_CASE(loukas_georgiadis, DominatorFixture) +{ // Extracted from Loukas Georgiadis Dissertation - Linear-Time Algorithms for Dominators and Related Problems // pg. 12 Fig. 2.2 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - testDefinitions[4] = prepareTestDefinition( + ImmediateDominatorTest const* test = prepareTestDefinition( {"R", "W", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "Y"}, { Edge("R", "W"), @@ -317,11 +344,17 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) {"Y", 9} } ); + DominatorFinder dominatorFinder(*test->entry, test->numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); +} +BOOST_FIXTURE_TEST_CASE(itworst, DominatorFixture) +{ // Worst-case families for k = 3 // Example itworst(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - testDefinitions[5] = prepareTestDefinition( + ImmediateDominatorTest const* test = prepareTestDefinition( {"R", "W1", "W2", "W3", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3"}, { Edge("R", "W1"), @@ -366,12 +399,17 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) {"Z3", 12} } ); + DominatorFinder dominatorFinder(*test->entry, test->numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); +} - +BOOST_FIXTURE_TEST_CASE(idfsquad, DominatorFixture) +{ // Worst-case families for k = 3 // Example idfsquad(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - testDefinitions[6] = prepareTestDefinition( + ImmediateDominatorTest const* test = prepareTestDefinition( {"R", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3"}, { Edge("R", "X1"), @@ -404,11 +442,17 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) {"X3", 9} } ); + DominatorFinder dominatorFinder(*test->entry, test->numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); +} +BOOST_FIXTURE_TEST_CASE(ibsfquad, DominatorFixture) +{ // Worst-case families for k = 3 // Example ibfsquad(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - testDefinitions[7] = prepareTestDefinition( + ImmediateDominatorTest const* test = prepareTestDefinition( {"R", "W", "X1", "X2", "X3", "Y", "Z"}, { Edge("R", "W"), @@ -432,11 +476,17 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) {"Z", 6} } ); + DominatorFinder dominatorFinder(*test->entry, test->numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); +} +BOOST_FIXTURE_TEST_CASE(sncaworst, DominatorFixture) +{ // Worst-case families for k = 3 // Example sncaworst(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - testDefinitions[8] = prepareTestDefinition( + ImmediateDominatorTest const* test = prepareTestDefinition( {"R", "X1", "X2", "X3", "Y1", "Y2", "Y3"}, { Edge("R", "X1"), @@ -460,17 +510,9 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) {"Y3", 6}, } ); - - for (ImmediateDominatorTest const* test: testDefinitions) - { - Dominator< - ImmediateDominatorTest::Vertex, - ImmediateDominatorTest::ForEachVertexSuccessorTest - > dominatorFinder(*test->entry, test->numVertices); - - BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); - BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); - } + DominatorFinder dominatorFinder(*test->entry, test->numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); } BOOST_AUTO_TEST_SUITE_END() From 9aad3688dcad772d82fd97460fdb5fe2f35854fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 18:50:53 +0200 Subject: [PATCH 13/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- test/libyul/DominatorTest.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index 46c5ee312..a27da3a40 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -71,20 +71,20 @@ protected: { soltestAssert(_edges.size() > 0); - ImmediateDominatorTest* graph = new ImmediateDominatorTest(); - for (std::string v: _vertices) - graph->vertices.insert(make_pair(v, new Vertex{v, std::vector{}})); - graph->entry = graph->vertices[_vertices[0]]; + ImmediateDominatorTest* test = new ImmediateDominatorTest(); + for (std::string name: _vertices) + test->vertices.insert(make_pair(name, new Vertex{name, std::vector{}})); + test->entry = test->vertices[_vertices[0]]; - soltestAssert(_vertices.size() > 0 && _vertices.size() == graph->vertices.size()); + soltestAssert(_vertices.size() > 0 && _vertices.size() == test->vertices.size()); - graph->numVertices = _vertices.size(); + test->numVertices = _vertices.size(); for (auto const& [from, to]: _edges) - graph->vertices[from]->successors.push_back(graph->vertices[to]); + test->vertices[from]->successors.push_back(test->vertices[to]); - graph->expectedIdom = _expectedIdom; - graph->expectedDFSIndices = _expectedDFSIndices; - return graph; + test->expectedIdom = _expectedIdom; + test->expectedDFSIndices = _expectedDFSIndices; + return test; } std::map toDFSIndices(std::map const& _vertexIndices) From ffb53ad8a6d5d576946ddeffb400ec2c3ce36f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 18:55:01 +0200 Subject: [PATCH 14/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- libyul/backends/evm/Dominator.h | 6 +++--- test/libyul/DominatorTest.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libyul/backends/evm/Dominator.h b/libyul/backends/evm/Dominator.h index 7de1f1410..5603409dc 100644 --- a/libyul/backends/evm/Dominator.h +++ b/libyul/backends/evm/Dominator.h @@ -95,7 +95,7 @@ public: // @note for a vertex ``_v``, the _v’s inclusion in the set of dominators of ``_v`` is implicit. std::vector dominatorsOf(Vertex _v) { - solAssert(m_vertex.size() > 0); + solAssert(!m_vertex.empty()); // The entry node always dominates all other nodes std::vector dominators = std::vector{m_vertex[0]}; @@ -112,8 +112,8 @@ public: } void buildDominatorTree() { - solAssert(m_vertex.size() > 0); - solAssert(m_immediateDominator.size() > 0); + solAssert(!m_vertex.empty()); + solAssert(!m_immediateDominator.empty()); //Ignoring the entry node since no one dominates it. for (size_t i = 1; i < m_immediateDominator.size(); ++i) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index a27da3a40..943befb49 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -69,14 +69,14 @@ protected: std::map _expectedDFSIndices ) { - soltestAssert(_edges.size() > 0); + soltestAssert(!_edges.empty()); ImmediateDominatorTest* test = new ImmediateDominatorTest(); for (std::string name: _vertices) test->vertices.insert(make_pair(name, new Vertex{name, std::vector{}})); test->entry = test->vertices[_vertices[0]]; - soltestAssert(_vertices.size() > 0 && _vertices.size() == test->vertices.size()); + soltestAssert(!_vertices.empty() && _vertices.size() == test->vertices.size()); test->numVertices = _vertices.size(); for (auto const& [from, to]: _edges) From 56cabdc69aa858317789e3ca58bc30fd139bf903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 18:56:35 +0200 Subject: [PATCH 15/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- libyul/backends/evm/Dominator.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libyul/backends/evm/Dominator.h b/libyul/backends/evm/Dominator.h index 5603409dc..497117368 100644 --- a/libyul/backends/evm/Dominator.h +++ b/libyul/backends/evm/Dominator.h @@ -211,7 +211,7 @@ public: // Process the vertices in decreasing order of the dfs number for (auto it = m_vertex.rbegin(); it != m_vertex.rend(); ++it) { - auto w = m_vertexIndex[*it]; + Vertex const& w = m_vertexIndex[*it]; // step 3 // NOTE: this is an optimization, i.e. performing the step 3 before step 2. // The goal is to process the bucket in the beginning of the loop for the vertex ``w`` @@ -230,7 +230,7 @@ public: ); // step 2 - for (auto v: predecessors[w]) + for (size_t v: predecessors[w]) { size_t u = eval(v); if (semi[u] < semi[w]) From a9a09bea6df24a1afef1e30fb44090314fb373db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 18:58:20 +0200 Subject: [PATCH 16/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- libyul/backends/evm/Dominator.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libyul/backends/evm/Dominator.h b/libyul/backends/evm/Dominator.h index 497117368..dcbfd02ee 100644 --- a/libyul/backends/evm/Dominator.h +++ b/libyul/backends/evm/Dominator.h @@ -40,10 +40,10 @@ class Dominator { public: - Dominator(Vertex _entry, size_t _numVertices) + Dominator(Vertex _entry, size_t _numVertices): + m_vertex(_numVertices), + m_immediateDominator(lengauerTarjanDominator(_entry, _numVertices)) { - m_vertex = std::vector(_numVertices); - m_immediateDominator = lengauerTarjanDominator(_entry, _numVertices); buildDominatorTree(); } @@ -97,18 +97,18 @@ public: { solAssert(!m_vertex.empty()); // The entry node always dominates all other nodes - std::vector dominators = std::vector{m_vertex[0]}; + std::vector dominators{m_vertex[0]}; size_t idomIdx = m_immediateDominator[m_vertexIndex[_v]]; if (idomIdx == 0) - return std::move(dominators); + return dominators; while (idomIdx != 0) { dominators.emplace_back(m_vertex[idomIdx]); idomIdx = m_immediateDominator[idomIdx]; } - return std::move(dominators); + return dominators; } void buildDominatorTree() { From 37af76405a732724a917c4a17978adcc7511dd35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 19:01:25 +0200 Subject: [PATCH 17/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- libyul/backends/evm/Dominator.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libyul/backends/evm/Dominator.h b/libyul/backends/evm/Dominator.h index dcbfd02ee..b2b4683e1 100644 --- a/libyul/backends/evm/Dominator.h +++ b/libyul/backends/evm/Dominator.h @@ -111,7 +111,8 @@ public: return dominators; } - void buildDominatorTree() { + void buildDominatorTree() + { solAssert(!m_vertex.empty()); solAssert(!m_immediateDominator.empty()); From 1e2069bdfc328f4f4041934290c0056a53fecc49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 17:56:43 +0200 Subject: [PATCH 18/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- libyul/backends/evm/Dominator.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libyul/backends/evm/Dominator.h b/libyul/backends/evm/Dominator.h index b2b4683e1..9a47b903e 100644 --- a/libyul/backends/evm/Dominator.h +++ b/libyul/backends/evm/Dominator.h @@ -47,22 +47,22 @@ public: buildDominatorTree(); } - std::vector vertices() const + std::vector const& vertices() const { return m_vertex; } - std::map vertexIndices() const + std::map const& vertexIndices() const { return m_vertexIndex; } - std::vector immediateDominators() const + std::vector const& immediateDominators() const { return m_immediateDominator; } - std::map> dominatorTree() const + std::map> const& dominatorTree() const { return m_dominatorTree; } From f804e8bc004244a07facaeaffbc644729c7a2bbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 19:10:19 +0200 Subject: [PATCH 19/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- libyul/backends/evm/Dominator.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libyul/backends/evm/Dominator.h b/libyul/backends/evm/Dominator.h index 9a47b903e..a594c65a4 100644 --- a/libyul/backends/evm/Dominator.h +++ b/libyul/backends/evm/Dominator.h @@ -40,7 +40,7 @@ class Dominator { public: - Dominator(Vertex _entry, size_t _numVertices): + Dominator(Vertex const& _entry, size_t _numVertices): m_vertex(_numVertices), m_immediateDominator(lengauerTarjanDominator(_entry, _numVertices)) { @@ -71,7 +71,7 @@ public: // through the path from ``_b`` to the entry node. // If ``_a`` is found, then it dominates ``_b`` // otherwise it doesn't. - bool dominates(Vertex _a, Vertex _b) + bool dominates(Vertex const& _a, Vertex const& _b) { size_t aIdx = m_vertexIndex[_a]; size_t bIdx = m_vertexIndex[_b]; @@ -93,7 +93,7 @@ public: // Find all dominators of a node _v // @note for a vertex ``_v``, the _v’s inclusion in the set of dominators of ``_v`` is implicit. - std::vector dominatorsOf(Vertex _v) + std::vector dominatorsOf(Vertex const& _v) { solAssert(!m_vertex.empty()); // The entry node always dominates all other nodes @@ -141,7 +141,7 @@ public: } } - std::vector lengauerTarjanDominator(Vertex _entry, size_t numVertices) + std::vector lengauerTarjanDominator(Vertex const& _entry, size_t numVertices) { solAssert(numVertices > 0); // semi(w): The dfs index of the semidominator of ``w``. @@ -189,7 +189,7 @@ public: // The number of vertices reached during the dfs. // The vertices are indexed based on this number. size_t dfIdx = 0; - auto dfs = [&](Vertex _v, auto _dfs) -> void { + auto dfs = [&](Vertex const& _v, auto _dfs) -> void { if (visited.count(_v)) return; visited.insert(_v); @@ -198,7 +198,7 @@ public: semi[dfIdx] = dfIdx; label[dfIdx] = dfIdx; dfIdx++; - ForEachSuccessor{}(_v, [&](Vertex w) { + ForEachSuccessor{}(_v, [&](Vertex const& w) { if (semi[dfIdx] == std::numeric_limits::max()) { parent[dfIdx] = m_vertexIndex[_v]; From e4bac1340d3654ed75e47cafca23fe92b6e91543 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 19:24:12 +0200 Subject: [PATCH 20/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- libyul/backends/evm/Dominator.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libyul/backends/evm/Dominator.h b/libyul/backends/evm/Dominator.h index a594c65a4..df46043ba 100644 --- a/libyul/backends/evm/Dominator.h +++ b/libyul/backends/evm/Dominator.h @@ -27,10 +27,10 @@ #include #include -#include -#include -#include #include +#include +#include +#include namespace solidity::yul { From b7ec9d3fddc82a256b508468a81d93f0e787d2da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 19:51:19 +0200 Subject: [PATCH 21/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- libyul/backends/evm/Dominator.h | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/libyul/backends/evm/Dominator.h b/libyul/backends/evm/Dominator.h index df46043ba..1737f2cbb 100644 --- a/libyul/backends/evm/Dominator.h +++ b/libyul/backends/evm/Dominator.h @@ -27,6 +27,11 @@ #include #include +#include +#include +#include +#include + #include #include #include @@ -117,8 +122,8 @@ public: solAssert(!m_immediateDominator.empty()); //Ignoring the entry node since no one dominates it. - for (size_t i = 1; i < m_immediateDominator.size(); ++i) - m_dominatorTree[m_immediateDominator[i]].emplace_back(i); + for (size_t idomIdx: m_immediateDominator | ranges::views::drop(1)) + m_dominatorTree[idomIdx].emplace_back(idomIdx); } // Path compression updates the ancestors of vertices along @@ -177,6 +182,8 @@ public: return _v; }; + auto toIdx = [&](Vertex const& v) { return m_vertexIndex[v]; }; + // step 1 std::set visited; // predecessors(w): The set of vertices ``v`` such that (``v``, ``w``) is an edge of the graph. @@ -210,9 +217,8 @@ public: dfs(_entry, dfs); // Process the vertices in decreasing order of the dfs number - for (auto it = m_vertex.rbegin(); it != m_vertex.rend(); ++it) + for (size_t w: m_vertex | ranges::views::reverse | ranges::views::transform(toIdx)) { - Vertex const& w = m_vertexIndex[*it]; // step 3 // NOTE: this is an optimization, i.e. performing the step 3 before step 2. // The goal is to process the bucket in the beginning of the loop for the vertex ``w`` @@ -220,9 +226,8 @@ public: // Inverting those steps ensures that a bucket is only processed once and // it does not need to be erased. // The optimization proposal is available here: https://jgaa.info/accepted/2006/GeorgiadisTarjanWerneck2006.10.1.pdf pg.77 - for_each( - bucket[w].begin(), - bucket[w].end(), + ranges::for_each( + bucket[w], [&](size_t v) { size_t u = eval(v); @@ -243,12 +248,10 @@ public: // step 4 idom[0] = 0; - for (auto it = m_vertex.begin() + 1; it != m_vertex.end(); ++it) - { - size_t w = m_vertexIndex[*it]; + for (size_t w: m_vertex | ranges::views::drop(1) | ranges::views::transform(toIdx)) if (idom[w] != semi[w]) idom[w] = idom[idom[w]]; - } + return idom; } private: From 88f70738575997c5b43f8608af1b18ff81460b78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 20:32:57 +0200 Subject: [PATCH 22/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- test/libyul/DominatorTest.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index 943befb49..97e3569d9 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -133,7 +133,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator_1, DominatorFixture) Edge("D", "E"), Edge("E", "F"), Edge("G", "H"), - Edge("H", "F") + Edge("H", "F"), }, {0, 0, 1, 1, 3, 1, 2, 6}, { @@ -144,7 +144,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator_1, DominatorFixture) {"E", 4}, {"F", 5}, {"G", 6}, - {"H", 7} + {"H", 7}, } ); DominatorFinder dominatorFinder(*test->entry, test->numVertices); @@ -174,7 +174,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator_2, DominatorFixture) Edge("D", "F"), Edge("E", "G"), Edge("F", "G"), - Edge("G", "C") + Edge("G", "C"), }, {0, 0, 0, 0, 0, 4, 4}, { @@ -184,7 +184,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator_2, DominatorFixture) {"G", 3}, {"D", 4}, {"E", 5}, - {"F", 6} + {"F", 6}, } ); DominatorFinder dominatorFinder(*test->entry, test->numVertices); @@ -234,7 +234,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator_3, DominatorFixture) Edge("G", "D"), Edge("H", "G"), Edge("I", "E"), - Edge("I", "H") + Edge("I", "H"), }, {0, 0, 0, 0, 1, 1, 1, 1, 5}, { @@ -246,7 +246,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator_3, DominatorFixture) {"E", 5}, {"H", 6}, {"G", 7}, - {"F", 8} + {"F", 8}, } ); DominatorFinder dominatorFinder(*test->entry, test->numVertices); @@ -297,7 +297,7 @@ BOOST_FIXTURE_TEST_CASE(langauer_tarjan_p122_fig1, DominatorFixture) {"C", 9}, {"F", 10}, {"G", 11}, - {"J", 12} + {"J", 12}, } ); DominatorFinder dominatorFinder(*test->entry, test->numVertices); @@ -328,7 +328,7 @@ BOOST_FIXTURE_TEST_CASE(loukas_georgiadis, DominatorFixture) Edge("X5", "X6"), Edge("X6", "X5"), Edge("X6", "X7"), - Edge("X7", "X6") + Edge("X7", "X6"), }, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { @@ -341,7 +341,7 @@ BOOST_FIXTURE_TEST_CASE(loukas_georgiadis, DominatorFixture) {"X5", 6}, {"X6", 7}, {"X7", 8}, - {"Y", 9} + {"Y", 9}, } ); DominatorFinder dominatorFinder(*test->entry, test->numVertices); @@ -380,7 +380,7 @@ BOOST_FIXTURE_TEST_CASE(itworst, DominatorFixture) Edge("Z1", "Z2"), Edge("Z2", "Z1"), Edge("Z2", "Z3"), - Edge("Z3", "Z2") + Edge("Z3", "Z2"), }, {0, 0, 0, 0, 0, 4, 5, 6, 7, 8, 0, 0, 0}, { @@ -396,7 +396,7 @@ BOOST_FIXTURE_TEST_CASE(itworst, DominatorFixture) {"Y3", 9}, {"Z1", 10}, {"Z2", 11}, - {"Z3", 12} + {"Z3", 12}, } ); DominatorFinder dominatorFinder(*test->entry, test->numVertices); @@ -426,7 +426,7 @@ BOOST_FIXTURE_TEST_CASE(idfsquad, DominatorFixture) Edge("Y2", "Z3"), Edge("Z2", "Y2"), Edge("Y3", "Z3"), - Edge("Z3", "Y3") + Edge("Z3", "Y3"), }, {0, 0, 0, 0, 0, 0, 0, 0, 1, 8}, { @@ -439,7 +439,7 @@ BOOST_FIXTURE_TEST_CASE(idfsquad, DominatorFixture) {"Z3", 6}, {"Y3", 7}, {"X2", 8}, - {"X3", 9} + {"X3", 9}, } ); DominatorFinder dominatorFinder(*test->entry, test->numVertices); @@ -463,7 +463,7 @@ BOOST_FIXTURE_TEST_CASE(ibsfquad, DominatorFixture) Edge("Y", "Z"), Edge("Z", "X3"), Edge("X3", "X2"), - Edge("X2", "X1") + Edge("X2", "X1"), }, {0, 0, 0, 0, 0, 0, 5}, { @@ -473,7 +473,7 @@ BOOST_FIXTURE_TEST_CASE(ibsfquad, DominatorFixture) {"X2", 3}, {"X3", 4}, {"Y", 5}, - {"Z", 6} + {"Z", 6}, } ); DominatorFinder dominatorFinder(*test->entry, test->numVertices); @@ -497,7 +497,7 @@ BOOST_FIXTURE_TEST_CASE(sncaworst, DominatorFixture) Edge("X2", "X3"), Edge("X3", "Y1"), Edge("X3", "Y2"), - Edge("X3", "Y3") + Edge("X3", "Y3"), }, {0, 0, 1, 2, 0, 0, 0}, { From 48edc744f10bd96b3ec853782f306a14ea936250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 11 Aug 2023 20:34:41 +0200 Subject: [PATCH 23/28] fixup! Implementation of Lengauer-Tarjan algorithm to find dominators --- test/libyul/DominatorTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index 97e3569d9..707cd59f4 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -52,7 +52,7 @@ struct ImmediateDominatorTest }; size_t numVertices; - Vertex* entry; + Vertex const* entry; std::map vertices; std::vector expectedIdom; std::map expectedDFSIndices; From 5e68617a2e52cb3ec86d78fa9c24f6697fe51dd8 Mon Sep 17 00:00:00 2001 From: r0qs Date: Tue, 22 Aug 2023 16:26:47 +0200 Subject: [PATCH 24/28] Use smart pointers --- test/libyul/DominatorTest.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index 707cd59f4..d79d557f9 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -32,7 +32,7 @@ struct ImmediateDominatorTest { struct Vertex { std::string name; - std::vector successors; + std::vector> successors; bool operator<(Vertex const& _other) const { @@ -52,8 +52,8 @@ struct ImmediateDominatorTest }; size_t numVertices; - Vertex const* entry; - std::map vertices; + std::shared_ptr entry; + std::map> vertices; std::vector expectedIdom; std::map expectedDFSIndices; }; @@ -62,7 +62,7 @@ class DominatorFixture { typedef ImmediateDominatorTest::Vertex Vertex; protected: - static ImmediateDominatorTest const* prepareTestDefinition( + static std::shared_ptr prepareTestDefinition( std::vector _vertices, std::vector _edges, std::vector _expectedIdom, @@ -71,9 +71,9 @@ protected: { soltestAssert(!_edges.empty()); - ImmediateDominatorTest* test = new ImmediateDominatorTest(); + std::shared_ptr test(new ImmediateDominatorTest()); for (std::string name: _vertices) - test->vertices.insert(make_pair(name, new Vertex{name, std::vector{}})); + test->vertices.insert(make_pair(name, std::make_shared(Vertex{name, std::vector>{}}))); test->entry = test->vertices[_vertices[0]]; soltestAssert(!_vertices.empty() && _vertices.size() == test->vertices.size()); @@ -122,7 +122,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator_1, DominatorFixture) // E H // │ │ // └──►F◄──┘ - ImmediateDominatorTest const* test = prepareTestDefinition( + std::shared_ptr test = prepareTestDefinition( {"A", "B", "C", "D", "E", "F", "G", "H"}, { Edge("A", "B"), @@ -162,7 +162,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator_2, DominatorFixture) // └─C◄───┐ E F // │ │ │ │ // └───►G◄─┴─────┘ - ImmediateDominatorTest const* test = prepareTestDefinition( + std::shared_ptr test = prepareTestDefinition( {"A", "B", "C", "D", "E", "F", "G"}, { Edge("A", "B"), @@ -215,7 +215,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator_3, DominatorFixture) // │ └─────┴─G◄─┴──────┘ // │ │ // └─────────────┘ - ImmediateDominatorTest const* test = prepareTestDefinition( + std::shared_ptr test = prepareTestDefinition( {"A", "B", "C", "D", "E", "F", "G", "H", "I"}, { Edge("A", "B"), @@ -258,7 +258,7 @@ BOOST_FIXTURE_TEST_CASE(langauer_tarjan_p122_fig1, DominatorFixture) { // T. Lengauer and R. E. Tarjan pg. 122 fig. 1 // ref: https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf - ImmediateDominatorTest const* test = prepareTestDefinition( + std::shared_ptr test = prepareTestDefinition( {"R", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "L", "K"}, { Edge("R", "B"), @@ -310,7 +310,7 @@ BOOST_FIXTURE_TEST_CASE(loukas_georgiadis, DominatorFixture) // Extracted from Loukas Georgiadis Dissertation - Linear-Time Algorithms for Dominators and Related Problems // pg. 12 Fig. 2.2 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - ImmediateDominatorTest const* test = prepareTestDefinition( + std::shared_ptr test = prepareTestDefinition( {"R", "W", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "Y"}, { Edge("R", "W"), @@ -354,7 +354,7 @@ BOOST_FIXTURE_TEST_CASE(itworst, DominatorFixture) // Worst-case families for k = 3 // Example itworst(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - ImmediateDominatorTest const* test = prepareTestDefinition( + std::shared_ptr test = prepareTestDefinition( {"R", "W1", "W2", "W3", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3"}, { Edge("R", "W1"), @@ -409,7 +409,7 @@ BOOST_FIXTURE_TEST_CASE(idfsquad, DominatorFixture) // Worst-case families for k = 3 // Example idfsquad(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - ImmediateDominatorTest const* test = prepareTestDefinition( + std::shared_ptr test = prepareTestDefinition( {"R", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3"}, { Edge("R", "X1"), @@ -452,7 +452,7 @@ BOOST_FIXTURE_TEST_CASE(ibsfquad, DominatorFixture) // Worst-case families for k = 3 // Example ibfsquad(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - ImmediateDominatorTest const* test = prepareTestDefinition( + std::shared_ptr test = prepareTestDefinition( {"R", "W", "X1", "X2", "X3", "Y", "Z"}, { Edge("R", "W"), @@ -486,7 +486,7 @@ BOOST_FIXTURE_TEST_CASE(sncaworst, DominatorFixture) // Worst-case families for k = 3 // Example sncaworst(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - ImmediateDominatorTest const* test = prepareTestDefinition( + std::shared_ptr test = prepareTestDefinition( {"R", "X1", "X2", "X3", "Y1", "Y2", "Y3"}, { Edge("R", "X1"), From 2ab40e3fb31240431bc1d8e11a686b0475425352 Mon Sep 17 00:00:00 2001 From: r0qs Date: Tue, 22 Aug 2023 16:43:59 +0200 Subject: [PATCH 25/28] Move type definitions to test namespace --- test/libyul/DominatorTest.cpp | 51 ++++++++++++++++------------------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index d79d557f9..594b77de1 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -28,29 +28,29 @@ using namespace solidity::yul; namespace solidity::yul::test { +typedef std::pair Edge; + +struct Vertex { + std::string name; + std::vector> successors; + + bool operator<(Vertex const& _other) const + { + return name < _other.name; + } +}; + +struct ForEachVertexSuccessorTest { + template + void operator()(Vertex _v, Callable&& _callable) const + { + for (auto const& w: _v.successors) + _callable(*w); + } +}; + struct ImmediateDominatorTest { - struct Vertex { - std::string name; - std::vector> successors; - - bool operator<(Vertex const& _other) const - { - return name < _other.name; - } - }; - - typedef std::pair Edge; - - struct ForEachVertexSuccessorTest { - template - void operator()(Vertex _v, Callable&& _callable) const - { - for (auto const& w: _v.successors) - _callable(*w); - } - }; - size_t numVertices; std::shared_ptr entry; std::map> vertices; @@ -60,11 +60,10 @@ struct ImmediateDominatorTest class DominatorFixture { - typedef ImmediateDominatorTest::Vertex Vertex; protected: static std::shared_ptr prepareTestDefinition( std::vector _vertices, - std::vector _edges, + std::vector _edges, std::vector _expectedIdom, std::map _expectedDFSIndices ) @@ -97,11 +96,7 @@ protected: } }; -typedef ImmediateDominatorTest::Edge Edge; -typedef Dominator< - ImmediateDominatorTest::Vertex, - ImmediateDominatorTest::ForEachVertexSuccessorTest -> DominatorFinder; +typedef Dominator DominatorFinder; BOOST_AUTO_TEST_SUITE(Dominators) From 701b96cfa79e33c3d293c273964c2675ab3b6f31 Mon Sep 17 00:00:00 2001 From: r0qs Date: Tue, 22 Aug 2023 17:56:47 +0200 Subject: [PATCH 26/28] Add constructor to ImmediateDominatorTest --- test/libyul/DominatorTest.cpp | 124 +++++++++++++++++----------------- 1 file changed, 61 insertions(+), 63 deletions(-) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index 594b77de1..542037939 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -51,8 +51,31 @@ struct ForEachVertexSuccessorTest { struct ImmediateDominatorTest { - size_t numVertices; - std::shared_ptr entry; + ImmediateDominatorTest( + std::vector _vertices, + std::vector _edges, + std::vector _expectedIdom, + std::map _expectedDFSIndices + ) + { + soltestAssert(!_vertices.empty() && !_edges.empty()); + + for (std::string name: _vertices) + vertices.insert(make_pair(name, std::make_shared(Vertex{name, std::vector>{}}))); + + soltestAssert(vertices.size() == _vertices.size()); + + for (auto const& [from, to]: _edges) + vertices[from]->successors.push_back(vertices[to]); + + entry = vertices[_vertices[0]]; + numVertices = _vertices.size(); + expectedIdom = _expectedIdom; + expectedDFSIndices = _expectedDFSIndices; + } + + size_t numVertices = 0; + std::shared_ptr entry = nullptr; std::map> vertices; std::vector expectedIdom; std::map expectedDFSIndices; @@ -61,31 +84,6 @@ struct ImmediateDominatorTest class DominatorFixture { protected: - static std::shared_ptr prepareTestDefinition( - std::vector _vertices, - std::vector _edges, - std::vector _expectedIdom, - std::map _expectedDFSIndices - ) - { - soltestAssert(!_edges.empty()); - - std::shared_ptr test(new ImmediateDominatorTest()); - for (std::string name: _vertices) - test->vertices.insert(make_pair(name, std::make_shared(Vertex{name, std::vector>{}}))); - test->entry = test->vertices[_vertices[0]]; - - soltestAssert(!_vertices.empty() && _vertices.size() == test->vertices.size()); - - test->numVertices = _vertices.size(); - for (auto const& [from, to]: _edges) - test->vertices[from]->successors.push_back(test->vertices[to]); - - test->expectedIdom = _expectedIdom; - test->expectedDFSIndices = _expectedDFSIndices; - return test; - } - std::map toDFSIndices(std::map const& _vertexIndices) { auto convertIndex = [](std::pair const& _pair) -> std::pair @@ -117,7 +115,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator_1, DominatorFixture) // E H // │ │ // └──►F◄──┘ - std::shared_ptr test = prepareTestDefinition( + ImmediateDominatorTest test( {"A", "B", "C", "D", "E", "F", "G", "H"}, { Edge("A", "B"), @@ -142,9 +140,9 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator_1, DominatorFixture) {"H", 7}, } ); - DominatorFinder dominatorFinder(*test->entry, test->numVertices); - BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); - BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); + DominatorFinder dominatorFinder(*test.entry, test.numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test.expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test.expectedIdom); } BOOST_FIXTURE_TEST_CASE(immediate_dominator_2, DominatorFixture) @@ -157,7 +155,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator_2, DominatorFixture) // └─C◄───┐ E F // │ │ │ │ // └───►G◄─┴─────┘ - std::shared_ptr test = prepareTestDefinition( + ImmediateDominatorTest test( {"A", "B", "C", "D", "E", "F", "G"}, { Edge("A", "B"), @@ -182,9 +180,9 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator_2, DominatorFixture) {"F", 6}, } ); - DominatorFinder dominatorFinder(*test->entry, test->numVertices); - BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); - BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); + DominatorFinder dominatorFinder(*test.entry, test.numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test.expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test.expectedIdom); } BOOST_FIXTURE_TEST_CASE(immediate_dominator_3, DominatorFixture) @@ -210,7 +208,7 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator_3, DominatorFixture) // │ └─────┴─G◄─┴──────┘ // │ │ // └─────────────┘ - std::shared_ptr test = prepareTestDefinition( + ImmediateDominatorTest test( {"A", "B", "C", "D", "E", "F", "G", "H", "I"}, { Edge("A", "B"), @@ -244,16 +242,16 @@ BOOST_FIXTURE_TEST_CASE(immediate_dominator_3, DominatorFixture) {"F", 8}, } ); - DominatorFinder dominatorFinder(*test->entry, test->numVertices); - BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); - BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); + DominatorFinder dominatorFinder(*test.entry, test.numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test.expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test.expectedIdom); } BOOST_FIXTURE_TEST_CASE(langauer_tarjan_p122_fig1, DominatorFixture) { // T. Lengauer and R. E. Tarjan pg. 122 fig. 1 // ref: https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf - std::shared_ptr test = prepareTestDefinition( + ImmediateDominatorTest test( {"R", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "L", "K"}, { Edge("R", "B"), @@ -295,9 +293,9 @@ BOOST_FIXTURE_TEST_CASE(langauer_tarjan_p122_fig1, DominatorFixture) {"J", 12}, } ); - DominatorFinder dominatorFinder(*test->entry, test->numVertices); - BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); - BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); + DominatorFinder dominatorFinder(*test.entry, test.numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test.expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test.expectedIdom); } BOOST_FIXTURE_TEST_CASE(loukas_georgiadis, DominatorFixture) @@ -305,7 +303,7 @@ BOOST_FIXTURE_TEST_CASE(loukas_georgiadis, DominatorFixture) // Extracted from Loukas Georgiadis Dissertation - Linear-Time Algorithms for Dominators and Related Problems // pg. 12 Fig. 2.2 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - std::shared_ptr test = prepareTestDefinition( + ImmediateDominatorTest test( {"R", "W", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "Y"}, { Edge("R", "W"), @@ -339,9 +337,9 @@ BOOST_FIXTURE_TEST_CASE(loukas_georgiadis, DominatorFixture) {"Y", 9}, } ); - DominatorFinder dominatorFinder(*test->entry, test->numVertices); - BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); - BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); + DominatorFinder dominatorFinder(*test.entry, test.numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test.expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test.expectedIdom); } BOOST_FIXTURE_TEST_CASE(itworst, DominatorFixture) @@ -349,7 +347,7 @@ BOOST_FIXTURE_TEST_CASE(itworst, DominatorFixture) // Worst-case families for k = 3 // Example itworst(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - std::shared_ptr test = prepareTestDefinition( + ImmediateDominatorTest test( {"R", "W1", "W2", "W3", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3"}, { Edge("R", "W1"), @@ -394,9 +392,9 @@ BOOST_FIXTURE_TEST_CASE(itworst, DominatorFixture) {"Z3", 12}, } ); - DominatorFinder dominatorFinder(*test->entry, test->numVertices); - BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); - BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); + DominatorFinder dominatorFinder(*test.entry, test.numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test.expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test.expectedIdom); } BOOST_FIXTURE_TEST_CASE(idfsquad, DominatorFixture) @@ -404,7 +402,7 @@ BOOST_FIXTURE_TEST_CASE(idfsquad, DominatorFixture) // Worst-case families for k = 3 // Example idfsquad(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - std::shared_ptr test = prepareTestDefinition( + ImmediateDominatorTest test( {"R", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3"}, { Edge("R", "X1"), @@ -437,9 +435,9 @@ BOOST_FIXTURE_TEST_CASE(idfsquad, DominatorFixture) {"X3", 9}, } ); - DominatorFinder dominatorFinder(*test->entry, test->numVertices); - BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); - BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); + DominatorFinder dominatorFinder(*test.entry, test.numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test.expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test.expectedIdom); } BOOST_FIXTURE_TEST_CASE(ibsfquad, DominatorFixture) @@ -447,7 +445,7 @@ BOOST_FIXTURE_TEST_CASE(ibsfquad, DominatorFixture) // Worst-case families for k = 3 // Example ibfsquad(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - std::shared_ptr test = prepareTestDefinition( + ImmediateDominatorTest test( {"R", "W", "X1", "X2", "X3", "Y", "Z"}, { Edge("R", "W"), @@ -471,9 +469,9 @@ BOOST_FIXTURE_TEST_CASE(ibsfquad, DominatorFixture) {"Z", 6}, } ); - DominatorFinder dominatorFinder(*test->entry, test->numVertices); - BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); - BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); + DominatorFinder dominatorFinder(*test.entry, test.numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test.expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test.expectedIdom); } BOOST_FIXTURE_TEST_CASE(sncaworst, DominatorFixture) @@ -481,7 +479,7 @@ BOOST_FIXTURE_TEST_CASE(sncaworst, DominatorFixture) // Worst-case families for k = 3 // Example sncaworst(3) pg. 26 fig. 2.9 // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf - std::shared_ptr test = prepareTestDefinition( + ImmediateDominatorTest test( {"R", "X1", "X2", "X3", "Y1", "Y2", "Y3"}, { Edge("R", "X1"), @@ -505,9 +503,9 @@ BOOST_FIXTURE_TEST_CASE(sncaworst, DominatorFixture) {"Y3", 6}, } ); - DominatorFinder dominatorFinder(*test->entry, test->numVertices); - BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test->expectedDFSIndices); - BOOST_TEST(dominatorFinder.immediateDominators() == test->expectedIdom); + DominatorFinder dominatorFinder(*test.entry, test.numVertices); + BOOST_TEST(toDFSIndices(dominatorFinder.vertexIndices()) == test.expectedDFSIndices); + BOOST_TEST(dominatorFinder.immediateDominators() == test.expectedIdom); } BOOST_AUTO_TEST_SUITE_END() From e1f049fd24a003b4e0e9a3a40e703188c12c8a2a Mon Sep 17 00:00:00 2001 From: r0qs Date: Tue, 5 Sep 2023 13:33:59 +0200 Subject: [PATCH 27/28] Minor fix for OSX build --- test/libyul/DominatorTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/libyul/DominatorTest.cpp b/test/libyul/DominatorTest.cpp index 542037939..9c9bfe86f 100644 --- a/test/libyul/DominatorTest.cpp +++ b/test/libyul/DominatorTest.cpp @@ -90,7 +90,7 @@ protected: { return {_pair.first.name, _pair.second}; }; - return _vertexIndices | ranges::views::transform(convertIndex) | ranges::to; + return _vertexIndices | ranges::views::transform(convertIndex) | ranges::to>; } }; From 3c1f4525a48851f31160775dc3366b19f7cc914e Mon Sep 17 00:00:00 2001 From: r0qs Date: Fri, 22 Sep 2023 14:45:41 +0200 Subject: [PATCH 28/28] Apply suggestions --- libyul/backends/evm/Dominator.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libyul/backends/evm/Dominator.h b/libyul/backends/evm/Dominator.h index 1737f2cbb..936147b4d 100644 --- a/libyul/backends/evm/Dominator.h +++ b/libyul/backends/evm/Dominator.h @@ -91,9 +91,10 @@ public: return true; idomIdx = m_immediateDominator[idomIdx]; } - // Now that we reach the entry node (i.e. idx = 0), - // either ``aIdx == 0`` or it does not dominates other node. - return idomIdx == aIdx; + // Now that we reach the entry node (i.e. idomIdx = 0), + // either ``aIdx == 0`` or it does not dominates the other node. + solAssert(idomIdx == 0, ""); + return aIdx == 0; } // Find all dominators of a node _v