From fa97c4830ef31bb6851f9a9166708d0d40af1cf2 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Thu, 6 Mar 2025 16:57:47 -0800 Subject: [PATCH] Generalize muxadd to muxorder --- passes/opt/Makefile.inc | 2 +- passes/opt/peepopt.cc | 16 +-- passes/opt/peepopt_muxadd.pmg | 128 -------------------- passes/opt/peepopt_muxorder.pmg | 143 +++++++++++++++++++++++ tests/peepopt/{muxadd.ys => muxorder.ys} | 36 +++--- 5 files changed, 171 insertions(+), 154 deletions(-) delete mode 100644 passes/opt/peepopt_muxadd.pmg create mode 100644 passes/opt/peepopt_muxorder.pmg rename tests/peepopt/{muxadd.ys => muxorder.ys} (91%) diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc index 47667fba3..9dd90072d 100644 --- a/passes/opt/Makefile.inc +++ b/passes/opt/Makefile.inc @@ -32,7 +32,7 @@ PEEPOPT_PATTERN += passes/opt/peepopt_shiftmul_left.pmg PEEPOPT_PATTERN += passes/opt/peepopt_shiftadd.pmg PEEPOPT_PATTERN += passes/opt/peepopt_muldiv.pmg PEEPOPT_PATTERN += passes/opt/peepopt_muldiv_c.pmg -PEEPOPT_PATTERN += passes/opt/peepopt_muxadd.pmg +PEEPOPT_PATTERN += passes/opt/peepopt_muxorder.pmg PEEPOPT_PATTERN += passes/opt/peepopt_formal_clockgateff.pmg passes/opt/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) diff --git a/passes/opt/peepopt.cc b/passes/opt/peepopt.cc index 2917d3103..8448b0485 100644 --- a/passes/opt/peepopt.cc +++ b/passes/opt/peepopt.cc @@ -68,9 +68,11 @@ 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("If -muxorder is specified it adds the following rule:\n"); log("\n"); - log(" * muxadd - Replace S?(A+B):A with A+(S?B:0)\n"); + log(" * muxorder - Replace S?(A OP B):A with A OP (S?B:I) where I is identity of OP\n"); + log(" Ex 1: S?(A + B):A ---> A + (S?B:0)\n"); + log(" Ex 2: S?(A * B):A ---> A & (S?B:1)\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) override @@ -78,7 +80,7 @@ struct PeepoptPass : public Pass { log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n"); bool formalclk = false; - bool withmuxadd = false; + bool muxorder = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -86,8 +88,8 @@ struct PeepoptPass : public Pass { formalclk = true; continue; } - if (args[argidx] == "-withmuxadd") { - withmuxadd = true; + if (args[argidx] == "-muxorder") { + muxorder = true; continue; } break; @@ -119,8 +121,8 @@ struct PeepoptPass : public Pass { pm.run_shiftmul_left(); pm.run_muldiv(); pm.run_muldiv_c(); - if (withmuxadd) - pm.run_muxadd(); + if (muxorder) + pm.run_muxorder(); } } } diff --git a/passes/opt/peepopt_muxadd.pmg b/passes/opt/peepopt_muxadd.pmg deleted file mode 100644 index 90a6a0932..000000000 --- a/passes/opt/peepopt_muxadd.pmg +++ /dev/null @@ -1,128 +0,0 @@ -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 mux_a mux_b mux_y -state add_a_signed -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_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 - -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->type == $mux - 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 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 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(); - - // 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; - 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; - } - } - } - } - // Alternatively, the port name could be a wire name - if (add_y.is_wire()) { - if (GetSize(adder_y_name)) { - 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 - Cell *cell = mux; - mid = module->addWire(NEW_ID2_SUFFIX("mid"), GetSize(add_b)); - - // Connect ports - add->setPort(add_b_id, mid); - add->setPort(add_a_id, add_a); - add->setPort(\Y, add_y); - cell = add; - module->rename(add, NEW_ID2_SUFFIX("rot")); - mux->setPort(mux_a_id, Const(State::S0, GetSize(add_b))); - mux->setPort(mux_b_id, add_b); - mux->setPort(\Y, mid); - cell = mux; - module->rename(mux, NEW_ID2_SUFFIX("rot")); - 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/passes/opt/peepopt_muxorder.pmg b/passes/opt/peepopt_muxorder.pmg new file mode 100644 index 000000000..d67d2181c --- /dev/null +++ b/passes/opt/peepopt_muxorder.pmg @@ -0,0 +1,143 @@ +pattern muxorder +// +// Authored by Akash Levy and Alain Dargelas of Silimate, Inc. under ISC license. +// +// Transforms OP->mux into mux->OP using identity input for two-input OP. Example: +// y = s ? (a + b) : a ===> y = a + (s ? b : 0) +// or +// y = s ? a : (a + b) ===> y = a + (s ? 0 : b) +// +// Supported OPs: +, *, &, |, ^, ^~ +// + +state op_a op_b op_y op_a_ext mux_a mux_b mux_y +state op_a_signed +state op_a_id op_b_id mux_a_id mux_b_id + +match op + // Select OP + select op->type.in($add, $mul, $and, $or, $xor, $xnor) + + // Set ports, allowing A and B to be swapped + choice A {\A, \B} + define B (A == \A ? \B : \A) + set op_a port(op, A) + set op_b port(op, B) + set op_y port(op, \Y) + + // Get signedness + set op_a_signed param(op, (A == \A) ? \A_SIGNED : \B_SIGNED) + + // Choice ids + set op_a_id A + set op_b_id B +endmatch + +code op_y op_a op_b op_a_ext + // Get OP signals + op_a_ext = SigSpec(port(op, op_a_id)); + op_a_ext.extend_u0(GetSize(op_y), op_a_signed.as_bool()); + + // Fanout of each OP Y bit should be 1 (no bit-split) + if (nusers(op_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->type == $mux + 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) === op_a_ext + index port(mux, BA) === op_y +endmatch + +code op_y op_a op_b op_a_ext op_a_id op_b_id mux_y mux_a mux_b mux_a_id mux_b_id + // Get mux signal + SigSpec mid; + std::string op_y_name; + if (op_y.is_wire()) + op_y_name = op_y.as_wire()->name.c_str(); + else + op_y_name = op_y.as_string(); + + // Start by renaming the LHS of an eventual assign statement + // where the RHS is the OP 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. + + // OP output could be assigned + for (auto it = module->connections().begin(); it != module->connections().end(); ++it) { + RTLIL::SigSpec rhs = it->second; + if (rhs.is_wire()) { + const std::string& rhs_name = rhs.as_wire()->name.c_str(); + if (rhs_name == op_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; + } + } + } + } + // Alternatively, the port name could be a wire name + if (op_y.is_wire()) { + if (GetSize(op_y_name)) { + if (op_y_name[0] != '$') { + module->rename(op_y_name, module->uniquify("$" + op_y_name)); + } + } + } else { + for (auto chunk : op_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 + Cell *cell = mux; + mid = module->addWire(NEW_ID2_SUFFIX("mid"), GetSize(op_b)); + + // Determine identity input of operator + Const identity; + if (op->type.in($add, $or, $xor)) + identity = Const(0, GetSize(op_b)); + else if (op->type == $mul) + identity = Const(1, GetSize(op_b)); + else if (op->type.in($and, $xnor)) + identity = Const(State::S1, GetSize(op_b)); + else + log_assert(0); // invalid operator, should never happen + + // Connect ports + op->setPort(op_b_id, mid); + op->setPort(op_a_id, op_a); + op->setPort(\Y, op_y); + cell = op; + module->rename(op, NEW_ID2_SUFFIX("reord")); + mux->setPort(mux_a_id, identity); + mux->setPort(mux_b_id, op_b); + mux->setPort(\Y, mid); + cell = mux; + module->rename(mux, NEW_ID2_SUFFIX("reord")); + module->connect(mux_y, op_y); + + // Log, fixup, accept + log("muxorder pattern in %s: mux=%s, op=%s, optype=%s\n", log_id(module), log_id(mux), log_id(op), log_id(op->type)); + op->fixup_parameters(); + mux->fixup_parameters(); + did_something = true; + accept; +endcode diff --git a/tests/peepopt/muxadd.ys b/tests/peepopt/muxorder.ys similarity index 91% rename from tests/peepopt/muxadd.ys rename to tests/peepopt/muxorder.ys index 04d9a5f74..c2d22af48 100644 --- a/tests/peepopt/muxadd.ys +++ b/tests/peepopt/muxorder.ys @@ -18,7 +18,7 @@ module top(a, b, s, y); endmodule EOF check -assert -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired log -pop @@ -36,7 +36,7 @@ module top(a, b, s, y); endmodule EOF check -assert -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired log -pop @@ -56,7 +56,7 @@ module top(a, b, s, y); endmodule EOF check -assert -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired log -pop @@ -77,7 +77,7 @@ module top(a_, b, s, y); endmodule EOF check -assert -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired log -pop @@ -101,7 +101,7 @@ module top(a, b_, f, s, y_); endmodule EOF check -assert -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired log -pop @@ -121,7 +121,7 @@ module top(a, b, ab, s, y); endmodule EOF check -assert -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-none t:$add %co1 %a w:y %i log -pop @@ -141,7 +141,7 @@ module top(a, b, s, y, z); endmodule EOF check -assert -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-none t:$add %co1 %a w:y %i @@ -162,7 +162,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-none t:$add %co1 %a w:y %i @@ -183,7 +183,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-none t:$add %co1 %a w:y %i @@ -204,7 +204,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-none t:$add %co1 %a w:y %i @@ -226,7 +226,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-none t:$add %co1 %a w:y %i @@ -247,7 +247,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-any t:$add %co1 %a w:y %i @@ -268,7 +268,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-any t:$add %co1 %a w:y %i @@ -289,7 +289,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired @@ -310,7 +310,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired @@ -331,7 +331,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired @@ -352,7 +352,7 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired @@ -373,6 +373,6 @@ EOF check -assert wreduce opt_clean -equiv_opt -assert peepopt -withmuxadd +equiv_opt -assert peepopt -muxorder design -load postopt select -assert-any t:$add %co1 %a w:y %i # assert adder rewired