diff options
author | Jannis Harder <me@jix.one> | 2022-11-02 17:57:14 +0100 |
---|---|---|
committer | Jannis Harder <me@jix.one> | 2022-11-29 19:06:45 +0100 |
commit | c08242ba413302d76cc4986ad972c29a510d6990 (patch) | |
tree | 65363f81a6164f1673b5f669f139979ce7820e24 | |
parent | 661fa5ff92f19675cfd87754a99d0c5c42c9df13 (diff) | |
download | yosys-c08242ba413302d76cc4986ad972c29a510d6990.tar.gz yosys-c08242ba413302d76cc4986ad972c29a510d6990.tar.bz2 yosys-c08242ba413302d76cc4986ad972c29a510d6990.zip |
opt_expr: Optimize bitwise logic ops with one fully const input
-rw-r--r-- | passes/opt/opt_expr.cc | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 9cc0170dc..38b0d221b 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -643,6 +643,87 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons goto next_cell; } + if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor))) + { + RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); + RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B)); + + bool a_fully_const = (sig_a.is_fully_const() && (!keepdc || !sig_a.is_fully_undef())); + bool b_fully_const = (sig_b.is_fully_const() && (!keepdc || !sig_b.is_fully_undef())); + + if (a_fully_const != b_fully_const) + { + cover("opt.opt_expr.bitwise_logic_one_const"); + log_debug("Replacing %s cell `%s' in module `%s' having one fully constant input\n", + log_id(cell->type), log_id(cell->name), log_id(module)); + RTLIL::SigSpec sig_y = assign_map(cell->getPort(ID::Y)); + + int width = GetSize(cell->getPort(ID::Y)); + + sig_a.extend_u0(width, cell->getParam(ID::A_SIGNED).as_bool()); + sig_b.extend_u0(width, cell->getParam(ID::B_SIGNED).as_bool()); + + if (!a_fully_const) + std::swap(sig_a, sig_b); + + RTLIL::SigSpec b_group_0, b_group_1, b_group_x; + RTLIL::SigSpec y_group_0, y_group_1, y_group_x; + + for (int i = 0; i < width; i++) { + auto bit_a = sig_a[i].data; + if (bit_a == State::S0) b_group_0.append(sig_b[i]), y_group_0.append(sig_y[i]); + if (bit_a == State::S1) b_group_1.append(sig_b[i]), y_group_1.append(sig_y[i]); + if (bit_a == State::Sx) b_group_x.append(sig_b[i]), y_group_x.append(sig_y[i]); + } + + if (cell->type == ID($xnor)) { + std::swap(b_group_0, b_group_1); + std::swap(y_group_0, y_group_1); + } + + RTLIL::SigSpec y_new_0, y_new_1, y_new_x; + + if (cell->type == ID($and)) { + if (!y_group_0.empty()) y_new_0 = Const(State::S0, GetSize(y_group_0)); + if (!y_group_1.empty()) y_new_1 = b_group_1; + if (!y_group_x.empty()) { + if (keepdc) + y_new_x = module->And(NEW_ID, Const(State::Sx, GetSize(y_group_x)), b_group_x); + else + y_new_x = Const(State::S0, GetSize(y_group_x)); + } + } else if (cell->type == ID($or)) { + if (!y_group_0.empty()) y_new_0 = b_group_0; + if (!y_group_1.empty()) y_new_1 = Const(State::S1, GetSize(y_group_1)); + if (!y_group_x.empty()) { + if (keepdc) + y_new_x = module->Or(NEW_ID, Const(State::Sx, GetSize(y_group_x)), b_group_x); + else + y_new_x = Const(State::S1, GetSize(y_group_x)); + } + } else if (cell->type.in(ID($xor), ID($xnor))) { + if (!y_group_0.empty()) y_new_0 = b_group_0; + if (!y_group_1.empty()) y_new_1 = module->Not(NEW_ID, b_group_1); + if (!y_group_x.empty()) { + if (keepdc) + y_new_x = module->Xor(NEW_ID, Const(State::Sx, GetSize(y_group_x)), b_group_x); + else // This should be fine even with keepdc, but opt_expr_xor.ys wants to keep the xor + y_new_x = Const(State::Sx, GetSize(y_group_x)); + } + } else { + log_abort(); + } + + assign_map.add(y_group_0, y_new_0); module->connect(y_group_0, y_new_0); + assign_map.add(y_group_1, y_new_1); module->connect(y_group_1, y_new_1); + assign_map.add(y_group_x, y_new_x); module->connect(y_group_x, y_new_x); + + module->remove(cell); + did_something = true; + goto next_cell; + } + } + if (do_fine) { if (cell->type.in(ID($not), ID($pos), ID($and), ID($or), ID($xor), ID($xnor))) |