summaryrefslogtreecommitdiff
path: root/src/SDCCtree_dec.hpp
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/SDCCtree_dec.hpp
downloadsdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'src/SDCCtree_dec.hpp')
-rw-r--r--src/SDCCtree_dec.hpp648
1 files changed, 648 insertions, 0 deletions
diff --git a/src/SDCCtree_dec.hpp b/src/SDCCtree_dec.hpp
new file mode 100644
index 0000000..7870396
--- /dev/null
+++ b/src/SDCCtree_dec.hpp
@@ -0,0 +1,648 @@
+// Philipp Klaus Krause, philipp@informatik.uni-frankfurt.de, pkk@spth.de, 2010 - 2011
+//
+// (c) 2010-2011 Goethe-Universität Frankfurt
+//
+// This program 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 2, or (at your option) any
+// later version.
+//
+// This program 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 this program; if not, write to the Free Software
+// Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+//
+// Some routines for tree-decompositions.
+//
+// A tree decomposition is a graph that has a set of vertex indices as bundled property, e.g.:
+//
+// struct tree_dec_node
+// {
+// std::set<unsigned int> bag;
+// };
+// typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, tree_dec_node> tree_dec_t;
+//
+// The following are the routines that are most likely to be interesting for outside use:
+//
+// void nicify(T_t &T)
+// Transforms a tree decomposition T into a nice tree decomposition
+//
+// void thorup_tree_decomposition(T_t &tree_decomposition, const G_t &cfg)
+// Creates a tree decomposition T from a graph cfg using Thorup's heuristic.
+//
+// void tree_decomposition_from_elimination_ordering(T_t &T, std::list<unsigned int>& l, const G_t &G)
+// Creates a tree decomposition T of a graph G from an elimination ordering l.
+//
+// void thorup_elimination_ordering(l_t &l, const J_t &J)
+// Creates an elimination ordering l of a graph J using Thorup's heuristic.
+//
+
+#include <map>
+#include <vector>
+#include <set>
+#include <stack>
+#include <list>
+
+#include <boost/tuple/tuple_io.hpp>
+#include <boost/graph/graph_traits.hpp>
+#include <boost/graph/graph_utility.hpp>
+#include <boost/graph/properties.hpp>
+#include <boost/graph/copy.hpp>
+#include <boost/graph/adjacency_list.hpp>
+
+#undef RANGE
+#undef BLOCK
+
+struct forget_properties
+{
+ template<class T1, class T2>
+ void operator()(const T1&, const T2&) const
+ {
+ }
+};
+
+// Thorup algorithm D.
+// The use of the multimap makes the complexity of this O(|I|log|I|), which could be reduced to O(|I|).
+template <class l_t>
+void thorup_D(l_t &l, const std::multimap<unsigned int, unsigned int> &MJ, const std::multimap<unsigned int, unsigned int> &MS, const unsigned int n)
+{
+ std::map<unsigned int, unsigned int> m;
+
+ l.clear();
+
+ unsigned int i = 0;
+ for (unsigned int j = n; j > 0;)
+ {
+ j--;
+ if (m.find(j) == m.end())
+ m[j] = i++;
+
+ std::multimap<unsigned int, unsigned int>::const_iterator k, k_end;
+
+ for (boost::tie(k, k_end) = MS.equal_range(j); k != k_end; ++k)
+ if (m.find(k->second) == m.end())
+ m[k->second] = i++;
+
+ for (boost::tie(k, k_end) = MJ.equal_range(j); k != k_end; ++k)
+ if (m.find(k->second) == m.end())
+ m[k->second] = i++;
+ }
+
+ std::vector<unsigned int> v(n);
+
+ std::map<unsigned int, unsigned int>::iterator mi;
+
+ for (mi = m.begin(); mi != m.end(); ++mi)
+ v[mi->second] = mi->first;
+
+ for (i = 0; i < n; i++)
+ l.push_back(v[i]);
+}
+
+// Thorup algorithm E.
+// The use of the multimap makes the complexity of this O(|I|log|I|), which could be reduced to O(|I|).
+template <class I_t>
+void thorup_E(std::multimap<unsigned int, unsigned int> &M, const I_t &I)
+{
+ typedef typename boost::graph_traits<I_t>::adjacency_iterator adjacency_iter_t;
+ typedef typename boost::property_map<I_t, boost::vertex_index_t>::type index_map;
+ index_map index = boost::get(boost::vertex_index, I);
+
+ std::stack<std::pair<int, unsigned int> > s;
+
+ M.clear();
+
+ s.push(std::pair<int, unsigned int>(-1, boost::num_vertices(I)));
+
+ for (unsigned int i = 0; i < boost::num_vertices(I); i++)
+ {
+ unsigned int j = i;
+ adjacency_iter_t j_curr, j_end;
+
+ for (boost::tie(j_curr, j_end) = boost::adjacent_vertices(i, I); j_curr != j_end; ++j_curr)
+ if (index[*j_curr] > j)
+ j = index[*j_curr];
+
+ if (j == i)
+ continue;
+
+ while (s.top().second <= i)
+ {
+ M.insert(std::pair<unsigned int, unsigned int>(s.top().second, s.top().first));
+ s.pop();
+ }
+
+ unsigned int i2 = i;
+ while (j >= s.top().second && s.top().second > i2)
+ {
+ i2 = s.top().first;
+ s.pop();
+ }
+
+ s.push(std::pair<int, unsigned int>(i2, j));
+ }
+
+ // Thorup forgot this in his paper. Without it, some maximal chains are omitted.
+ while(s.size() > 1)
+ {
+ M.insert(std::pair<unsigned int, unsigned int>(s.top().second, s.top().first));
+ s.pop();
+ }
+}
+
+// Heuristically give an elimination ordering for a directed graph.
+// For a description of this, including algorithms D and E, see
+// Mikkel Thorup, "All Structured Programs have Small Tree-Width and Good Register Allocation", Appendix A.
+// The use of the multimap makes the complexity of this O(|I|log|I|), could be reduced to O(|I|).
+template <class l_t, class G_t>
+void thorup_elimination_ordering(l_t &l, const G_t &G)
+{
+ // Remove edges to immediately following instruction. By "each statement can have at most obne jump" in the last paragraph of Appendix A it is clear that Thorup does not consider the implicit next-instruction-edges as jumps.
+ boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS> J;
+ boost::copy_graph(G, J, boost::vertex_copy(forget_properties()).edge_copy(forget_properties()));
+ for (unsigned int i = 0; i < boost::num_vertices(J) - 1; i++)
+ remove_edge(i, i + 1, J);
+
+ // Todo: Implement a graph adaptor for boost that allows to treat directed graphs as undirected graphs.
+ boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> S;
+ boost::copy_graph(J, S);
+
+ std::multimap<unsigned int, unsigned int> MJ, MS;
+
+ thorup_E(MJ, J);
+
+ thorup_E(MS, S);
+
+ thorup_D(l, MJ, MS, num_vertices(J));
+}
+
+// Finds a (the newest) bag that contains all vertices in X in the tree decomposition T.
+template <class X_t, class T_t>
+typename boost::graph_traits<T_t>::vertex_iterator find_bag(const X_t &X, const T_t &T)
+{
+ typedef typename boost::graph_traits<T_t>::vertex_iterator T_vertex_iter_t;
+ typedef typename X_t::const_iterator vertex_index_iter_t;
+
+ T_vertex_iter_t t, t_end, t_found;
+ vertex_index_iter_t v;
+
+ for (boost::tie(t, t_end) = vertices(T), t_found = t_end; t != t_end; ++t)
+ {
+ for (v = X.begin(); v != X.end(); ++v)
+ if (T[*t].bag.find(*v) == T[*t].bag.end())
+ break;
+
+ if (v == X.end())
+ t_found = t;
+ }
+
+ if (t_found == t_end) // Todo: Better error handling (throw exception?)
+ {
+ std::cerr << "find_bag() failed.\n";
+ std::cerr.flush();
+ }
+
+ return(t_found);
+}
+
+// Add edges to make the vertices in X a clique in G.
+template <class X_t, class G_t>
+void make_clique(const X_t &X , G_t &G)
+{
+ typename X_t::const_iterator n1, n2;
+ for (n1 = X.begin(); n1 != X.end(); n1++)
+ for (n2 = n1, ++n2; n2 != X.end(); ++n2)
+ add_edge(*n1, *n2, G);
+}
+
+template <class T_t, class v_t, class G_t>
+void add_vertices_to_tree_decomposition(T_t &T, const v_t v, const v_t v_end, G_t &G, std::vector<bool> &active)
+{
+ // Base case: Empty graph. Create an empty bag.
+ if (v == v_end)
+ {
+ boost::add_vertex(T);
+ return;
+ }
+
+ // Todo: A more elegant solution, e.g. using subgraphs or filtered graphs.
+
+ typedef typename boost::graph_traits<G_t>::adjacency_iterator adjacency_iter_t;
+ typedef typename boost::property_map<G_t, boost::vertex_index_t>::type index_map;
+ index_map index = boost::get(boost::vertex_index, G);
+
+ // Get the neigbours
+ adjacency_iter_t n, n_end;
+ decltype(T[0].bag) neighbours;
+ for (boost::tie(n, n_end) = boost::adjacent_vertices(*v, G); n != n_end; ++n)
+ if (active[index[*n]])
+ neighbours.insert(index[*n]);
+
+ // Recurse
+ active[*v] = false;
+ make_clique(neighbours, G);
+ v_t v_next = v;
+ add_vertices_to_tree_decomposition(T, ++v_next, v_end, G, active);
+
+ // Add new bag
+ typename boost::graph_traits<T_t>::vertex_iterator t;
+ typename boost::graph_traits<T_t>::vertex_descriptor s;
+ t = find_bag(neighbours, T);
+ s = boost::add_vertex(T);
+ boost::add_edge(*t, s, T);
+ T[s].bag = neighbours;
+ T[s].bag.insert(*v);
+}
+
+// Create a tree decomposition from an elimination ordering.
+template <class T_t, class G_t>
+void tree_decomposition_from_elimination_ordering(T_t &T, const std::list<unsigned int>& l, const G_t &G)
+{
+ std::list<unsigned int>::const_reverse_iterator v, v_end;
+ v = l.rbegin(), v_end = l.rend();
+
+ // Todo: Implement a graph adaptor for boost that allows to treat directed graphs as undirected graphs.
+ boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> G_sym;
+ boost::copy_graph(G, G_sym, boost::vertex_copy(forget_properties()).edge_copy(forget_properties()));
+
+ std::vector<bool> active(boost::num_vertices(G), true);
+
+ add_vertices_to_tree_decomposition(T, v, v_end, G_sym, active);
+}
+
+template <class T_t, class G_t>
+void thorup_tree_decomposition(T_t &tree_decomposition, const G_t &cfg)
+{
+ std::list<unsigned int> elimination_ordering;
+
+ thorup_elimination_ordering(elimination_ordering, cfg);
+
+ tree_decomposition_from_elimination_ordering(tree_decomposition, elimination_ordering, cfg);
+}
+
+// Ensure that all joins are at proper join nodes: Each node that has two children has the same bag as its children.
+// Complexity: Linear in the number of vertices of T.
+template <class T_t>
+void nicify_joins(T_t &T, typename boost::graph_traits<T_t>::vertex_descriptor t)
+{
+ typedef typename boost::graph_traits<T_t>::adjacency_iterator adjacency_iter_t;
+
+ adjacency_iter_t c, c_end;
+ typename boost::graph_traits<T_t>::vertex_descriptor c0, c1;
+
+ boost::tie(c, c_end) = boost::adjacent_vertices(t, T);
+
+ switch (out_degree(t, T))
+ {
+ case 0:
+ return;
+ case 1:
+ nicify_joins(T, *c);
+ return;
+ case 2:
+ break;
+ default:
+ c0 = *c++;
+ c1 = *c;
+ typename boost::graph_traits<T_t>::vertex_descriptor d;
+ d = boost::add_vertex(T);
+ add_edge(d, c0, T);
+ add_edge(d, c1, T);
+ boost::remove_edge(t, c0, T);
+ boost::remove_edge(t, c1, T);
+ T[d].bag = T[t].bag;
+ boost::add_edge(t, d, T);
+ nicify_joins(T, t);
+ return;
+ }
+
+ c0 = *c++;
+ c1 = *c;
+ nicify_joins(T, c0);
+ if (T[t].bag != T[c0].bag)
+ {
+ typename boost::graph_traits<T_t>::vertex_descriptor d;
+ d = boost::add_vertex(T);
+ boost::add_edge(d, c0, T);
+ boost::remove_edge(t, c0, T);
+ T[d].bag = T[t].bag;
+ boost::add_edge(t, d, T);
+ }
+ nicify_joins(T, c1);
+ if (T[t].bag != T[c1].bag)
+ {
+ typename boost::graph_traits<T_t>::vertex_descriptor d = boost::add_vertex(T);
+ boost::add_edge(d, c1, T);
+ boost::remove_edge(t, c1, T);
+ T[d].bag = T[t].bag;
+ boost::add_edge(t, d, T);
+ }
+}
+
+// Ensure that all nodes' bags are either a subset or a superset of their successors'.
+// Complexity: Linear in the number of vertices of T.
+template <class T_t>
+void nicify_diffs(T_t &T, typename boost::graph_traits<T_t>::vertex_descriptor t)
+{
+ typedef typename boost::graph_traits<T_t>::adjacency_iterator adjacency_iter_t;
+
+ adjacency_iter_t c, c_end;
+ typename boost::graph_traits<T_t>::vertex_descriptor c0, c1;
+
+ boost::tie(c, c_end) = adjacent_vertices(t, T);
+
+ switch (boost::out_degree(t, T))
+ {
+ case 0:
+ if (T[t].bag.size())
+ boost::add_edge(t, boost::add_vertex(T), T);
+ return;
+ case 1:
+ break;
+ case 2:
+ c0 = *c++;
+ c1 = *c;
+ nicify_diffs(T, c0);
+ nicify_diffs(T, c1);
+ return;
+ default:
+ std::cerr << "nicify_diffs error.\n";
+ return;
+ }
+
+ c0 = *c;
+ nicify_diffs(T, c0);
+
+ // Redundant bags are isolated, and thus marked for later removal.
+ if (T[t].bag == T[c0].bag)
+ {
+ T[c0].bag.clear();
+ boost::remove_edge(t, c0, T);
+ adjacency_iter_t c, c_end;
+ for(boost::tie(c, c_end) = adjacent_vertices(c0, T); c != c_end; ++c)
+ boost::add_edge(t, *c, T);
+ boost::clear_vertex(c0, T);
+ }
+
+ if (std::includes(T[t].bag.begin(), T[t].bag.end(), T[c0].bag.begin(), T[c0].bag.end()) || std::includes(T[c0].bag.begin(), T[c0].bag.end(), T[t].bag.begin(), T[t].bag.end()))
+ return;
+
+ typename boost::graph_traits<T_t>::vertex_descriptor d = boost::add_vertex(T);
+
+ boost::add_edge(d, c0, T);
+ boost::remove_edge(t, c0, T);
+ std::set_intersection(T[t].bag.begin(), T[t].bag.end(), T[c0].bag.begin(), T[c0].bag.end(), std::inserter(T[d].bag, T[d].bag.begin()));
+ boost::add_edge(t, d, T);
+}
+
+// Ensure that all nodes' bags' sizes differ by at most one to their successors'.
+template <class T_t>
+void nicify_diffs_more(T_t &T, typename boost::graph_traits<T_t>::vertex_descriptor t)
+{
+ typedef typename boost::graph_traits<T_t>::adjacency_iterator adjacency_iter_t;
+
+ adjacency_iter_t c, c_end;
+ typename boost::graph_traits<T_t>::vertex_descriptor c0, c1;
+
+ boost::tie(c, c_end) = adjacent_vertices(t, T);
+
+ switch (boost::out_degree(t, T))
+ {
+ case 0:
+ if (T[t].bag.size() > 1)
+ {
+ typename boost::graph_traits<T_t>::vertex_descriptor d = boost::add_vertex(T);
+ T[d].bag = T[t].bag;
+ T[d].bag.erase(T[d].bag.begin());
+ T[d].weight = 0;
+ boost::add_edge(t, d, T);
+ nicify_diffs_more(T, t);
+ }
+ else
+ T[t].weight = 0;
+ return;
+ case 1:
+ break;
+ case 2:
+ c0 = *c++;
+ c1 = *c;
+ nicify_diffs_more(T, c0);
+ nicify_diffs_more(T, c1);
+ {
+ const unsigned l = T[c0].weight;
+ const unsigned r = T[c1].weight;
+ T[t].weight = (l == r) ? l + 1 : std::max(l , r);
+ }
+ return;
+ default:
+ std::cerr << "nicify_diffs_more error.\n";
+ return;
+ }
+
+ c0 = *c;
+
+ size_t c0_size, t_size;
+ t_size = T[t].bag.size();
+ c0_size = T[c0].bag.size();
+
+ if (t_size <= c0_size + 1 && t_size + 1 >= c0_size)
+ {
+ nicify_diffs_more(T, c0);
+ T[t].weight = T[c0].weight;
+ return;
+ }
+
+ typename boost::graph_traits<T_t>::vertex_descriptor d = add_vertex(T);
+ boost::add_edge(d, c0, T);
+ boost::remove_edge(t, c0, T);
+ T[d].bag = T[t_size > c0_size ? t : c0].bag;
+ typename decltype(T[d].bag)::iterator i;
+ for (i = T[d].bag.begin(); T[t_size < c0_size ? t : c0].bag.find(*i) != T[t_size < c0_size ? t : c0].bag.end(); ++i);
+ T[d].bag.erase(i);
+ boost::add_edge(t, d, T);
+
+ nicify_diffs_more(T, t);
+}
+
+#ifdef HAVE_TREEDEC_COMBINATIONS_HPP
+#include <treedec/treedec_traits.hpp>
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/graph/graph_utility.hpp>
+#include <treedec/nice_decomposition.hpp>
+
+using treedec::find_root;
+#else
+// Find a root of an acyclic graph T
+// Complexity: Linear in the number of vertices of T.
+template <class T_t>
+typename boost::graph_traits<T_t>::vertex_descriptor find_root(T_t &T)
+{
+ typename boost::graph_traits<T_t>::vertex_descriptor t;
+ typename boost::graph_traits<T_t>::in_edge_iterator e, e_end;
+
+ t = *(boost::vertices(T).first);
+
+ for (boost::tie(e, e_end) = boost::in_edges(t, T); e != e_end; boost::tie(e, e_end) = boost::in_edges(t, T))
+ t = boost::source(*e, T);
+
+ return(t);
+}
+#endif
+
+// Remove isolated vertices possibly introduced by nicify_diffs(). Complicated, since boost does not support removing more than one vertex at a time.
+template <class T_t>
+void remove_isolated_vertices(T_t &T)
+{
+ bool change = true;
+ while(change)
+ {
+ change = false;
+ if(boost::num_vertices(T) <= 1)
+ return;
+
+ for (unsigned int i = 0; i < boost::num_vertices(T); i++)
+ if(!boost::out_degree(i, T) && !boost::in_degree(i, T))
+ {
+ remove_vertex(i, T);
+ change = true;
+ break;
+ }
+ }
+}
+
+// Transform a tree decomposition into a nice tree decomposition.
+template <class T_t>
+void nicify(T_t &T)
+{
+ typename boost::graph_traits<T_t>::vertex_descriptor t;
+
+ t = find_root(T);
+
+ // Ensure we have an empty bag at the root.
+ if(T[t].bag.size())
+ {
+ typename boost::graph_traits<T_t>::vertex_descriptor d = t;
+ t = add_vertex(T);
+ boost::add_edge(t, d, T);
+ }
+
+ nicify_joins(T, t);
+ nicify_diffs(T, t);
+ nicify_diffs_more(T, t);
+ remove_isolated_vertices(T);
+}
+
+class cfg_titlewriter
+{
+public:
+ explicit cfg_titlewriter(const std::string& f, const std::string& p) : function(f), purpose(p)
+ {
+ }
+ void operator()(std::ostream& out) const
+ {
+ out << "graph [label=\"Control-flow-graph for " << purpose << " (function " << function << ")\"]\n";
+ }
+private:
+ std::string function;
+ std::string purpose;
+};
+
+class dec_titlewriter
+{
+public:
+ explicit dec_titlewriter(unsigned int w, const std::string& f, const std::string& p) : function(f), purpose(p)
+ {
+ width = w;
+ }
+ void operator()(std::ostream& out) const
+ {
+ out << "graph [label=\"Tree-decomposition of width " << width << " for " << purpose << " (function " << function << ")\"]\n";
+ }
+private:
+ unsigned int width;
+ std::string function;
+ std::string purpose;
+};
+
+#ifdef HAVE_TREEDEC_COMBINATIONS_HPP
+
+#include <treedec/graph.hpp>
+#include <treedec/preprocessing.hpp>
+#include <boost/graph/copy.hpp>
+
+#include <treedec/thorup.hpp>
+#include <treedec/combinations.hpp>
+#include <treedec/misc.hpp>
+
+template <typename Gd_t, typename Gs_t>
+void copy_undir(Gd_t &dst, const Gs_t &src)
+{
+ for(unsigned i = 0; i < boost::num_vertices(src); i++)
+ boost::add_vertex(dst);
+
+ typename boost::graph_traits<Gs_t>::edge_iterator e, e_end;
+ for(boost::tie(e, e_end) = boost::edges(src); e != e_end; ++e)
+ {
+ wassert (boost::source(*e, src) != boost::target(*e, src));
+ if (!boost::edge(boost::source(*e, src), boost::target(*e, src), dst).second)
+ boost::add_edge(boost::source(*e, src), boost::target(*e, src), dst);
+ }
+}
+
+#endif
+
+#undef USE_THORUP // Thorup's classic algorithm (default in SDCC pre-3.7.0). Substantially worse width than the others.
+#define USE_PP_FI_TM 1 // A good trade-off between width and runtime
+#undef USE_EX17 // Slightly better width than PP_FI_TM, but no polynomial runtime bound.
+#undef USE_PP_MD // Slightly worse width than PP_FI_TM.
+#undef USE_PP_FI // Slightly worse width than PP_FI_TM.
+
+// Get a nice tree decomposition for a cfg.
+template <class T_t, class G_t>
+void get_nice_tree_decomposition(T_t &tree_dec, const G_t &cfg)
+{
+ thorup_tree_decomposition(tree_dec, cfg);
+
+#ifdef HAVE_TREEDEC_COMBINATIONS_HPP
+
+#ifdef USE_THORUP
+ treedec::thorup<G_t> a2(cfg);
+#else
+ typedef boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS> cfg2_t;
+ cfg2_t cfg2;
+ copy_undir(cfg2, cfg);
+#if USE_PP_FI_TM
+ treedec::comb::PP_FI_TM<cfg2_t> a2(cfg2);
+#elif USE_EX17
+ treedec::comb::ex17<cfg2_t> a2(cfg2);
+#elif USE_PP_MD
+ treedec::comb::PP_MD<cfg2_t> a2(cfg2);
+#elif USE_PP_FI
+ treedec::comb::PP_FI<cfg2_t> a2(cfg2);
+#else
+#error No algorithm selected
+#endif
+#endif
+
+ T_t tree_dec2;
+ a2.do_it();
+ a2.get_tree_decomposition(tree_dec2);
+ wassert(treedec::is_valid_treedecomposition(cfg, tree_dec2));
+
+ if (treedec::get_width(tree_dec2) < treedec::get_width(tree_dec))
+ std::swap(tree_dec, tree_dec2);
+#endif
+
+ nicify(tree_dec);
+
+#ifdef HAVE_TREEDEC_COMBINATIONS_HPP
+ wassert(treedec::is_valid_treedecomposition(cfg, tree_dec));
+#endif
+}
+