opt_lut: eliminate LUTs evaluating to constants or inputs.
authorwhitequark <whitequark@whitequark.org>
Mon, 31 Dec 2018 23:53:23 +0000 (23:53 +0000)
committerwhitequark <whitequark@whitequark.org>
Mon, 31 Dec 2018 23:55:40 +0000 (23:55 +0000)
passes/opt/opt_lut.cc
tests/opt/opt_lut_elim.il [new file with mode: 0644]
tests/opt/opt_lut_elim.ys [new file with mode: 0644]
tests/opt/opt_lut_port.ys

index be050c7138cef0ae05e40f17e4709cb8f7fd4ef0..261af538f813ac05ff0d53b9d3de8a90e0f8f417 100644 (file)
@@ -187,6 +187,87 @@ struct OptLutWorker
                }
                show_stats_by_arity();
 
+               log("\n");
+               log("Eliminating LUTs.\n");
+               for (auto lut : luts)
+               {
+                       SigSpec lut_input = sigmap(lut->getPort("\\A"));
+                       pool<int> &lut_dlogic_inputs = luts_dlogic_inputs[lut];
+
+                       vector<SigBit> lut_inputs;
+                       for (auto &bit : lut_input)
+                       {
+                               if (bit.wire)
+                                       lut_inputs.push_back(sigmap(bit));
+                       }
+
+                       bool const0_match = true;
+                       bool const1_match = true;
+                       vector<bool> input_matches;
+                       for (size_t i = 0; i < lut_inputs.size(); i++)
+                               input_matches.push_back(true);
+
+                       for (int eval = 0; eval < 1 << lut_inputs.size(); eval++)
+                       {
+                               dict<SigBit, bool> eval_inputs;
+                               for (size_t i = 0; i < lut_inputs.size(); i++)
+                                       eval_inputs[lut_inputs[i]] = (eval >> i) & 1;
+                               bool value = evaluate_lut(lut, eval_inputs);
+                               if (value != 0)
+                                       const0_match = false;
+                               if (value != 1)
+                                       const1_match = false;
+                               for (size_t i = 0; i < lut_inputs.size(); i++)
+                               {
+                                       if (value != eval_inputs[lut_inputs[i]])
+                                               input_matches[i] = false;
+                               }
+                       }
+
+                       int input_match = -1;
+                       for (size_t i = 0; i < lut_inputs.size(); i++)
+                               if (input_matches[i])
+                                       input_match = i;
+
+                       if (const0_match || const1_match || input_match != -1)
+                       {
+                               log("Found redundant cell %s.%s.\n", log_id(module), log_id(lut));
+
+                               SigBit value;
+                               if (const0_match)
+                               {
+                                       log("  Cell evaluates constant 0.\n");
+                                       value = State::S0;
+                               }
+                               if (const1_match)
+                               {
+                                       log("  Cell evaluates constant 1.\n");
+                                       value = State::S1;
+                               }
+                               if (input_match != -1) {
+                                       log("  Cell evaluates signal %s.\n", log_signal(lut_inputs[input_match]));
+                                       value = lut_inputs[input_match];
+                               }
+
+                               if (lut_dlogic_inputs.size())
+                               {
+                                       log("  Not eliminating cell (connected to dedicated logic).\n");
+                               }
+                               else
+                               {
+                                       SigSpec lut_output = lut->getPort("\\Y");
+                                       module->connect(lut_output, value);
+
+                                       module->remove(lut);
+                                       luts.erase(lut);
+                                       luts_arity.erase(lut);
+                                       luts_dlogics.erase(lut);
+                                       luts_dlogic_inputs.erase(lut);
+                               }
+                       }
+               }
+               show_stats_by_arity();
+
                log("\n");
                log("Combining LUTs.\n");
                pool<RTLIL::Cell*> worklist = luts;
diff --git a/tests/opt/opt_lut_elim.il b/tests/opt/opt_lut_elim.il
new file mode 100644 (file)
index 0000000..75675d9
--- /dev/null
@@ -0,0 +1,19 @@
+module \test
+  wire input 1 \i
+
+  wire output 2 \o1
+  cell $lut $1
+    parameter \LUT 16'0110100110010110
+    parameter \WIDTH 4
+    connect \A { \i 3'000 }
+    connect \Y \o1
+  end
+
+  wire output 2 \o2
+  cell $lut $2
+    parameter \LUT 16'0110100010010110
+    parameter \WIDTH 4
+    connect \A { \i 3'000 }
+    connect \Y \o2
+  end
+end
diff --git a/tests/opt/opt_lut_elim.ys b/tests/opt/opt_lut_elim.ys
new file mode 100644 (file)
index 0000000..8e5e23a
--- /dev/null
@@ -0,0 +1,3 @@
+read_ilang opt_lut_elim.il
+opt_lut
+select -assert-count 0 t:$lut
index 51dfd988bc987cea0f5ca7bd717d774445b1d7a9..3cb4ecb23bb0c49164b61b37117a7ce838def46b 100644 (file)
@@ -1,2 +1,3 @@
 read_ilang opt_lut_port.il
+opt_lut
 select -assert-count 2 t:$lut