Fixed topological ordering in freduce pass
authorClifford Wolf <clifford@clifford.at>
Wed, 7 Aug 2013 17:38:19 +0000 (19:38 +0200)
committerClifford Wolf <clifford@clifford.at>
Wed, 7 Aug 2013 17:38:19 +0000 (19:38 +0200)
passes/sat/freduce.cc

index b822405f7ecdcf227fb1ba047c58d59a27ad6485..c19f252943d2d6fe1301974f0ce53e7efb04214b 100644 (file)
@@ -46,14 +46,11 @@ struct FreduceHelper
        SigPool inputs, nodes;
        RTLIL::SigSpec input_sigs;
 
-       SigSet<RTLIL::SigSpec> driver_inputs;
+       SigSet<RTLIL::SigSpec> source_signals;
        std::vector<RTLIL::Const> test_vectors;
        std::map<RTLIL::SigSpec, RTLIL::Const> node_to_data;
        std::map<RTLIL::SigSpec, RTLIL::SigSpec> node_result;
 
-       std::vector<RTLIL::SigSig> result_groups;
-       SigPool groups_unlink;
-
        uint32_t xorshift32_state;
 
         uint32_t xorshift32() {
@@ -93,8 +90,9 @@ struct FreduceHelper
                int max_node_len = 20;
                for (auto &it : node_to_data)
                        max_node_len = std::max(max_node_len, int(strlen(log_signal(it.first))));
+               log("  full node fingerprints:\n");
                for (auto &it : node_to_data)
-                       log("  %-*s %s\n", max_node_len+5, log_signal(it.first), log_signal(it.second));
+                       log("    %-*s %s\n", max_node_len+5, log_signal(it.first), log_signal(it.second));
        }
 
        void check(RTLIL::SigSpec sig1, RTLIL::SigSpec sig2)
@@ -165,16 +163,20 @@ struct FreduceHelper
                }
        }
 
-       bool topsort_helper(RTLIL::SigSpec cursor, RTLIL::SigSpec stoplist)
+       bool toproot_helper(RTLIL::SigSpec cursor, RTLIL::SigSpec stoplist, int level)
        {
-               if (stoplist.extract(cursor).width != 0)
+               // log("    %*schecking %s: %s\n", level*2, "", log_signal(cursor), log_signal(stoplist));
+
+               if (stoplist.extract(cursor).width != 0) {
+                       // log("    %*s  STOP\n", level*2, "");
                        return false;
+               }
 
                stoplist.append(cursor);
-               std::set<RTLIL::SigSpec> next = driver_inputs.find(cursor);
+               std::set<RTLIL::SigSpec> next = source_signals.find(cursor);
 
                for (auto &it : next)
-                       if (!topsort_helper(it, stoplist))
+                       if (!toproot_helper(it, stoplist, level+1))
                                return false;
 
                return true;
@@ -182,18 +184,61 @@ struct FreduceHelper
 
        // KISS topological sort of bits in signal. return one element of sig
        // without dependencies to the others (or empty if input is not a DAG).
-       RTLIL::SigSpec topsort(RTLIL::SigSpec sig)
+       RTLIL::SigSpec toproot(RTLIL::SigSpec sig)
        {
                sig.expand();
+               // log("  finding topological root in %s:\n", log_signal(sig));
                for (auto &c : sig.chunks) {
                        RTLIL::SigSpec stoplist = sig;
                        stoplist.remove(c);
-                       if (topsort_helper(c, stoplist))
+                       // log("    testing %s as root:\n", log_signal(c));
+                       if (toproot_helper(c, stoplist, 0))
                                return c;
                }
                return RTLIL::SigSpec();
        }
 
+       void update_design_for_group(RTLIL::SigSpec root, RTLIL::SigSpec rest)
+       {
+               SigPool unlink;
+               unlink.add(rest);
+
+               for (auto &cell_it : module->cells) {
+                       RTLIL::Cell *cell = cell_it.second;
+                       if (!ct.cell_known(cell->type))
+                               continue;
+                       for (auto &conn : cell->connections)
+                               if (ct.cell_output(cell->type, conn.first)) {
+                                       RTLIL::SigSpec sig = sigmap(conn.second);
+                                       sig.expand();
+                                       bool did_something = false;
+                                       for (auto &c : sig.chunks) {
+                                               if (c.wire == NULL || !unlink.check_any(c))
+                                                       continue;
+                                               c.wire = new RTLIL::Wire;
+                                               c.wire->name = NEW_ID;
+                                               module->add(c.wire);
+                                               assert(c.width == 1);
+                                               c.offset = 0;
+                                               did_something = true;
+                                       }
+                                       if (did_something) {
+                                               sig.optimize();
+                                               conn.second = sig;
+                                       }
+                               }
+               }
+
+               rest.expand();
+               for (auto &c : rest.chunks) {
+                       if (c.wire != NULL && !root.is_fully_const()) {
+                               source_signals.erase(c);
+                               source_signals.insert(c, root);
+                       }
+                       module->connections.push_back(RTLIL::SigSig(c, root));
+               }
+       }
+
        void analyze_groups()
        {
                SigMap to_group_major;
@@ -212,15 +257,19 @@ struct FreduceHelper
                        RTLIL::SigSig group = it;
 
                        if (!it.first.is_fully_const()) {
-                               group.first = topsort(it.second);
-                               if (group.first.width == 0)
-                                       log_error("Operating on non-DAG input: failed to find topological root for `%s'.\n", log_signal(it.second));
+                               group.first = toproot(it.second);
+                               if (group.first.width == 0) {
+                                       log("Operating on non-DAG input: failed to find topological root for `%s'.\n", log_signal(it.second));
+                                       return;
+                               }
                                group.second.remove(group.first);
                        }
 
                        group.first.optimize();
                        group.second.sort_and_unify();
-                       result_groups.push_back(group);
+
+                       log("  found group: %s -> %s\n", log_signal(group.first), log_signal(group.second));
+                       update_design_for_group(group.first, group.second);
                }
        }
 
