diff --git a/passes/pmgen/peepopt_muxadd.pmg b/passes/pmgen/peepopt_muxadd.pmg index f286ee73f3f..f534dd42df5 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)"