From 83b095ab6ca294cb8ccd8504e5dcdae54841199a Mon Sep 17 00:00:00 2001 From: Anhijkt Date: Sun, 30 Mar 2025 15:43:41 +0300 Subject: [PATCH 1/3] opt_expr: optimize pow of 2 cells --- passes/opt/opt_expr.cc | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 62a0ffc48..5089959ae 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -1690,7 +1690,43 @@ skip_identity: else if (inA == inB) ACTION_DO(ID::Y, cell->getPort(ID::A)); } + if (cell->type == ID($pow) && cell->getPort(ID::A).is_fully_const() && !cell->parameters[ID::B_SIGNED].as_bool()) { + SigSpec sig_a = assign_map(cell->getPort(ID::A)); + SigSpec sig_y = assign_map(cell->getPort(ID::Y)); + int y_size = GetSize(sig_y); + unsigned int bits = unsigned(sig_a.as_int()); + int bit_count = 0; + for (; bits; bits >>= 1) + bit_count += (bits & 1); + + if (bit_count == 1) { + if (sig_a.as_int() == 2) { + log_debug("Replacing pow cell `%s' in module `%s' with left-shift\n", + cell->name.c_str(), module->name.c_str()); + cell->type = ID($shl); + cell->parameters[ID::A_WIDTH] = 1; + cell->setPort(ID::A, Const(1, 1)); + } + else { + log_debug("Replacing pow cell `%s' in module `%s' with multiply and left-shift\n", + cell->name.c_str(), module->name.c_str()); + cell->type = ID($mul); + cell->parameters[ID::A_SIGNED] = 0; + + int left_shift; + sig_a.is_onehot(&left_shift); + cell->setPort(ID::A, Const(left_shift, cell->parameters[ID::A_WIDTH].as_int())); + + SigSpec y_wire = module->addWire(NEW_ID, y_size); + cell->setPort(ID::Y, y_wire); + + module->addShl(NEW_ID, Const(1, 1), y_wire, sig_y); + } + did_something = true; + goto next_cell; + } + } if (!keepdc && cell->type == ID($mul)) { bool a_signed = cell->parameters[ID::A_SIGNED].as_bool(); From 6b5507139ecc8b0d5e71bf81ae077ff3f5258210 Mon Sep 17 00:00:00 2001 From: Anhijkt Date: Tue, 1 Apr 2025 20:37:22 +0300 Subject: [PATCH 2/3] opt_expr: requsted changes --- passes/opt/opt_expr.cc | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 5089959ae..9967c7753 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -1695,33 +1695,28 @@ skip_identity: SigSpec sig_y = assign_map(cell->getPort(ID::Y)); int y_size = GetSize(sig_y); - unsigned int bits = unsigned(sig_a.as_int()); - int bit_count = 0; - for (; bits; bits >>= 1) - bit_count += (bits & 1); + int bit_idx; + const auto onehot = sig_a.is_onehot(&bit_idx); - if (bit_count == 1) { - if (sig_a.as_int() == 2) { + if (onehot) { + if (bit_idx == 1) { log_debug("Replacing pow cell `%s' in module `%s' with left-shift\n", cell->name.c_str(), module->name.c_str()); cell->type = ID($shl); cell->parameters[ID::A_WIDTH] = 1; - cell->setPort(ID::A, Const(1, 1)); + cell->setPort(ID::A, Const(State::S1, 1)); } else { log_debug("Replacing pow cell `%s' in module `%s' with multiply and left-shift\n", cell->name.c_str(), module->name.c_str()); cell->type = ID($mul); cell->parameters[ID::A_SIGNED] = 0; - - int left_shift; - sig_a.is_onehot(&left_shift); - cell->setPort(ID::A, Const(left_shift, cell->parameters[ID::A_WIDTH].as_int())); + cell->setPort(ID::A, Const(bit_idx, cell->parameters[ID::A_WIDTH].as_int())); SigSpec y_wire = module->addWire(NEW_ID, y_size); cell->setPort(ID::Y, y_wire); - module->addShl(NEW_ID, Const(1, 1), y_wire, sig_y); + module->addShl(NEW_ID, Const(State::S1, 1), y_wire, sig_y); } did_something = true; goto next_cell; From c57cbfa8f9525ac230815ca9fffe751f0e63f2e7 Mon Sep 17 00:00:00 2001 From: Anhijkt Date: Tue, 1 Apr 2025 21:54:46 +0300 Subject: [PATCH 3/3] opt_expr: add test --- tests/opt/opt_pow.ys | 89 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 tests/opt/opt_pow.ys diff --git a/tests/opt/opt_pow.ys b/tests/opt/opt_pow.ys new file mode 100644 index 000000000..0fa2f88c7 --- /dev/null +++ b/tests/opt/opt_pow.ys @@ -0,0 +1,89 @@ +# Default power of two + +design -reset + +read_rtlil << EOT +autoidx 3 +attribute \cells_not_processed 1 +attribute \src ":1.1-3.10" +module \top + attribute \src ":2.17-2.20" + wire width 32 $add$:2$1_Y + attribute \src ":2.12-2.21" + wire width 32 signed $pow$:2$2_Y + attribute \src ":1.29-1.30" + wire width 15 input 1 \a + attribute \src ":1.51-1.52" + wire width 32 output 2 \b + attribute \src ":2.17-2.20" + cell $add $add$:2$1 + parameter \A_SIGNED 0 + parameter \A_WIDTH 15 + parameter \B_SIGNED 0 + parameter \B_WIDTH 32 + parameter \Y_WIDTH 32 + connect \A \a + connect \B 2 + connect \Y $add$:2$1_Y + end + attribute \src ":2.12-2.21" + cell $pow $pow$:2$2 + parameter \A_SIGNED 0 + parameter \A_WIDTH 32 + parameter \B_SIGNED 0 + parameter \B_WIDTH 32 + parameter \Y_WIDTH 32 + connect \A 2 + connect \B $add$:2$1_Y + connect \Y $pow$:2$2_Y + end + connect \b $pow$:2$2_Y +end +EOT + +select -assert-count 1 t:$pow +select -assert-none t:$shl +opt_expr +select -assert-none t:$pow +select -assert-count 1 t:$shl + +read_verilog << EOT +module ref(input wire [14:0] a, output wire [31:0] b); +assign b = 1 << (a+2); +endmodule +EOT + +equiv_make top ref equiv +select -assert-any -module equiv t:$equiv +equiv_induct +equiv_status -assert + +# Other power of 2 value + +design -reset + +read_verilog <