@@ -249,7 +298,7 @@ struct FreduceHelper
                        cell_inputs.expand();
                        for (auto &c : cell_inputs.chunks)
                                if (c.wire != NULL)
-                                       driver_inputs.insert(cell_outputs, c);
+                                       source_signals.insert(cell_outputs, c);
                        if (!satgen.importCell(cell))
                                log_error("Failed to import cell to SAT solver: %s (%s)\n",
                                                RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
@@ -276,7 +325,7 @@ struct FreduceHelper
                for (auto &test_vec : test_vectors)
                        run_test(test_vec);
 
-               // run the analysis
+               // run the analysis and update design
 
                analyze_const();
                analyze_alias();
@@ -285,44 +334,8 @@ struct FreduceHelper
                for (auto &test_vec : test_vectors)
                        log("  test vector: %s\n", log_signal(test_vec));
 
+               dump_node_data();
                analyze_groups();
-
-               for (auto &it : result_groups) {
-                       log("  found group: %s -> %s\n", log_signal(it.first), log_signal(it.second));
-                       groups_unlink.add(it.second);
-               }
-
-               for (auto &cell_it : module->cells) {
-                       RTLIL::Cell *cell = cell_it.second;
-                       if (!ct.cell_known(cell->type))
-                               continue;
-                       for (auto &conn : cell->connections)
-                               if (ct.cell_output(cell->type, conn.first)) {
-                                       RTLIL::SigSpec sig = sigmap(conn.second);
-                                       sig.expand();
-                                       bool did_something = false;
-                                       for (auto &c : sig.chunks) {
-                                               if (c.wire == NULL || !groups_unlink.check_any(c))
-                                                       continue;
-                                               c.wire = new RTLIL::Wire;
-                                               c.wire->name = NEW_ID;
-                                               module->add(c.wire);
-                                               assert(c.width == 1);
-                                               c.offset = 0;
-                                               did_something = true;
-                                       }
-                                       if (did_something) {
-                                               sig.optimize();
-                                               conn.second = sig;
-                                       }
-                               }
-               }
-
-               for (auto &it : result_groups) {
-                       it.second.expand();
-                       for (auto &c : it.second.chunks)
-                               module->connections.push_back(RTLIL::SigSig(c, it.first));
-               }
        }
 };