From 9943b18a059ff0c383b06e713866d19793b86c15 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Wed, 13 Nov 2024 15:00:05 -0800 Subject: [PATCH 01/42] Add `muldiv_c` and `muxadd` peepopts --- passes/pmgen/Makefile.inc | 2 + passes/pmgen/peepopt.cc | 6 +++ passes/pmgen/peepopt_muldiv_c.pmg | 76 +++++++++++++++++++++++++++++++ passes/pmgen/peepopt_muxadd.pmg | 57 +++++++++++++++++++++++ 4 files changed, 141 insertions(+) create mode 100644 passes/pmgen/peepopt_muldiv_c.pmg create mode 100644 passes/pmgen/peepopt_muxadd.pmg diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index 6fa7d1fd740..c2cd8b9e9ce 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -57,6 +57,8 @@ PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul_right.pmg PEEPOPT_PATTERN += passes/pmgen/peepopt_shiftmul_left.pmg PEEPOPT_PATTERN += passes/pmgen/peepopt_shiftadd.pmg PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg +PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv_c.pmg +PEEPOPT_PATTERN += passes/pmgen/peepopt_muxadd.pmg PEEPOPT_PATTERN += passes/pmgen/peepopt_formal_clockgateff.pmg passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index 5b678ee556d..e7a729ecb5f 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -42,8 +42,12 @@ struct PeepoptPass : public Pass { log("\n"); log("This pass employs the following rules by default:\n"); log("\n"); + log(" * muxadd - Replace S?(A+B):A with A+(S?B:0)\n"); + log("\n"); log(" * muldiv - Replace (A*B)/B with A\n"); log("\n"); + log(" * muldiv_c - Replace (A*B)/C with A*(B/C) when C is a const divisible by B.\n"); + log("\n"); log(" * shiftmul - Replace A>>(B*C) with A'>>(B<div into const->mul when b and c are divisible constants: +// y = (a * b_const) / c_const ===> a * eval(b_const / c_const) +// + +state a b_const mul_y + +match mul + // Select multiplier + select mul->type == $mul +endmatch + +code a b_const mul_y + // Get multiplier signals + a = port(mul, \A); + b_const = port(mul, \B); + mul_y = port(mul, \Y); + + // Fanout of each multiplier Y bit should be 1 (no bit-split) + for (auto bit : mul_y) + if (nusers(bit) != 2) + reject; + + // A and B can be interchanged + branch; + std::swap(a, b_const); +endcode + +match div + // Select div of form (a * b_const) / c_const + select div->type == $div + + // Check that b_const and c_const is constant + filter b_const.is_fully_const() + filter port(div, \B).is_fully_const() +endmatch + +code + // Get div signals + SigSpec div_a = port(div, \A); + SigSpec c_const = port(div, \B); + SigSpec div_y = port(div, \Y); + + // Get offset of multiplier result chunk in divider + int offset = GetSize(div_a) - GetSize(mul_y); + + // Get properties and values of b_const and c_const + int b_const_width = mul->getParam(ID::B_WIDTH).as_int(); + bool b_const_signed = mul->getParam(ID::B_SIGNED).as_bool(); + bool c_const_signed = div->getParam(ID::B_SIGNED).as_bool(); + int b_const_int = b_const.as_int(b_const_signed); + int c_const_int = c_const.as_int(c_const_signed); + int b_const_int_shifted = b_const_int << offset; + + // Check that there are only zeros before offset + if (offset < 0 || !div_a.extract(0, offset).is_fully_zero()) + reject; + + // Check that b is divisible by c + if (b_const_int_shifted % c_const_int != 0) + reject; + + // Rewire to only keep multiplier + mul->setPort(\B, Const(b_const_int_shifted / c_const_int, b_const_width)); + mul->setPort(\Y, div_y); + + // Remove divider + autoremove(div); + + // Log, fixup, accept + log("muldiv_const pattern in %s: mul=%s, div=%s\n", log_id(module), log_id(mul), log_id(div)); + mul->fixup_parameters(); + accept; +endcode diff --git a/passes/pmgen/peepopt_muxadd.pmg b/passes/pmgen/peepopt_muxadd.pmg new file mode 100644 index 00000000000..d4fd3cc4d7a --- /dev/null +++ b/passes/pmgen/peepopt_muxadd.pmg @@ -0,0 +1,57 @@ +pattern muxadd +// +// Authored by Akash Levy of Silimate, Inc. under ISC license. +// Transforms add->mux into mux->add: +// y = s ? (a + b) : a ===> y = a + (s ? b : 0) +// + +state add_a add_b add_y + +match add + // Select adder + select add->type == $add +endmatch + +code add_y add_a add_b + // Get adder signals + add_a = port(add, \A); + add_b = port(add, \B); + add_y = port(add, \Y); + + // Fanout of each adder Y bit should be 1 (no bit-split) + for (auto bit : add_y) + if (nusers(bit) != 2) + reject; + + // A and B can be interchanged + branch; + std::swap(add_a, add_b); +endcode + +match mux + // Select mux of form s ? (a + b) : a, allow leading 0s when A_WIDTH != Y_WIDTH + select mux->type == $mux + index port(mux, \A) === SigSpec({Const(State::S0, GetSize(add_y)-GetSize(add_a)), add_a}) + index port(mux, \B) === add_y +endmatch + +code + // Get mux signal + SigSpec mux_y = port(mux, \Y); + + // Create new mid wire + SigSpec mid = module->addWire(NEW_ID, GetSize(add_b)); + + // Rewire + mux->setPort(\A, Const(State::S0, GetSize(add_b))); + mux->setPort(\B, add_b); + mux->setPort(\Y, mid); + add->setPort(\B, mid); + add->setPort(\Y, mux_y); + + // Log, fixup, accept + log("muxadd pattern in %s: mux=%s, add=%s\n", log_id(module), log_id(mux), log_id(add)); + add->fixup_parameters(); + mux->fixup_parameters(); + accept; +endcode From 9f84a928781f638c639a86fbb82d351a5fa88aa6 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Sat, 16 Nov 2024 23:20:09 -0800 Subject: [PATCH 02/42] Update passes/pmgen/peepopt_muxadd.pmg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martin Povišer --- passes/pmgen/peepopt_muxadd.pmg | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/passes/pmgen/peepopt_muxadd.pmg b/passes/pmgen/peepopt_muxadd.pmg index d4fd3cc4d7a..421b89366ea 100644 --- a/passes/pmgen/peepopt_muxadd.pmg +++ b/passes/pmgen/peepopt_muxadd.pmg @@ -19,9 +19,8 @@ code add_y add_a add_b add_y = port(add, \Y); // Fanout of each adder Y bit should be 1 (no bit-split) - for (auto bit : add_y) - if (nusers(bit) != 2) - reject; + if (nusers(add_y) != 2) + reject; // A and B can be interchanged branch; From a3cc22821cbfb6bf043c2e07bf8b3b5119f9e2b3 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Sat, 16 Nov 2024 23:21:01 -0800 Subject: [PATCH 03/42] Update passes/pmgen/peepopt_muxadd.pmg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martin Povišer --- passes/pmgen/peepopt_muxadd.pmg | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/passes/pmgen/peepopt_muxadd.pmg b/passes/pmgen/peepopt_muxadd.pmg index 421b89366ea..7f114c93ee2 100644 --- a/passes/pmgen/peepopt_muxadd.pmg +++ b/passes/pmgen/peepopt_muxadd.pmg @@ -10,6 +10,13 @@ state add_a add_b add_y match add // Select adder select add->type == $add + choice A {\A, \B} + define B (A == \A ? \B : \A) + set add_y port(add, \Y) + set add_a port(add, A) + set add_b port(add, B) + set add_a_signed param(add, (A == \A) ? \A_SIGNED : \B_SIGNED)) + set add_a_id A endmatch code add_y add_a add_b From ee18e1faa4adba712a8529528caadc138396720f Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Sun, 17 Nov 2024 10:38:57 -0800 Subject: [PATCH 04/42] Preliminary fixes, not done --- passes/pmgen/peepopt_muldiv_c.pmg | 5 ++--- passes/pmgen/peepopt_muxadd.pmg | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/passes/pmgen/peepopt_muldiv_c.pmg b/passes/pmgen/peepopt_muldiv_c.pmg index a24e47b8cd8..411ff3122ff 100644 --- a/passes/pmgen/peepopt_muldiv_c.pmg +++ b/passes/pmgen/peepopt_muldiv_c.pmg @@ -19,9 +19,8 @@ code a b_const mul_y mul_y = port(mul, \Y); // Fanout of each multiplier Y bit should be 1 (no bit-split) - for (auto bit : mul_y) - if (nusers(bit) != 2) - reject; + if (nusers(mul_y) != 2) + reject; // A and B can be interchanged branch; diff --git a/passes/pmgen/peepopt_muxadd.pmg b/passes/pmgen/peepopt_muxadd.pmg index 7f114c93ee2..856875e3f63 100644 --- a/passes/pmgen/peepopt_muxadd.pmg +++ b/passes/pmgen/peepopt_muxadd.pmg @@ -6,17 +6,19 @@ pattern muxadd // state add_a add_b add_y +state add_a_signed +state add_a_id match add // Select adder select add->type == $add choice A {\A, \B} - define B (A == \A ? \B : \A) - set add_y port(add, \Y) - set add_a port(add, A) - set add_b port(add, B) - set add_a_signed param(add, (A == \A) ? \A_SIGNED : \B_SIGNED)) - set add_a_id A + define B (A == \A ? \B : \A) + set add_y port(add, \Y) + set add_a port(add, A) + set add_b port(add, B) + set add_a_signed param(add, (A == \A) ? \A_SIGNED : \B_SIGNED) + set add_a_id A endmatch code add_y add_a add_b @@ -26,8 +28,8 @@ code add_y add_a add_b add_y = port(add, \Y); // Fanout of each adder Y bit should be 1 (no bit-split) - if (nusers(add_y) != 2) - reject; + if (nusers(add_y) != 2) + reject; // A and B can be interchanged branch; @@ -37,7 +39,7 @@ endcode match mux // Select mux of form s ? (a + b) : a, allow leading 0s when A_WIDTH != Y_WIDTH select mux->type == $mux - index port(mux, \A) === SigSpec({Const(State::S0, GetSize(add_y)-GetSize(add_a)), add_a}) + index port(mux, \A) === SigSpec({Const(!param(add, \A_SIGNED).bool() ? () : State::S0, GetSize(add_y)-GetSize(add_a)), add_a}) index port(mux, \B) === add_y endmatch From 2375879b3209effd1b04143ef02eb5bdcf49bc93 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Tue, 17 Dec 2024 04:19:16 -0800 Subject: [PATCH 05/42] Update peepopt_muldiv_c.pmg --- passes/pmgen/peepopt_muldiv_c.pmg | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/passes/pmgen/peepopt_muldiv_c.pmg b/passes/pmgen/peepopt_muldiv_c.pmg index 411ff3122ff..94b260d2842 100644 --- a/passes/pmgen/peepopt_muldiv_c.pmg +++ b/passes/pmgen/peepopt_muldiv_c.pmg @@ -61,6 +61,13 @@ code if (b_const_int_shifted % c_const_int != 0) reject; + // Check that every single output bit of the multiplier is connected consecutively to the div operator (offset accounted for) + for (int i = 0; i < mul_y.size(); i++) { + if (sigmap(mul_y[i]) != sigmap(div_a[i + offset])) { + reject; + } + } + // Rewire to only keep multiplier mul->setPort(\B, Const(b_const_int_shifted / c_const_int, b_const_width)); mul->setPort(\Y, div_y); From 0e15edd099926b6397a769346db6e42b760543af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 17 Dec 2024 15:11:44 +0100 Subject: [PATCH 06/42] Add muxadd peepopt tests --- Makefile | 1 + tests/peepopt/muxadd.ys | 335 ++++++++++++++++++++++++++++++++++++++ tests/peepopt/run-test.sh | 6 + 3 files changed, 342 insertions(+) create mode 100644 tests/peepopt/muxadd.ys create mode 100755 tests/peepopt/run-test.sh diff --git a/Makefile b/Makefile index 0bc52fe1a7f..db290ca71d7 100644 --- a/Makefile +++ b/Makefile @@ -845,6 +845,7 @@ endif +cd tests/sim && bash run-test.sh +cd tests/svinterfaces && bash run-test.sh $(SEEDOPT) +cd tests/svtypes && bash run-test.sh $(SEEDOPT) + +cd tests/peepopt && bash run-test.sh +cd tests/proc && bash run-test.sh +cd tests/blif && bash run-test.sh +cd tests/opt && bash run-test.sh diff --git a/tests/peepopt/muxadd.ys b/tests/peepopt/muxadd.ys new file mode 100644 index 00000000000..261cdc2840e --- /dev/null +++ b/tests/peepopt/muxadd.ys @@ -0,0 +1,335 @@ +log -header "Test basic s?(a+b):a pattern gets transformed (a,b module inputs)" +log -push +design -reset +read_verilog < (a+b) > a" +log -push +design -reset +read_verilog < a > b" +log -push +design -reset +read_verilog < b > a" +log -push +design -reset +read_verilog < Date: Tue, 17 Dec 2024 15:33:31 -0800 Subject: [PATCH 07/42] Compiles and transforms correctly, fails equiv --- passes/pmgen/peepopt_muxadd.pmg | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/passes/pmgen/peepopt_muxadd.pmg b/passes/pmgen/peepopt_muxadd.pmg index 856875e3f63..137c94d9d59 100644 --- a/passes/pmgen/peepopt_muxadd.pmg +++ b/passes/pmgen/peepopt_muxadd.pmg @@ -5,8 +5,8 @@ pattern muxadd // y = s ? (a + b) : a ===> y = a + (s ? b : 0) // -state add_a add_b add_y -state add_a_signed +state add_a add_b add_y add_a_ext +state add_a_signed state add_a_id match add @@ -21,12 +21,13 @@ match add set add_a_id A endmatch -code add_y add_a add_b +code add_y add_a add_b add_a_ext // Get adder signals add_a = port(add, \A); add_b = port(add, \B); add_y = port(add, \Y); - + add_a_ext = SigSpec(add_a); + add_a_ext.extend_u0(GetSize(add_y), param(add, \A_SIGNED).as_bool()); // Fanout of each adder Y bit should be 1 (no bit-split) if (nusers(add_y) != 2) reject; @@ -39,7 +40,7 @@ endcode match mux // Select mux of form s ? (a + b) : a, allow leading 0s when A_WIDTH != Y_WIDTH select mux->type == $mux - index port(mux, \A) === SigSpec({Const(!param(add, \A_SIGNED).bool() ? () : State::S0, GetSize(add_y)-GetSize(add_a)), add_a}) + index port(mux, \A) === add_a_ext index port(mux, \B) === add_y endmatch @@ -55,11 +56,13 @@ code mux->setPort(\B, add_b); mux->setPort(\Y, mid); add->setPort(\B, mid); - add->setPort(\Y, mux_y); - + add->setPort(\A, add_a); + add->setPort(\Y, add_y); + module->connect(mux_y, add_y); // Log, fixup, accept log("muxadd pattern in %s: mux=%s, add=%s\n", log_id(module), log_id(mux), log_id(add)); add->fixup_parameters(); mux->fixup_parameters(); + did_something = true; accept; endcode From 8a6c1005e3afe45a17e2754f40f3341b31528dfe Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Tue, 17 Dec 2024 15:45:36 -0800 Subject: [PATCH 08/42] Clean after opt --- tests/peepopt/muxadd.ys | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/peepopt/muxadd.ys b/tests/peepopt/muxadd.ys index 261cdc2840e..6d36de54cb0 100644 --- a/tests/peepopt/muxadd.ys +++ b/tests/peepopt/muxadd.ys @@ -13,7 +13,7 @@ module top(a, b, s, y); endmodule EOF check -assert -equiv_opt -assert peepopt +equiv_opt -assert peepopt ;;; design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired From b4fa7dc5aab22376fabede16396b0f3769963bea Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Tue, 17 Dec 2024 15:50:13 -0800 Subject: [PATCH 09/42] Update peepopt_muxadd.pmg --- passes/pmgen/peepopt_muxadd.pmg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/pmgen/peepopt_muxadd.pmg b/passes/pmgen/peepopt_muxadd.pmg index 137c94d9d59..5001183daa8 100644 --- a/passes/pmgen/peepopt_muxadd.pmg +++ b/passes/pmgen/peepopt_muxadd.pmg @@ -1,6 +1,6 @@ pattern muxadd // -// Authored by Akash Levy of Silimate, Inc. under ISC license. +// Authored by Akash Levy and Alain Dargelas of Silimate, Inc. under ISC license. // Transforms add->mux into mux->add: // y = s ? (a + b) : a ===> y = a + (s ? b : 0) // From f9ae66d2e41b6de7a25bc9d7683ca4e7699fd936 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Tue, 17 Dec 2024 15:50:37 -0800 Subject: [PATCH 10/42] Update peepopt_muldiv_c.pmg --- passes/pmgen/peepopt_muldiv_c.pmg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/pmgen/peepopt_muldiv_c.pmg b/passes/pmgen/peepopt_muldiv_c.pmg index 94b260d2842..71b717312ad 100644 --- a/passes/pmgen/peepopt_muldiv_c.pmg +++ b/passes/pmgen/peepopt_muldiv_c.pmg @@ -1,6 +1,6 @@ pattern muldiv_c // -// Authored by Akash Levy of Silimate, Inc. under ISC license. +// Authored by Akash Levy and Alain Dargelas of Silimate, Inc. under ISC license. // Transforms mul->div into const->mul when b and c are divisible constants: // y = (a * b_const) / c_const ===> a * eval(b_const / c_const) // From 297923272db439d3ade09e3125a02983547d6c1d Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Tue, 17 Dec 2024 16:03:37 -0800 Subject: [PATCH 11/42] Fix code review issue --- passes/pmgen/peepopt_muldiv_c.pmg | 1 + passes/pmgen/pmgen.py | 7 ++++++ tests/peepopt/multdiv_c.ys | 38 +++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 tests/peepopt/multdiv_c.ys diff --git a/passes/pmgen/peepopt_muldiv_c.pmg b/passes/pmgen/peepopt_muldiv_c.pmg index 71b717312ad..dd755b962d7 100644 --- a/passes/pmgen/peepopt_muldiv_c.pmg +++ b/passes/pmgen/peepopt_muldiv_c.pmg @@ -34,6 +34,7 @@ match div // Check that b_const and c_const is constant filter b_const.is_fully_const() filter port(div, \B).is_fully_const() + index remove_bottom_padding(port(div, \A)) === mul_y endmatch code diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index 6e2fabeebde..b07612f507b 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -429,6 +429,13 @@ def process_pmgfile(f, filename): print(" }", file=f) print("", file=f) + print(" SigSpec remove_bottom_padding(SigSpec sig) {", file=f) + print(" int i = 0;", file=f) + print(" for (; i < sig.size() - 1 && sig[i] == State::S0; i++) {} ", file=f) + print(" return sig.extract(i, sig.size() - i);", file=f) + print(" }", file=f) + print("", file=f) + print(" void blacklist(Cell *cell) {", file=f) print(" if (cell != nullptr && blacklist_cells.insert(cell).second) {", file=f) print(" auto ptr = rollback_cache.find(cell);", file=f) diff --git a/tests/peepopt/multdiv_c.ys b/tests/peepopt/multdiv_c.ys new file mode 100644 index 00000000000..2564fd46728 --- /dev/null +++ b/tests/peepopt/multdiv_c.ys @@ -0,0 +1,38 @@ +log -header "Test simple positive case" +log -push +design -reset +read_verilog < Date: Tue, 17 Dec 2024 21:40:42 -0800 Subject: [PATCH 12/42] Passing equiv for simplest muxadd case, prevent multiple match/rewiring on same mux-add pair --- passes/pmgen/peepopt_muxadd.pmg | 42 ++++++++++++++++++--------------- tests/peepopt/muxadd.ys | 20 ++++++++++++++++ 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/passes/pmgen/peepopt_muxadd.pmg b/passes/pmgen/peepopt_muxadd.pmg index 5001183daa8..f2c86e4f748 100644 --- a/passes/pmgen/peepopt_muxadd.pmg +++ b/passes/pmgen/peepopt_muxadd.pmg @@ -7,7 +7,7 @@ pattern muxadd state add_a add_b add_y add_a_ext state add_a_signed -state add_a_id +state add_a_id add_b_id match add // Select adder @@ -19,6 +19,7 @@ match add set add_b port(add, B) set add_a_signed param(add, (A == \A) ? \A_SIGNED : \B_SIGNED) set add_a_id A + set add_b_id B endmatch code add_y add_a add_b add_a_ext @@ -47,22 +48,25 @@ endmatch code // Get mux signal SigSpec mux_y = port(mux, \Y); - - // Create new mid wire - SigSpec mid = module->addWire(NEW_ID, GetSize(add_b)); - - // Rewire - mux->setPort(\A, Const(State::S0, GetSize(add_b))); - mux->setPort(\B, add_b); - mux->setPort(\Y, mid); - add->setPort(\B, mid); - add->setPort(\A, add_a); - add->setPort(\Y, add_y); - module->connect(mux_y, add_y); - // Log, fixup, accept - log("muxadd pattern in %s: mux=%s, add=%s\n", log_id(module), log_id(mux), log_id(add)); - add->fixup_parameters(); - mux->fixup_parameters(); - did_something = true; - accept; + SigSpec mux_a = port(mux, \A); + SigSpec mux_b = port(mux, \B); + // Prevent multiple branches to edit the same pair of mux/add + if (mux_b == add_y || mux_a == add_y) { + // Create new mid wire + SigSpec mid = module->addWire(NEW_ID, GetSize(add_b)); + // Rewire + add->setPort(\B, mid); + add->setPort(\A, add_a); + add->setPort(\Y, add_y); + mux->setPort(add_a_id, Const(State::S0, GetSize(add_b))); + mux->setPort(add_b_id, add_b); + mux->setPort(\Y, mid); + module->connect(mux_y, add_y); + // Log, fixup, accept + log("muxadd pattern in %s: mux=%s, add=%s\n", log_id(module), log_id(mux), log_id(add)); + add->fixup_parameters(); + mux->fixup_parameters(); + did_something = true; + accept; + } endcode diff --git a/tests/peepopt/muxadd.ys b/tests/peepopt/muxadd.ys index 6d36de54cb0..d5b922153ea 100644 --- a/tests/peepopt/muxadd.ys +++ b/tests/peepopt/muxadd.ys @@ -8,6 +8,26 @@ module top(a, b, s, y); input wire s; output wire [3:0] y; + assign y = s ? (a + b) : a; +endmodule +EOF +check -assert +equiv_opt -assert peepopt ;;; +design -load postopt +select -assert-any t:$add %co1 %a w:y %i # assert adder rewired + +log -pop + +log -header "Test basic s?(a+b):a pattern with intermediate var gets transformed (a,b module inputs)" +log -push +design -reset +read_verilog < Date: Wed, 18 Dec 2024 14:40:05 +0100 Subject: [PATCH 13/42] peepopt_muldiv_c: add test --- tests/peepopt/muldiv_c.ys | 258 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 tests/peepopt/muldiv_c.ys diff --git a/tests/peepopt/muldiv_c.ys b/tests/peepopt/muldiv_c.ys new file mode 100644 index 00000000000..be46b5490c5 --- /dev/null +++ b/tests/peepopt/muldiv_c.ys @@ -0,0 +1,258 @@ +# Basic pattern transformed: (a * b) / c +read_verilog < Date: Wed, 18 Dec 2024 10:37:51 -0800 Subject: [PATCH 14/42] Switch formal proof to use miter/sat --- tests/peepopt/muxadd.ys | 66 ++++++++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/tests/peepopt/muxadd.ys b/tests/peepopt/muxadd.ys index d5b922153ea..bca3abdc876 100644 --- a/tests/peepopt/muxadd.ys +++ b/tests/peepopt/muxadd.ys @@ -7,17 +7,21 @@ module top(a, b, s, y); input wire [3:0] b; input wire s; output wire [3:0] y; - assign y = s ? (a + b) : a; endmodule EOF check -assert -equiv_opt -assert peepopt ;;; -design -load postopt +copy top orig +cd top +peepopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired +clean -purge +cd +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x top orig miter +sat -verify -prove-asserts -show-ports -enable_undef miter -log -pop +log -pop log -header "Test basic s?(a+b):a pattern with intermediate var gets transformed (a,b module inputs)" log -push design -reset @@ -33,9 +37,15 @@ module top(a, b, s, y); endmodule EOF check -assert -equiv_opt -assert peepopt ;;; -design -load postopt +copy top orig +cd top +peepopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired +clean -purge +cd +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x top orig miter +sat -verify -prove-asserts -show-ports -enable_undef miter + log -pop log -header "Test basic s?(a+b):a pattern gets transformed (a is driven by a cell)" @@ -54,9 +64,15 @@ module top(a_, b, s, y); endmodule EOF check -assert -equiv_opt -assert peepopt -design -load postopt +copy top orig +cd top +peepopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired +clean -purge +cd +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x top orig miter +sat -verify -prove-asserts -show-ports -enable_undef miter + log -pop log -header "Test basic s?(a+b):a pattern gets transformed (b is driven by a cell, output consumed by a cell)" @@ -78,9 +94,15 @@ module top(a, b_, f, s, y_); endmodule EOF check -assert -equiv_opt -assert peepopt -design -load postopt +copy top orig +cd top +peepopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired +clean -purge +cd +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x top orig miter +sat -verify -prove-asserts -show-ports -enable_undef miter + log -pop log -header "Test no transform when a+b has more fanouts (module output)" @@ -98,9 +120,15 @@ module top(a, b, ab, s, y); endmodule EOF check -assert -equiv_opt -assert peepopt -design -load postopt +copy top orig +cd top +peepopt select -assert-none t:$add %co1 %a w:y %i +clean -purge +cd +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x top orig miter +sat -verify -prove-asserts -show-ports -enable_undef miter + log -pop log -header "Test no transform when a+b has more fanouts (single bit, cell)" @@ -118,9 +146,19 @@ module top(a, b, s, y, z); endmodule EOF check -assert -equiv_opt -assert peepopt -design -load postopt +copy top orig +cd top +peepopt select -assert-none t:$add %co1 %a w:y %i +clean -purge +cd +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x top orig miter +sat -verify -prove-asserts -show-ports -enable_undef miter + + +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +log Please fix all the designs below to use the miter/sat proof +quit log -pop log -header "Test no transform when a+b width smaller than a's width" From 7b70ba4fd6cf42650097a9e33e8e0e519684ba9e Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Wed, 18 Dec 2024 10:54:54 -0800 Subject: [PATCH 15/42] Convert to miter/sat --- tests/peepopt/multdiv_c.ys | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/tests/peepopt/multdiv_c.ys b/tests/peepopt/multdiv_c.ys index 2564fd46728..dbf9f2dbbc2 100644 --- a/tests/peepopt/multdiv_c.ys +++ b/tests/peepopt/multdiv_c.ys @@ -2,7 +2,7 @@ log -header "Test simple positive case" log -push design -reset read_verilog < Date: Wed, 18 Dec 2024 11:28:32 -0800 Subject: [PATCH 16/42] Code review fix, bail out on integers above 64 bits --- passes/pmgen/peepopt_muldiv_c.pmg | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/passes/pmgen/peepopt_muldiv_c.pmg b/passes/pmgen/peepopt_muldiv_c.pmg index dd755b962d7..c2d7add17c2 100644 --- a/passes/pmgen/peepopt_muldiv_c.pmg +++ b/passes/pmgen/peepopt_muldiv_c.pmg @@ -54,6 +54,13 @@ code int c_const_int = c_const.as_int(c_const_signed); int b_const_int_shifted = b_const_int << offset; + if (mul->getParam(ID::B_WIDTH).size() > 64) + reject; + if (b_const.size() > 64) + reject; + if (c_const.size() > 64) + reject; + // Check that there are only zeros before offset if (offset < 0 || !div_a.extract(0, offset).is_fully_zero()) reject; From 53cf38c65680f3c254a55bda81b6ced19db01b14 Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Wed, 18 Dec 2024 11:36:21 -0800 Subject: [PATCH 17/42] Leave comment about signage assumption --- passes/pmgen/peepopt_muldiv_c.pmg | 1 + 1 file changed, 1 insertion(+) diff --git a/passes/pmgen/peepopt_muldiv_c.pmg b/passes/pmgen/peepopt_muldiv_c.pmg index c2d7add17c2..78b5e768ade 100644 --- a/passes/pmgen/peepopt_muldiv_c.pmg +++ b/passes/pmgen/peepopt_muldiv_c.pmg @@ -48,6 +48,7 @@ code // Get properties and values of b_const and c_const int b_const_width = mul->getParam(ID::B_WIDTH).as_int(); + // b_const may be coming from the A port but it's an RTLIL invariant that A_SIGNED equals B_SIGNED bool b_const_signed = mul->getParam(ID::B_SIGNED).as_bool(); bool c_const_signed = div->getParam(ID::B_SIGNED).as_bool(); int b_const_int = b_const.as_int(b_const_signed); From 1c774f41ee797784c442a6e0266fc5fffad62a5a Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 18 Dec 2024 21:24:04 +0100 Subject: [PATCH 18/42] peepopt_muldiv_c: remove write_verilog from test --- tests/peepopt/muldiv_c.ys | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/peepopt/muldiv_c.ys b/tests/peepopt/muldiv_c.ys index be46b5490c5..49397b2423c 100644 --- a/tests/peepopt/muldiv_c.ys +++ b/tests/peepopt/muldiv_c.ys @@ -164,7 +164,6 @@ endmodule EOT equiv_opt -assert peepopt design -load postopt -write_verilog select -assert-count 1 t:$mul select -assert-count 1 t:$div design -reset From 6db406f5c299fbaf89d3c4eb29005e1a6e4c276d Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Wed, 18 Dec 2024 20:21:44 -0800 Subject: [PATCH 19/42] Back to equiv_opt for multdiv tests --- tests/peepopt/multdiv_c.ys | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/tests/peepopt/multdiv_c.ys b/tests/peepopt/multdiv_c.ys index dbf9f2dbbc2..3f0693288c1 100644 --- a/tests/peepopt/multdiv_c.ys +++ b/tests/peepopt/multdiv_c.ys @@ -1,23 +1,19 @@ log -header "Test simple positive case" log -push design -reset -read_verilog < Date: Wed, 18 Dec 2024 20:22:35 -0800 Subject: [PATCH 20/42] Back to equiv_opt for multdiv tests --- tests/peepopt/multdiv_c.ys | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/peepopt/multdiv_c.ys b/tests/peepopt/multdiv_c.ys index 3f0693288c1..6261b356f9b 100644 --- a/tests/peepopt/multdiv_c.ys +++ b/tests/peepopt/multdiv_c.ys @@ -1,7 +1,7 @@ log -header "Test simple positive case" log -push design -reset -read_verilog -sv < Date: Wed, 18 Dec 2024 20:47:03 -0800 Subject: [PATCH 21/42] Check for overflow, remove obsolete code, fix test --- passes/pmgen/peepopt_muldiv_c.pmg | 13 ++++++------- tests/peepopt/multdiv_c.ys | 8 ++++---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/passes/pmgen/peepopt_muldiv_c.pmg b/passes/pmgen/peepopt_muldiv_c.pmg index 78b5e768ade..fff4ad2a9c2 100644 --- a/passes/pmgen/peepopt_muldiv_c.pmg +++ b/passes/pmgen/peepopt_muldiv_c.pmg @@ -55,6 +55,7 @@ code int c_const_int = c_const.as_int(c_const_signed); int b_const_int_shifted = b_const_int << offset; + // Integer values should be lesser than 64 bits if (mul->getParam(ID::B_WIDTH).size() > 64) reject; if (b_const.size() > 64) @@ -62,6 +63,11 @@ code if (c_const.size() > 64) reject; + // Check for potential mult overflow + if (b_const.size() + a.size() > mul_y.size()) { + reject; + } + // Check that there are only zeros before offset if (offset < 0 || !div_a.extract(0, offset).is_fully_zero()) reject; @@ -70,13 +76,6 @@ code if (b_const_int_shifted % c_const_int != 0) reject; - // Check that every single output bit of the multiplier is connected consecutively to the div operator (offset accounted for) - for (int i = 0; i < mul_y.size(); i++) { - if (sigmap(mul_y[i]) != sigmap(div_a[i + offset])) { - reject; - } - } - // Rewire to only keep multiplier mul->setPort(\B, Const(b_const_int_shifted / c_const_int, b_const_width)); mul->setPort(\Y, div_y); diff --git a/tests/peepopt/multdiv_c.ys b/tests/peepopt/multdiv_c.ys index 6261b356f9b..fa8f0d38d2f 100644 --- a/tests/peepopt/multdiv_c.ys +++ b/tests/peepopt/multdiv_c.ys @@ -4,7 +4,7 @@ design -reset read_verilog < Date: Wed, 18 Dec 2024 21:04:53 -0800 Subject: [PATCH 22/42] Remove redundant code --- passes/pmgen/peepopt_muxadd.pmg | 3 --- 1 file changed, 3 deletions(-) diff --git a/passes/pmgen/peepopt_muxadd.pmg b/passes/pmgen/peepopt_muxadd.pmg index f2c86e4f748..8b55f5c8861 100644 --- a/passes/pmgen/peepopt_muxadd.pmg +++ b/passes/pmgen/peepopt_muxadd.pmg @@ -24,9 +24,6 @@ endmatch code add_y add_a add_b add_a_ext // Get adder signals - add_a = port(add, \A); - add_b = port(add, \B); - add_y = port(add, \Y); add_a_ext = SigSpec(add_a); add_a_ext.extend_u0(GetSize(add_y), param(add, \A_SIGNED).as_bool()); // Fanout of each adder Y bit should be 1 (no bit-split) From 45500f4dd9b0f423ccf4152a9d5017184047db1b Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Wed, 18 Dec 2024 21:48:33 -0800 Subject: [PATCH 23/42] A or B width extend --- passes/pmgen/peepopt_muxadd.pmg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/pmgen/peepopt_muxadd.pmg b/passes/pmgen/peepopt_muxadd.pmg index 8b55f5c8861..b15183854a9 100644 --- a/passes/pmgen/peepopt_muxadd.pmg +++ b/passes/pmgen/peepopt_muxadd.pmg @@ -24,8 +24,8 @@ endmatch code add_y add_a add_b add_a_ext // Get adder signals - add_a_ext = SigSpec(add_a); - add_a_ext.extend_u0(GetSize(add_y), param(add, \A_SIGNED).as_bool()); + add_a_ext = SigSpec(port(add, add_a_id)); + add_a_ext.extend_u0(GetSize(add_y), add_a_signed.as_bool()); // Fanout of each adder Y bit should be 1 (no bit-split) if (nusers(add_y) != 2) reject; From 325b0e3f3398d3012047569c62937a92c2a9b4f8 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 19 Dec 2024 15:22:14 +0100 Subject: [PATCH 24/42] peepopt_multdiv_c: add forgotten -assert --- tests/peepopt/muldiv_c.ys | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/peepopt/muldiv_c.ys b/tests/peepopt/muldiv_c.ys index 49397b2423c..2d57e5b6b91 100644 --- a/tests/peepopt/muldiv_c.ys +++ b/tests/peepopt/muldiv_c.ys @@ -130,7 +130,7 @@ module top( assign y = mul / 8'sd0; endmodule EOT -equiv_opt peepopt +equiv_opt -assert peepopt design -load postopt select -assert-count 1 t:$mul select -assert-count 1 t:$div From e8e806f2ca289749cc5a7c7ddba11c55965bb54b Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Thu, 19 Dec 2024 13:54:25 -0800 Subject: [PATCH 25/42] Consolidate tests --- tests/peepopt/muldiv_c.ys | 42 ++++++++++++++++++++++++++++++++++++++ tests/peepopt/multdiv_c.ys | 39 ----------------------------------- 2 files changed, 42 insertions(+), 39 deletions(-) delete mode 100644 tests/peepopt/multdiv_c.ys diff --git a/tests/peepopt/muldiv_c.ys b/tests/peepopt/muldiv_c.ys index 2d57e5b6b91..892f0b53348 100644 --- a/tests/peepopt/muldiv_c.ys +++ b/tests/peepopt/muldiv_c.ys @@ -1,3 +1,45 @@ +log -header "Test simple positive case" +log -push +design -reset +read_verilog < Date: Thu, 19 Dec 2024 14:08:37 -0800 Subject: [PATCH 26/42] Move helper code to peepopt.cc, check offset --- passes/pmgen/peepopt.cc | 12 ++++++++++++ passes/pmgen/peepopt_muldiv_c.pmg | 2 +- passes/pmgen/pmgen.py | 7 ------- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index e7a729ecb5f..fe4fc89e0f6 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -28,6 +28,9 @@ bool did_something; // scratchpad configurations for pmgen int shiftadd_max_ratio; +// Helper function, removes LSB 0s +SigSpec remove_bottom_padding(SigSpec sig); + #include "passes/pmgen/peepopt_pm.h" struct PeepoptPass : public Pass { @@ -117,4 +120,13 @@ struct PeepoptPass : public Pass { } } PeepoptPass; + +SigSpec remove_bottom_padding(SigSpec sig) +{ + int i = 0; + for (; i < sig.size() - 1 && sig[i] == State::S0; i++) { + } + return sig.extract(i, sig.size() - i); +} + PRIVATE_NAMESPACE_END diff --git a/passes/pmgen/peepopt_muldiv_c.pmg b/passes/pmgen/peepopt_muldiv_c.pmg index fff4ad2a9c2..5841d396ea3 100644 --- a/passes/pmgen/peepopt_muldiv_c.pmg +++ b/passes/pmgen/peepopt_muldiv_c.pmg @@ -60,7 +60,7 @@ code reject; if (b_const.size() > 64) reject; - if (c_const.size() > 64) + if (c_const.size() + offset > 64) reject; // Check for potential mult overflow diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index b07612f507b..6e2fabeebde 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -429,13 +429,6 @@ def process_pmgfile(f, filename): print(" }", file=f) print("", file=f) - print(" SigSpec remove_bottom_padding(SigSpec sig) {", file=f) - print(" int i = 0;", file=f) - print(" for (; i < sig.size() - 1 && sig[i] == State::S0; i++) {} ", file=f) - print(" return sig.extract(i, sig.size() - i);", file=f) - print(" }", file=f) - print("", file=f) - print(" void blacklist(Cell *cell) {", file=f) print(" if (cell != nullptr && blacklist_cells.insert(cell).second) {", file=f) print(" auto ptr = rollback_cache.find(cell);", file=f) From 8b08f81d192b085d200ed59b4d352c0b26a10b80 Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Thu, 19 Dec 2024 14:23:40 -0800 Subject: [PATCH 27/42] compress constant ratio --- passes/pmgen/peepopt_muldiv_c.pmg | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/passes/pmgen/peepopt_muldiv_c.pmg b/passes/pmgen/peepopt_muldiv_c.pmg index 5841d396ea3..67a4b4f4f16 100644 --- a/passes/pmgen/peepopt_muldiv_c.pmg +++ b/passes/pmgen/peepopt_muldiv_c.pmg @@ -47,13 +47,15 @@ code int offset = GetSize(div_a) - GetSize(mul_y); // Get properties and values of b_const and c_const - int b_const_width = mul->getParam(ID::B_WIDTH).as_int(); // b_const may be coming from the A port but it's an RTLIL invariant that A_SIGNED equals B_SIGNED bool b_const_signed = mul->getParam(ID::B_SIGNED).as_bool(); bool c_const_signed = div->getParam(ID::B_SIGNED).as_bool(); int b_const_int = b_const.as_int(b_const_signed); int c_const_int = c_const.as_int(c_const_signed); int b_const_int_shifted = b_const_int << offset; + // Calculate the constant and compress the width to fit the value + Const const_ratio = b_const_int_shifted / c_const_int; + const_ratio.compress(b_const_signed | c_const_signed); // Integer values should be lesser than 64 bits if (mul->getParam(ID::B_WIDTH).size() > 64) @@ -77,7 +79,7 @@ code reject; // Rewire to only keep multiplier - mul->setPort(\B, Const(b_const_int_shifted / c_const_int, b_const_width)); + mul->setPort(\B, const_ratio); mul->setPort(\Y, div_y); // Remove divider From 8687e5f4fb2cce36c61df1097d48e5f336277a02 Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Thu, 19 Dec 2024 14:24:25 -0800 Subject: [PATCH 28/42] compress constant ratio --- passes/pmgen/peepopt_muldiv_c.pmg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/pmgen/peepopt_muldiv_c.pmg b/passes/pmgen/peepopt_muldiv_c.pmg index 67a4b4f4f16..01722d29adc 100644 --- a/passes/pmgen/peepopt_muldiv_c.pmg +++ b/passes/pmgen/peepopt_muldiv_c.pmg @@ -54,7 +54,7 @@ code int c_const_int = c_const.as_int(c_const_signed); int b_const_int_shifted = b_const_int << offset; // Calculate the constant and compress the width to fit the value - Const const_ratio = b_const_int_shifted / c_const_int; + Const const_ratio = b_const_int_shifted / c_const_int; const_ratio.compress(b_const_signed | c_const_signed); // Integer values should be lesser than 64 bits From 72aef58307a409b37576afbfbb09725ebe932c12 Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Thu, 19 Dec 2024 15:53:55 -0800 Subject: [PATCH 29/42] muxadd pass basic equiv_opt --- passes/pmgen/peepopt_muxadd.pmg | 55 +++++++++++-------- tests/peepopt/muxadd.ys | 94 +++++++++++++-------------------- 2 files changed, 71 insertions(+), 78 deletions(-) diff --git a/passes/pmgen/peepopt_muxadd.pmg b/passes/pmgen/peepopt_muxadd.pmg index b15183854a9..f286ee73f3f 100644 --- a/passes/pmgen/peepopt_muxadd.pmg +++ b/passes/pmgen/peepopt_muxadd.pmg @@ -30,9 +30,6 @@ code add_y add_a add_b add_a_ext if (nusers(add_y) != 2) reject; - // A and B can be interchanged - branch; - std::swap(add_a, add_b); endcode match mux @@ -47,23 +44,39 @@ code SigSpec mux_y = port(mux, \Y); SigSpec mux_a = port(mux, \A); SigSpec mux_b = port(mux, \B); - // Prevent multiple branches to edit the same pair of mux/add - if (mux_b == add_y || mux_a == add_y) { - // Create new mid wire - SigSpec mid = module->addWire(NEW_ID, GetSize(add_b)); - // Rewire - add->setPort(\B, mid); - add->setPort(\A, add_a); - add->setPort(\Y, add_y); - mux->setPort(add_a_id, Const(State::S0, GetSize(add_b))); - mux->setPort(add_b_id, add_b); - mux->setPort(\Y, mid); - module->connect(mux_y, add_y); - // Log, fixup, accept - log("muxadd pattern in %s: mux=%s, add=%s\n", log_id(module), log_id(mux), log_id(add)); - add->fixup_parameters(); - mux->fixup_parameters(); - did_something = true; - accept; + + // Create new mid wire + SigSpec mid = module->addWire(NEW_ID, GetSize(add_b)); + + // Rewire + + // Start by renaming the lhs of an eventual assign stmt where the rhs is the adder output (That is getting rewired). + // Renaming the signal allows equiv_opt to function as it would otherwize try to match the functionality witch would fail + // as the lhs signal has indeed changed function. + std::string adder_y_name = add_y.as_wire()->name.c_str(); + for (auto it = module->connections().begin(); it != module->connections().end(); ++it) { + RTLIL::SigSpec rhs = it->second; + const std::string& rhs_name = rhs.as_wire()->name.c_str(); + if (rhs_name == adder_y_name) { + RTLIL::SigSpec lhs = it->first; + const std::string& lhs_name = lhs.as_wire()->name.c_str(); + module->rename(lhs_name, module->uniquify("$" + lhs_name)); + break; + } } + + add->setPort(\B, mid); + add->setPort(\A, add_a); + add->setPort(\Y, add_y); + mux->setPort(add_a_id, Const(State::S0, GetSize(add_b))); + mux->setPort(add_b_id, add_b); + mux->setPort(\Y, mid); + module->connect(mux_y, add_y); + // Log, fixup, accept + log("muxadd pattern in %s: mux=%s, add=%s\n", log_id(module), log_id(mux), log_id(add)); + add->fixup_parameters(); + mux->fixup_parameters(); + did_something = true; + accept; + endcode diff --git a/tests/peepopt/muxadd.ys b/tests/peepopt/muxadd.ys index bca3abdc876..c49bd7d028d 100644 --- a/tests/peepopt/muxadd.ys +++ b/tests/peepopt/muxadd.ys @@ -7,21 +7,35 @@ module top(a, b, s, y); input wire [3:0] b; input wire s; output wire [3:0] y; - assign y = s ? (a + b) : a; + + wire [3:0] ab = a + b; + assign y = s ? ab : a; endmodule EOF check -assert -copy top orig -cd top -peepopt +equiv_opt -assert peepopt +design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired -clean -purge -cd -miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x top orig miter -sat -verify -prove-asserts -show-ports -enable_undef miter - +log -pop +log -header "Test basic s?(a+b):a pattern gets transformed (a,b module inputs)" +log -push +design -reset +read_verilog < Date: Thu, 19 Dec 2024 16:18:30 -0800 Subject: [PATCH 30/42] log test header for debug --- tests/peepopt/muldiv_c.ys | 69 +++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/tests/peepopt/muldiv_c.ys b/tests/peepopt/muldiv_c.ys index 892f0b53348..d41dcfcf836 100644 --- a/tests/peepopt/muldiv_c.ys +++ b/tests/peepopt/muldiv_c.ys @@ -39,8 +39,9 @@ select -assert-any t:$div design -reset - -# Basic pattern transformed: (a * b) / c +log -pop +log -header "Basic pattern transformed: (a * b) / c" +log -push read_verilog < Date: Thu, 19 Dec 2024 16:37:06 -0800 Subject: [PATCH 31/42] Fix symmetry test --- passes/pmgen/peepopt_muldiv_c.pmg | 1 + 1 file changed, 1 insertion(+) diff --git a/passes/pmgen/peepopt_muldiv_c.pmg b/passes/pmgen/peepopt_muldiv_c.pmg index 01722d29adc..22ccb84b776 100644 --- a/passes/pmgen/peepopt_muldiv_c.pmg +++ b/passes/pmgen/peepopt_muldiv_c.pmg @@ -79,6 +79,7 @@ code reject; // Rewire to only keep multiplier + mul->setPort(\A, a); mul->setPort(\B, const_ratio); mul->setPort(\Y, div_y); From 4a28e0d39f0783468ac56002a3f31fe1dfaa3bcc Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Thu, 19 Dec 2024 21:35:59 -0800 Subject: [PATCH 32/42] Pass all muldiv tests --- passes/pmgen/peepopt_muldiv_c.pmg | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/passes/pmgen/peepopt_muldiv_c.pmg b/passes/pmgen/peepopt_muldiv_c.pmg index 22ccb84b776..f1fd49b1dbd 100644 --- a/passes/pmgen/peepopt_muldiv_c.pmg +++ b/passes/pmgen/peepopt_muldiv_c.pmg @@ -53,8 +53,34 @@ code int b_const_int = b_const.as_int(b_const_signed); int c_const_int = c_const.as_int(c_const_signed); int b_const_int_shifted = b_const_int << offset; - // Calculate the constant and compress the width to fit the value - Const const_ratio = b_const_int_shifted / c_const_int; + + // Helper Lambdas for 2's complement math + auto sign2sComplement = [](auto value, int numBits) { + if (value & (1 << (numBits - 1))) { + return -1; + } else { + return 1; + } + }; + + auto twosComplement = [](auto value, int numBits) { + if (value & (1 << (numBits - 1))) { + return (~value) + 1; // Invert bits before adding 1 + } else { + return value; + } + }; + // 2's complement convertion + if (b_const_signed) + b_const_int = sign2sComplement(b_const_int, b_const.size()) * twosComplement(b_const_int, b_const.size()); + if (c_const_signed) + c_const_int = sign2sComplement(c_const_int, c_const.size()) * twosComplement(c_const_int, c_const.size()); + // Calculate the constant and compress the width to fit the value + Const const_ratio; + if (c_const_int == 0) + // Avoid division by zero + reject; + const_ratio = b_const_int_shifted / c_const_int; const_ratio.compress(b_const_signed | c_const_signed); // Integer values should be lesser than 64 bits From b6d079bb621e7a97f8d630816e7731afe44a195a Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Fri, 20 Dec 2024 09:32:20 -0800 Subject: [PATCH 33/42] Overflow test fix --- passes/pmgen/peepopt_muldiv_c.pmg | 6 +++++- tests/peepopt/muldiv_c.ys | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/passes/pmgen/peepopt_muldiv_c.pmg b/passes/pmgen/peepopt_muldiv_c.pmg index f1fd49b1dbd..81347e8d49a 100644 --- a/passes/pmgen/peepopt_muldiv_c.pmg +++ b/passes/pmgen/peepopt_muldiv_c.pmg @@ -77,9 +77,13 @@ code c_const_int = sign2sComplement(c_const_int, c_const.size()) * twosComplement(c_const_int, c_const.size()); // Calculate the constant and compress the width to fit the value Const const_ratio; + Const b_const_actual; if (c_const_int == 0) // Avoid division by zero reject; + b_const_actual = b_const_int_shifted; + b_const_actual.compress(b_const_signed); + const_ratio = b_const_int_shifted / c_const_int; const_ratio.compress(b_const_signed | c_const_signed); @@ -92,7 +96,7 @@ code reject; // Check for potential mult overflow - if (b_const.size() + a.size() > mul_y.size()) { + if (b_const_actual.size() + a.size() > mul_y.size()) { reject; } diff --git a/tests/peepopt/muldiv_c.ys b/tests/peepopt/muldiv_c.ys index d41dcfcf836..62777caabc6 100644 --- a/tests/peepopt/muldiv_c.ys +++ b/tests/peepopt/muldiv_c.ys @@ -268,7 +268,7 @@ module top( output [7:0] y, ); wire [6:0] mul; - assign mul = a * 4'd4; + assign mul = a * 4'd8; assign y = mul / 8'd2; endmodule EOT @@ -278,6 +278,7 @@ select -assert-count 1 t:$mul select -assert-count 1 t:$div design -reset + log -pop log -header "No transform when (a*b) and x/c fitting criteria but not connected (x != a*b)" log -push From b1930e9fe3c199ecb8410b335145cb788278334c Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Fri, 20 Dec 2024 09:33:42 -0800 Subject: [PATCH 34/42] Overflow test fix --- passes/pmgen/peepopt_muldiv_c.pmg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/pmgen/peepopt_muldiv_c.pmg b/passes/pmgen/peepopt_muldiv_c.pmg index 81347e8d49a..fc46afcef97 100644 --- a/passes/pmgen/peepopt_muldiv_c.pmg +++ b/passes/pmgen/peepopt_muldiv_c.pmg @@ -75,14 +75,14 @@ code b_const_int = sign2sComplement(b_const_int, b_const.size()) * twosComplement(b_const_int, b_const.size()); if (c_const_signed) c_const_int = sign2sComplement(c_const_int, c_const.size()) * twosComplement(c_const_int, c_const.size()); - // Calculate the constant and compress the width to fit the value + // Calculate the constant and compress the width to fit the value Const const_ratio; Const b_const_actual; if (c_const_int == 0) // Avoid division by zero reject; b_const_actual = b_const_int_shifted; - b_const_actual.compress(b_const_signed); + b_const_actual.compress(b_const_signed); const_ratio = b_const_int_shifted / c_const_int; const_ratio.compress(b_const_signed | c_const_signed); From 7ce046053b4cd978b362c860fdf3c62849069747 Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Fri, 20 Dec 2024 12:03:53 -0800 Subject: [PATCH 35/42] All tests pass --- passes/pmgen/peepopt_muxadd.pmg | 65 ++++++++++++++++++++++++--------- tests/peepopt/muxadd.ys | 4 +- 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/passes/pmgen/peepopt_muxadd.pmg b/passes/pmgen/peepopt_muxadd.pmg index f286ee73f3f..27aa2cda36f 100644 --- a/passes/pmgen/peepopt_muxadd.pmg +++ b/passes/pmgen/peepopt_muxadd.pmg @@ -3,11 +3,12 @@ pattern muxadd // Authored by Akash Levy and Alain Dargelas of Silimate, Inc. under ISC license. // Transforms add->mux into mux->add: // y = s ? (a + b) : a ===> y = a + (s ? b : 0) -// +// or +// y = s ? a : (a + b) ===> y = a + (s ? 0 : b) -state add_a add_b add_y add_a_ext +state add_a add_b add_y add_a_ext mux_a mux_b mux_y state add_a_signed -state add_a_id add_b_id +state add_a_id add_b_id mux_a_id mux_b_id match add // Select adder @@ -32,28 +33,36 @@ code add_y add_a add_b add_a_ext endcode -match mux +match mux // Select mux of form s ? (a + b) : a, allow leading 0s when A_WIDTH != Y_WIDTH + // or s ? a : (a + b) select mux->type == $mux - index port(mux, \A) === add_a_ext - index port(mux, \B) === add_y + choice AB {\A, \B} + define BA (AB == \A ? \B : \A) + set mux_y port(mux, \Y) + set mux_a port(mux, AB) + set mux_b port(mux, BA) + set mux_a_id AB + set mux_b_id BA + index port(mux, AB) === add_a_ext + index port(mux, BA) === add_y endmatch -code +code add_y add_a add_b add_a_ext add_a_id add_b_id mux_y mux_a mux_b mux_a_id mux_b_id // Get mux signal - SigSpec mux_y = port(mux, \Y); - SigSpec mux_a = port(mux, \A); - SigSpec mux_b = port(mux, \B); + SigSpec mid; + std::string adder_y_name; + if (add_y.is_wire()) + adder_y_name = add_y.as_wire()->name.c_str(); + else + adder_y_name = add_y.as_string(); - // Create new mid wire - SigSpec mid = module->addWire(NEW_ID, GetSize(add_b)); - // Rewire // Start by renaming the lhs of an eventual assign stmt where the rhs is the adder output (That is getting rewired). // Renaming the signal allows equiv_opt to function as it would otherwize try to match the functionality witch would fail // as the lhs signal has indeed changed function. - std::string adder_y_name = add_y.as_wire()->name.c_str(); + // Adder output could be assigned... for (auto it = module->connections().begin(); it != module->connections().end(); ++it) { RTLIL::SigSpec rhs = it->second; const std::string& rhs_name = rhs.as_wire()->name.c_str(); @@ -64,12 +73,32 @@ code break; } } + // ...or the port name could be a wire name + if (add_y.is_wire()) { + if (adder_y_name.size()) { + if (adder_y_name[0] != '$') { + module->rename(adder_y_name, module->uniquify("$" + adder_y_name)); + } + } + } else { + for (auto chunk : add_y.chunks()) { + if (chunk.is_wire()) { + const std::string& name = chunk.wire->name.c_str(); + if (name[0] != '$') { + module->rename(name, module->uniquify("$" + name)); + } + } + } + } + + // Create new mid wire + mid = module->addWire(NEW_ID, GetSize(add_b)); - add->setPort(\B, mid); - add->setPort(\A, add_a); + add->setPort(add_b_id, mid); + add->setPort(add_a_id, add_a); add->setPort(\Y, add_y); - mux->setPort(add_a_id, Const(State::S0, GetSize(add_b))); - mux->setPort(add_b_id, add_b); + mux->setPort(mux_a_id, Const(State::S0, GetSize(add_b))); + mux->setPort(mux_b_id, add_b); mux->setPort(\Y, mid); module->connect(mux_y, add_y); // Log, fixup, accept diff --git a/tests/peepopt/muxadd.ys b/tests/peepopt/muxadd.ys index c49bd7d028d..77f1e1719e8 100644 --- a/tests/peepopt/muxadd.ys +++ b/tests/peepopt/muxadd.ys @@ -244,7 +244,7 @@ wreduce opt_clean equiv_opt -assert peepopt design -load postopt -select -assert-none t:$add %co1 %a w:y %i +select -assert-any t:$add %co1 %a w:y %i log -pop log -header "Test transform when (a+b) wider than a, adder’s a input is signed, a sign-extended on the muxes input" @@ -265,7 +265,7 @@ wreduce opt_clean equiv_opt -assert peepopt design -load postopt -select -assert-none t:$add %co1 %a w:y %i +select -assert-any t:$add %co1 %a w:y %i log -pop log -header "Test transform when pattern is s?a:(a+b)" From 095bf92bdcb4d0d6a1258c54f574b59296b30782 Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Fri, 20 Dec 2024 12:04:37 -0800 Subject: [PATCH 36/42] All tests pass --- passes/pmgen/peepopt_muxadd.pmg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/pmgen/peepopt_muxadd.pmg b/passes/pmgen/peepopt_muxadd.pmg index 27aa2cda36f..4dbab697ca8 100644 --- a/passes/pmgen/peepopt_muxadd.pmg +++ b/passes/pmgen/peepopt_muxadd.pmg @@ -74,7 +74,7 @@ code add_y add_a add_b add_a_ext add_a_id add_b_id mux_y mux_a mux_b mux_a_id m } } // ...or the port name could be a wire name - if (add_y.is_wire()) { + if (add_y.is_wire()) { if (adder_y_name.size()) { if (adder_y_name[0] != '$') { module->rename(adder_y_name, module->uniquify("$" + adder_y_name)); From cd503d4c0f48a9841628f256de7bd8823aafd083 Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Fri, 20 Dec 2024 12:05:35 -0800 Subject: [PATCH 37/42] All tests pass --- passes/pmgen/peepopt_muxadd.pmg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/pmgen/peepopt_muxadd.pmg b/passes/pmgen/peepopt_muxadd.pmg index 4dbab697ca8..f534dd42df5 100644 --- a/passes/pmgen/peepopt_muxadd.pmg +++ b/passes/pmgen/peepopt_muxadd.pmg @@ -91,8 +91,8 @@ code add_y add_a add_b add_a_ext add_a_id add_b_id mux_y mux_a mux_b mux_a_id m } } - // Create new mid wire - mid = module->addWire(NEW_ID, GetSize(add_b)); + // Create new mid wire + mid = module->addWire(NEW_ID, GetSize(add_b)); add->setPort(add_b_id, mid); add->setPort(add_a_id, add_a); From 39ff4425fe8f631fc1ea871acd2c747c1aba0d6f Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Fri, 20 Dec 2024 13:21:25 -0800 Subject: [PATCH 38/42] Small muxadd comments --- passes/pmgen/peepopt_muxadd.pmg | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/passes/pmgen/peepopt_muxadd.pmg b/passes/pmgen/peepopt_muxadd.pmg index f534dd42df5..931aa0701fb 100644 --- a/passes/pmgen/peepopt_muxadd.pmg +++ b/passes/pmgen/peepopt_muxadd.pmg @@ -13,12 +13,18 @@ state add_a_id add_b_id mux_a_id mux_b_id match add // Select adder select add->type == $add + + // Set ports, allowing A and B to be swapped choice A {\A, \B} define B (A == \A ? \B : \A) - set add_y port(add, \Y) set add_a port(add, A) set add_b port(add, B) + set add_y port(add, \Y) + + // Get signedness set add_a_signed param(add, (A == \A) ? \A_SIGNED : \B_SIGNED) + + // Choice ids set add_a_id A set add_b_id B endmatch @@ -27,15 +33,15 @@ code add_y add_a add_b add_a_ext // Get adder signals add_a_ext = SigSpec(port(add, add_a_id)); add_a_ext.extend_u0(GetSize(add_y), add_a_signed.as_bool()); + // Fanout of each adder Y bit should be 1 (no bit-split) if (nusers(add_y) != 2) reject; - endcode match mux - // Select mux of form s ? (a + b) : a, allow leading 0s when A_WIDTH != Y_WIDTH - // or s ? a : (a + b) + // Select mux of form: s ? (a + b) : a + // Allow leading 0s when A_WIDTH != Y_WIDTH or s ? a : (a + b) select mux->type == $mux choice AB {\A, \B} define BA (AB == \A ? \B : \A) @@ -56,13 +62,14 @@ code add_y add_a add_b add_a_ext add_a_id add_b_id mux_y mux_a mux_b mux_a_id m adder_y_name = add_y.as_wire()->name.c_str(); else adder_y_name = add_y.as_string(); - - // Rewire - // Start by renaming the lhs of an eventual assign stmt where the rhs is the adder output (That is getting rewired). - // Renaming the signal allows equiv_opt to function as it would otherwize try to match the functionality witch would fail - // as the lhs signal has indeed changed function. - // Adder output could be assigned... + // Start by renaming the LHS of an eventual assign statement + // where the RHS is the adder output (that is getting rewired). + // Renaming the signal allows equiv_opt to function as it would + // otherwise try to match the functionality which would fail + // as the LHS signal has indeed changed function. + + // Adder output could be assigned for (auto it = module->connections().begin(); it != module->connections().end(); ++it) { RTLIL::SigSpec rhs = it->second; const std::string& rhs_name = rhs.as_wire()->name.c_str(); @@ -73,7 +80,7 @@ code add_y add_a add_b add_a_ext add_a_id add_b_id mux_y mux_a mux_b mux_a_id m break; } } - // ...or the port name could be a wire name + // Alternatively, the port name could be a wire name if (add_y.is_wire()) { if (adder_y_name.size()) { if (adder_y_name[0] != '$') { @@ -94,6 +101,7 @@ code add_y add_a add_b add_a_ext add_a_id add_b_id mux_y mux_a mux_b mux_a_id m // Create new mid wire mid = module->addWire(NEW_ID, GetSize(add_b)); + // Connect ports add->setPort(add_b_id, mid); add->setPort(add_a_id, add_a); add->setPort(\Y, add_y); @@ -101,11 +109,11 @@ code add_y add_a add_b add_a_ext add_a_id add_b_id mux_y mux_a mux_b mux_a_id m mux->setPort(mux_b_id, add_b); mux->setPort(\Y, mid); module->connect(mux_y, add_y); + // Log, fixup, accept log("muxadd pattern in %s: mux=%s, add=%s\n", log_id(module), log_id(mux), log_id(add)); add->fixup_parameters(); mux->fixup_parameters(); did_something = true; accept; - endcode From 832c877388051901b6b9cb915e341e08e0b78e2f Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Fri, 20 Dec 2024 13:28:48 -0800 Subject: [PATCH 39/42] Smallfixes --- passes/pmgen/peepopt_muldiv_c.pmg | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/passes/pmgen/peepopt_muldiv_c.pmg b/passes/pmgen/peepopt_muldiv_c.pmg index fc46afcef97..5488dd7a1a6 100644 --- a/passes/pmgen/peepopt_muldiv_c.pmg +++ b/passes/pmgen/peepopt_muldiv_c.pmg @@ -47,14 +47,15 @@ code int offset = GetSize(div_a) - GetSize(mul_y); // Get properties and values of b_const and c_const - // b_const may be coming from the A port but it's an RTLIL invariant that A_SIGNED equals B_SIGNED + // b_const may be coming from the A port + // But it is an RTLIL invariant that A_SIGNED equals B_SIGNED bool b_const_signed = mul->getParam(ID::B_SIGNED).as_bool(); bool c_const_signed = div->getParam(ID::B_SIGNED).as_bool(); int b_const_int = b_const.as_int(b_const_signed); int c_const_int = c_const.as_int(c_const_signed); int b_const_int_shifted = b_const_int << offset; - // Helper Lambdas for 2's complement math + // Helper lambdas for two's complement math auto sign2sComplement = [](auto value, int numBits) { if (value & (1 << (numBits - 1))) { return -1; @@ -62,15 +63,15 @@ code return 1; } }; - auto twosComplement = [](auto value, int numBits) { if (value & (1 << (numBits - 1))) { - return (~value) + 1; // Invert bits before adding 1 + return (~value) + 1; // invert bits before adding 1 } else { return value; } }; - // 2's complement convertion + + // Two's complement conversion if (b_const_signed) b_const_int = sign2sComplement(b_const_int, b_const.size()) * twosComplement(b_const_int, b_const.size()); if (c_const_signed) @@ -78,8 +79,8 @@ code // Calculate the constant and compress the width to fit the value Const const_ratio; Const b_const_actual; + // Avoid division by zero if (c_const_int == 0) - // Avoid division by zero reject; b_const_actual = b_const_int_shifted; b_const_actual.compress(b_const_signed); @@ -88,6 +89,7 @@ code const_ratio.compress(b_const_signed | c_const_signed); // Integer values should be lesser than 64 bits + // This is because we are using C++ types, and int is 64 bits if (mul->getParam(ID::B_WIDTH).size() > 64) reject; if (b_const.size() > 64) @@ -95,10 +97,9 @@ code if (c_const.size() + offset > 64) reject; - // Check for potential mult overflow - if (b_const_actual.size() + a.size() > mul_y.size()) { + // Check for potential multiplier overflow + if (b_const_actual.size() + a.size() > mul_y.size()) reject; - } // Check that there are only zeros before offset if (offset < 0 || !div_a.extract(0, offset).is_fully_zero()) From b9c3666433e142f7f6233290ad5d341b5ce7d0c2 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Fri, 20 Dec 2024 13:51:41 -0800 Subject: [PATCH 40/42] GetSize, fix int sizing thing, add .gitignore --- passes/pmgen/peepopt_muldiv_c.pmg | 17 +++++++++-------- passes/pmgen/peepopt_muxadd.pmg | 2 +- tests/peepopt/.gitignore | 1 + 3 files changed, 11 insertions(+), 9 deletions(-) create mode 100644 tests/peepopt/.gitignore diff --git a/passes/pmgen/peepopt_muldiv_c.pmg b/passes/pmgen/peepopt_muldiv_c.pmg index 5488dd7a1a6..2cf9b028b5c 100644 --- a/passes/pmgen/peepopt_muldiv_c.pmg +++ b/passes/pmgen/peepopt_muldiv_c.pmg @@ -73,9 +73,9 @@ code // Two's complement conversion if (b_const_signed) - b_const_int = sign2sComplement(b_const_int, b_const.size()) * twosComplement(b_const_int, b_const.size()); + b_const_int = sign2sComplement(b_const_int, GetSize(b_const)) * twosComplement(b_const_int, GetSize(b_const)); if (c_const_signed) - c_const_int = sign2sComplement(c_const_int, c_const.size()) * twosComplement(c_const_int, c_const.size()); + c_const_int = sign2sComplement(c_const_int, GetSize(c_const)) * twosComplement(c_const_int, GetSize(c_const)); // Calculate the constant and compress the width to fit the value Const const_ratio; Const b_const_actual; @@ -88,17 +88,18 @@ code const_ratio = b_const_int_shifted / c_const_int; const_ratio.compress(b_const_signed | c_const_signed); - // Integer values should be lesser than 64 bits - // This is because we are using C++ types, and int is 64 bits - if (mul->getParam(ID::B_WIDTH).size() > 64) + // Integer values should be lesser than 32 bits + // This is because we are using C++ types, and int is 32 bits + // FIXME: use long long or BigInteger to make pass work with >32 bits + if (GetSize(mul->getParam(ID::B_WIDTH)) > 32) reject; - if (b_const.size() > 64) + if (GetSize(b_const) > 32) reject; - if (c_const.size() + offset > 64) + if (GetSize(c_const) + offset > 32) reject; // Check for potential multiplier overflow - if (b_const_actual.size() + a.size() > mul_y.size()) + if (GetSize(b_const_actual) + GetSize(a) > GetSize(mul_y)) reject; // Check that there are only zeros before offset diff --git a/passes/pmgen/peepopt_muxadd.pmg b/passes/pmgen/peepopt_muxadd.pmg index 931aa0701fb..84eb7ece546 100644 --- a/passes/pmgen/peepopt_muxadd.pmg +++ b/passes/pmgen/peepopt_muxadd.pmg @@ -82,7 +82,7 @@ code add_y add_a add_b add_a_ext add_a_id add_b_id mux_y mux_a mux_b mux_a_id m } // Alternatively, the port name could be a wire name if (add_y.is_wire()) { - if (adder_y_name.size()) { + if (GetSize(adder_y_name)) { if (adder_y_name[0] != '$') { module->rename(adder_y_name, module->uniquify("$" + adder_y_name)); } diff --git a/tests/peepopt/.gitignore b/tests/peepopt/.gitignore new file mode 100644 index 00000000000..50e13221d7a --- /dev/null +++ b/tests/peepopt/.gitignore @@ -0,0 +1 @@ +/*.log From 11e4446efe2189b864911827300f9c97c3195792 Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Fri, 20 Dec 2024 16:00:10 -0800 Subject: [PATCH 41/42] Fix nanoxplore meminit test --- passes/pmgen/peepopt_muxadd.pmg | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/passes/pmgen/peepopt_muxadd.pmg b/passes/pmgen/peepopt_muxadd.pmg index f534dd42df5..f9c23882adf 100644 --- a/passes/pmgen/peepopt_muxadd.pmg +++ b/passes/pmgen/peepopt_muxadd.pmg @@ -65,12 +65,16 @@ code add_y add_a add_b add_a_ext add_a_id add_b_id mux_y mux_a mux_b mux_a_id m // Adder output could be assigned... for (auto it = module->connections().begin(); it != module->connections().end(); ++it) { RTLIL::SigSpec rhs = it->second; - const std::string& rhs_name = rhs.as_wire()->name.c_str(); - if (rhs_name == adder_y_name) { - RTLIL::SigSpec lhs = it->first; - const std::string& lhs_name = lhs.as_wire()->name.c_str(); - module->rename(lhs_name, module->uniquify("$" + lhs_name)); - break; + if (rhs.is_wire()) { + const std::string& rhs_name = rhs.as_wire()->name.c_str(); + if (rhs_name == adder_y_name) { + RTLIL::SigSpec lhs = it->first; + if (lhs.is_wire()) { + const std::string& lhs_name = lhs.as_wire()->name.c_str(); + module->rename(lhs_name, module->uniquify("$" + lhs_name)); + break; + } + } } } // ...or the port name could be a wire name From 41a7c7244b7ad128f949bae43324920389281298 Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Fri, 20 Dec 2024 16:38:09 -0800 Subject: [PATCH 42/42] muxadd breaks Quicklogic dsp inference, make it optional --- passes/pmgen/peepopt.cc | 15 +++++++++++---- tests/peepopt/muxadd.ys | 41 +++++++++++++++++++++++------------------ 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index fe4fc89e0f6..94c4a6c14cc 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -45,8 +45,6 @@ struct PeepoptPass : public Pass { log("\n"); log("This pass employs the following rules by default:\n"); log("\n"); - log(" * muxadd - Replace S?(A+B):A with A+(S?B:0)\n"); - log("\n"); log(" * muldiv - Replace (A*B)/B with A\n"); log("\n"); log(" * muldiv_c - Replace (A*B)/C with A*(B/C) when C is a const divisible by B.\n"); @@ -70,13 +68,17 @@ struct PeepoptPass : public Pass { log(" based pattern to prevent combinational paths from the\n"); log(" output to the enable input after running clk2fflogic.\n"); log("\n"); + log("If -withmuxadd is specified it adds the following rule:\n"); + log("\n"); + log(" * muxadd - Replace S?(A+B):A with A+(S?B:0)\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n"); bool formalclk = false; - + bool withmuxadd = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -84,6 +86,10 @@ struct PeepoptPass : public Pass { formalclk = true; continue; } + if (args[argidx] == "-withmuxadd") { + withmuxadd = true; + continue; + } break; } extra_args(args, argidx, design); @@ -113,7 +119,8 @@ struct PeepoptPass : public Pass { pm.run_shiftmul_left(); pm.run_muldiv(); pm.run_muldiv_c(); - pm.run_muxadd(); + if (withmuxadd) + pm.run_muxadd(); } } } diff --git a/tests/peepopt/muxadd.ys b/tests/peepopt/muxadd.ys index 77f1e1719e8..04d9a5f74ce 100644 --- a/tests/peepopt/muxadd.ys +++ b/tests/peepopt/muxadd.ys @@ -1,3 +1,8 @@ + + +log -header "Test basic s?(a+b):a pattern gets transformed (a,b module inputs)" +log -push +design -reset log -header "Test basic s?(a+b):a pattern gets transformed (a,b module inputs)" log -push design -reset @@ -13,7 +18,7 @@ module top(a, b, s, y); endmodule EOF check -assert -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired log -pop @@ -31,7 +36,7 @@ module top(a, b, s, y); endmodule EOF check -assert -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired log -pop @@ -51,7 +56,7 @@ module top(a, b, s, y); endmodule EOF check -assert -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired log -pop @@ -72,7 +77,7 @@ module top(a_, b, s, y); endmodule EOF check -assert -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired log -pop @@ -96,7 +101,7 @@ module top(a, b_, f, s, y_); endmodule EOF check -assert -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired log -pop @@ -116,7 +121,7 @@ module top(a, b, ab, s, y); endmodule EOF check -assert -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-none t:$add %co1 %a w:y %i log -pop @@ -136,7 +141,7 @@ module top(a, b, s, y, z); endmodule EOF check -assert -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-none t:$add %co1 %a w:y %i @@ -157,7 +162,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-none t:$add %co1 %a w:y %i @@ -178,7 +183,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-none t:$add %co1 %a w:y %i @@ -199,7 +204,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-none t:$add %co1 %a w:y %i @@ -221,7 +226,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-none t:$add %co1 %a w:y %i @@ -242,7 +247,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-any t:$add %co1 %a w:y %i @@ -263,7 +268,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-any t:$add %co1 %a w:y %i @@ -284,7 +289,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired @@ -305,7 +310,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired @@ -326,7 +331,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired @@ -347,7 +352,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired @@ -368,6 +373,6 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt +equiv_opt -assert peepopt -withmuxadd design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired