Added "opt_const -fine" and "opt_reduce -fine"
authorClifford Wolf <clifford@clifford.at>
Mon, 21 Jul 2014 14:34:16 +0000 (16:34 +0200)
committerClifford Wolf <clifford@clifford.at>
Mon, 21 Jul 2014 14:34:16 +0000 (16:34 +0200)
passes/opt/opt.cc
passes/opt/opt_const.cc
passes/opt/opt_reduce.cc
tests/tools/autotest.sh

index 8f4725e1c2779d5719d2c94a3a2753626765f62f..62aa48bee9ba0327a9c95f4e5d9ab4e555fb34cf 100644 (file)
@@ -31,7 +31,7 @@ struct OptPass : public Pass {
        {
                //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
                log("\n");
-               log("    opt [-purge] [-mux_undef] [-mux_bool] [-undriven] [selection]\n");
+               log("    opt [-purge] [-mux_undef] [-mux_bool] [-undriven] [-fine] [selection]\n");
                log("\n");
                log("This pass calls all the other opt_* passes in a useful order. This performs\n");
                log("a series of trivial optimizations and cleanups. This pass executes the other\n");
@@ -42,11 +42,11 @@ struct OptPass : public Pass {
                log("\n");
                log("    do\n");
                log("        opt_muxtree\n");
-               log("        opt_reduce\n");
+               log("        opt_reduce [-fine]\n");
                log("        opt_share\n");
                log("        opt_rmdff\n");
                log("        opt_clean [-purge]\n");
-               log("        opt_const [-mux_undef] [-mux_bool] [-undriven]\n");
+               log("        opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine]\n");
                log("    while [changed design]\n");
                log("\n");
        }
@@ -54,6 +54,7 @@ struct OptPass : public Pass {
        {
                std::string opt_clean_args;
                std::string opt_const_args;
+               std::string opt_reduce_args;
 
                log_header("Executing OPT pass (performing simple optimizations).\n");
                log_push();
@@ -76,6 +77,11 @@ struct OptPass : public Pass {
                                opt_const_args += " -undriven";
                                continue;
                        }
+                       if (args[argidx] == "-fine") {
+                               opt_const_args += " -fine";
+                               opt_reduce_args += " -fine";
+                               continue;
+                       }
                        break;
                }
                extra_args(args, argidx, design);
@@ -88,7 +94,7 @@ struct OptPass : public Pass {
                while (1) {
                        OPT_DID_SOMETHING = false;
                        Pass::call(design, "opt_muxtree");
-                       Pass::call(design, "opt_reduce");
+                       Pass::call(design, "opt_reduce" + opt_reduce_args);
                        Pass::call(design, "opt_share");
                        Pass::call(design, "opt_rmdff");
                        Pass::call(design, "opt_clean" + opt_clean_args);
index 76948344ea23a11870e8a82a4c55cd52bc23f9fc..a17ca6792926ca2f3301fae3819c768737b283df 100644 (file)
 #include <stdlib.h>
 #include <assert.h>
 #include <stdio.h>
-#include <set>
+#include <algorithm>
 
 static bool did_something;
 
-void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
+static void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
 {
        CellTypes ct(design);
        SigMap sigmap(module);
@@ -71,7 +71,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
        }
 }
 
-void replace_cell(RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val)
+static void replace_cell(RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val)
 {
        RTLIL::SigSpec Y = cell->connections[out_port];
        log("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n",
@@ -85,7 +85,103 @@ void replace_cell(RTLIL::Module *module, RTLIL::Cell *cell, std::string info, st
        did_something = true;
 }
 
-void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool)
+static bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, bool extend_u0, SigMap &sigmap)
+{
+       std::string b_name = cell->connections.count("\\B") ? "\\B" : "\\A";
+
+       bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool();
+       bool b_signed = cell->parameters.at(b_name + "_SIGNED").as_bool();
+
+       RTLIL::SigSpec sig_a = sigmap(cell->connections.at("\\A"));
+       RTLIL::SigSpec sig_b = sigmap(cell->connections.at(b_name));
+       RTLIL::SigSpec sig_y = sigmap(cell->connections.at("\\Y"));
+
+       if (extend_u0) {
+               sig_a.extend_u0(sig_y.width, a_signed);
+               sig_b.extend_u0(sig_y.width, b_signed);
+       } else {
+               sig_a.extend(sig_y.width, a_signed);
+               sig_b.extend(sig_y.width, b_signed);
+       }
+
+       std::vector<RTLIL::SigBit> bits_a = sig_a, bits_b = sig_b, bits_y = sig_y;
+
+       enum { GRP_DYN, GRP_CONST_A, GRP_CONST_B, GRP_CONST_AB, GRP_N };
+       std::map<std::pair<RTLIL::SigBit, RTLIL::SigBit>, std::set<RTLIL::SigBit>> grouped_bits[GRP_N];
+
+       for (int i = 0; i < SIZE(bits_y); i++)
+       {
+               int group_idx = GRP_DYN;
+               RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i];
+
+               if (bit_a.wire == NULL && bit_b.wire == NULL)
+                       group_idx = GRP_CONST_AB;
+               else if (bit_a.wire == NULL)
+                       group_idx = GRP_CONST_A;
+               else if (bit_b.wire == NULL && commutative)
+                       group_idx = GRP_CONST_A, std::swap(bit_a, bit_b);
+               else if (bit_b.wire == NULL)
+                       group_idx = GRP_CONST_B;
+
+               grouped_bits[group_idx][std::pair<RTLIL::SigBit, RTLIL::SigBit>(bit_a, bit_b)].insert(bits_y[i]);
+       }
+
+       for (int i = 0; i < GRP_N; i++)
+               if (SIZE(grouped_bits[i]) == SIZE(bits_y))
+                       return false;
+
+       log("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n",
+                       log_id(cell->type), log_id(cell), log_id(module));
+
+       for (int i = 0; i < GRP_N; i++)
+       {
+               if (grouped_bits[i].empty())
+                       continue;
+
+               RTLIL::Wire *new_y = module->addWire(NEW_ID, SIZE(grouped_bits[i]));
+               RTLIL::SigSpec new_a, new_b;
+               RTLIL::SigSig new_conn;
+
+               for (auto &it : grouped_bits[i]) {
+                       for (auto &bit : it.second) {
+                               new_conn.first.append_bit(bit);
+                               new_conn.second.append_bit(RTLIL::SigBit(new_y, new_a.width));
+                       }
+                       new_a.append_bit(it.first.first);
+                       new_b.append_bit(it.first.second);
+               }
+
+               RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
+
+               c->connections["\\A"] = new_a;
+               c->parameters["\\A_WIDTH"] = new_a.width;
+               c->parameters["\\A_SIGNED"] = false;
+
+               if (b_name == "\\B") {
+                       c->connections["\\B"] = new_b;
+                       c->parameters["\\B_WIDTH"] = new_b.width;
+                       c->parameters["\\B_SIGNED"] = false;
+               }
+
+               c->connections["\\Y"] = new_y;
+               c->parameters["\\Y_WIDTH"] = new_y->width;
+               c->check();
+
+               module->connections.push_back(new_conn);
+
+               log("  New cell `%s': A=%s", log_id(c), log_signal(new_a));
+               if (b_name == "\\B")
+                       log(", B=%s", log_signal(new_b));
+               log("\n");
+       }
+
+       module->remove(cell);
+       OPT_DID_SOMETHING = true;
+       did_something = true;
+       return true;
+}
+
+static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine)
 {
        if (!design->selected(module))
                return;
@@ -108,6 +204,11 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 #define ACTION_DO(_p_, _s_) do { replace_cell(module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
 #define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_))
 
+               if (do_fine && (cell->type == "$not" || cell->type == "$pos" || cell->type == "$bu0" ||
+                               cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor"))
+                       if (group_cell_inputs(module, cell, true, cell->type != "$pos", assign_map))
+                               goto next_cell;
+
                if ((cell->type == "$_INV_" || cell->type == "$not" || cell->type == "$logic_not") && cell->connections["\\Y"].width == 1 &&
                                invert_map.count(assign_map(cell->connections["\\A"])) != 0) {
                        replace_cell(module, cell, "double_invert", "\\Y", invert_map.at(assign_map(cell->connections["\\A"])));
@@ -573,12 +674,16 @@ struct OptConstPass : public Pass {
                log("    -undriven\n");
                log("        replace undriven nets with undef (x) constants\n");
                log("\n");
+               log("    -fine\n");
+               log("        perform fine-grain optimizations\n");
+               log("\n");
        }
        virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
        {
                bool mux_undef = false;
                bool mux_bool = false;
                bool undriven = false;
+               bool do_fine = false;
 
                log_header("Executing OPT_CONST pass (perform const folding).\n");
                log_push();
@@ -597,6 +702,10 @@ struct OptConstPass : public Pass {
                                undriven = true;
                                continue;
                        }
+                       if (args[argidx] == "-fine") {
+                               do_fine = true;
+                               continue;
+                       }
                        break;
                }
                extra_args(args, argidx, design);
@@ -609,9 +718,9 @@ struct OptConstPass : public Pass {
                        do {
                                do {
                                        did_something = false;
-                                       replace_const_cells(design, mod_it.second, false, mux_undef, mux_bool);
+                                       replace_const_cells(design, mod_it.second, false, mux_undef, mux_bool, do_fine);
                                } while (did_something);
-                               replace_const_cells(design, mod_it.second, true, mux_undef, mux_bool);
+                               replace_const_cells(design, mod_it.second, true, mux_undef, mux_bool, do_fine);
                        } while (did_something);
                }
 
index a0c7a027feb4976fad930a7fe7d6428f591ae438..93945e49a847074eec482160f1483bed43da36d3 100644 (file)
@@ -244,7 +244,7 @@ struct OptReduceWorker
                }
        }
 
-       OptReduceWorker(RTLIL::Design *design, RTLIL::Module *module) :
+       OptReduceWorker(RTLIL::Design *design, RTLIL::Module *module, bool do_fine) :
                        design(design), module(module), assign_map(module)
        {
                log("  Optimizing cells in module %s.\n", module->name.c_str());
@@ -318,7 +318,7 @@ struct OptReduceWorker
 
                                // this optimization is to aggressive for most coarse-grain applications.
                                // but we always want it for multiplexers driving write enable ports.
-                               if (mem_wren_sigs.check_any(assign_map(cell->connections.at("\\Y"))))
+                               if (do_fine || mem_wren_sigs.check_any(assign_map(cell->connections.at("\\Y"))))
                                        opt_mux_bits(cell);
 
                                opt_mux(cell);
@@ -333,7 +333,7 @@ struct OptReducePass : public Pass {
        {
                //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
                log("\n");
-               log("    opt_reduce [selection]\n");
+               log("    opt_reduce [options] [selection]\n");
                log("\n");
                log("This pass performs two interlinked optimizations:\n");
                log("\n");
@@ -343,17 +343,31 @@ struct OptReducePass : public Pass {
                log("2. it identifies duplicated inputs to MUXes and replaces them with a single\n");
                log("input with the original control signals OR'ed together.\n");
                log("\n");
+               log("    -fine\n");
+               log("      perform fine-grain optimizations\n");
+               log("\n");
        }
        virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
        {
+               bool do_fine = false;
+
                log_header("Executing OPT_REDUCE pass (consolidate $*mux and $reduce_* inputs).\n");
-               extra_args(args, 1, design);
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       if (args[argidx] == "-fine") {
+                               do_fine = true;
+                               continue;
+                       }
+                       break;
+               }
+               extra_args(args, argidx, design);
 
                int total_count = 0;
                for (auto &mod_it : design->modules) {
                        if (!design->selected(mod_it.second))
                                continue;
-                       OptReduceWorker worker(design, mod_it.second);
+                       OptReduceWorker worker(design, mod_it.second, do_fine);
                        total_count += worker.total_count;
                }
 
index 266691a64a62d146fdd4a6cf9f4ba5c29e9b01f3..c383e19f4fef7048f3ab735af7ae5f6a7ef3fac0 100755 (executable)
@@ -129,7 +129,7 @@ do
                        test_passes -p "verific -vlog2k $fn; verific -import -gates -all; opt; memory;;"
                else
                        test_passes -f "$frontend" -p "hierarchy; proc; opt; memory -nomap; opt; fsm; opt" $fn
-                       test_passes -f "$frontend" -p "hierarchy; proc; opt; memory; opt; fsm; opt; techmap; opt; abc -dff; opt" $fn
+                       test_passes -f "$frontend" -p "hierarchy; proc; opt; memory; opt; fsm; opt -fine; techmap; opt; abc -dff; opt" $fn
                fi
                touch ../${bn}.log
        }