opt_expr: Propagate constants to port connections.
authorMarcelina Kościelnicka <mwk@0x04.net>
Tue, 27 Jul 2021 13:24:48 +0000 (15:24 +0200)
committerMarcelina Kościelnicka <mwk@0x04.net>
Tue, 27 Jul 2021 18:44:26 +0000 (20:44 +0200)
This adds one simple piece of functionality to opt_expr: when a cell
port is connected to a fully-constant signal (as determined by sigmap),
the port is reconnected directly to the constant value.  This is just
enough optimization to fix the "non-constant $meminit input" problem
without requiring a full opt_clean or a separate pass.

passes/opt/opt_expr.cc
tests/opt/opt_expr_constconn.v [new file with mode: 0644]
tests/opt/opt_expr_constconn.ys [new file with mode: 0644]

index 709cb6020d2d13d2be1d650f6f2d90e24b17fed6..b7bbb2adfa3b48a5a4f60f7130b35363d2716944 100644 (file)
@@ -395,9 +395,6 @@ int get_highest_hot_index(RTLIL::SigSpec signal)
 
 void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc, bool noclkinv)
 {
-       if (!design->selected(module))
-               return;
-
        CellTypes ct_combinational;
        ct_combinational.setup_internals();
        ct_combinational.setup_stdcells();
@@ -2007,6 +2004,23 @@ skip_alu_split:
        }
 }
 
+void replace_const_connections(RTLIL::Module *module) {
+       SigMap assign_map(module);
+       for (auto cell : module->selected_cells())
+       {
+               std::vector<std::pair<RTLIL::IdString, SigSpec>> changes;
+               for (auto &conn : cell->connections()) {
+                       SigSpec mapped = assign_map(conn.second);
+                       if (conn.second != mapped && mapped.is_fully_const())
+                               changes.push_back({conn.first, mapped});
+               }
+               if (!changes.empty())
+                       did_something = true;
+               for (auto &it : changes)
+                       cell->setPort(it.first, it.second);
+       }
+}
+
 struct OptExprPass : public Pass {
        OptExprPass() : Pass("opt_expr", "perform const folding and simple expression rewriting") { }
        void help() override
@@ -2117,6 +2131,11 @@ struct OptExprPass : public Pass {
                                        design->scratchpad_set_bool("opt.did_something", true);
                        } while (did_something);
 
+                       did_something = false;
+                       replace_const_connections(module);
+                       if (did_something)
+                               design->scratchpad_set_bool("opt.did_something", true);
+
                        log_suppressed();
                }
 
diff --git a/tests/opt/opt_expr_constconn.v b/tests/opt/opt_expr_constconn.v
new file mode 100644 (file)
index 0000000..d18b120
--- /dev/null
@@ -0,0 +1,8 @@
+module top(...);
+
+input [7:0] A;
+output [7:0] B;
+wire [7:0] C = 3;
+assign B = A + C;
+
+endmodule
diff --git a/tests/opt/opt_expr_constconn.ys b/tests/opt/opt_expr_constconn.ys
new file mode 100644 (file)
index 0000000..9dd848a
--- /dev/null
@@ -0,0 +1,7 @@
+read_verilog opt_expr_constconn.v
+select -assert-count 1 t:$add
+select -assert-count 1 t:$add %ci w:C %i
+equiv_opt -assert opt_expr
+design -load postopt
+select -assert-count 1 t:$add
+select -assert-count 0 t:$add %ci w:C %i