From 42c356c49c04a735fe27e672ff31452170f84b40 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 31 Dec 2018 23:53:23 +0000 Subject: [PATCH] opt_lut: eliminate LUTs evaluating to constants or inputs. --- passes/opt/opt_lut.cc | 81 +++++++++++++++++++++++++++++++++++++++ tests/opt/opt_lut_elim.il | 19 +++++++++ tests/opt/opt_lut_elim.ys | 3 ++ tests/opt/opt_lut_port.ys | 1 + 4 files changed, 104 insertions(+) create mode 100644 tests/opt/opt_lut_elim.il create mode 100644 tests/opt/opt_lut_elim.ys diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc index be050c713..261af538f 100644 --- a/passes/opt/opt_lut.cc +++ b/passes/opt/opt_lut.cc @@ -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 &lut_dlogic_inputs = luts_dlogic_inputs[lut]; + + vector 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 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 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 worklist = luts; diff --git a/tests/opt/opt_lut_elim.il b/tests/opt/opt_lut_elim.il new file mode 100644 index 000000000..75675d983 --- /dev/null +++ b/tests/opt/opt_lut_elim.il @@ -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 index 000000000..8e5e23aea --- /dev/null +++ b/tests/opt/opt_lut_elim.ys @@ -0,0 +1,3 @@ +read_ilang opt_lut_elim.il +opt_lut +select -assert-count 0 t:$lut diff --git a/tests/opt/opt_lut_port.ys b/tests/opt/opt_lut_port.ys index 51dfd988b..3cb4ecb23 100644 --- a/tests/opt/opt_lut_port.ys +++ b/tests/opt/opt_lut_port.ys @@ -1,2 +1,3 @@ read_ilang opt_lut_port.il +opt_lut select -assert-count 2 t:$lut -- 2.30.2