diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index f78da20c0..a2bfc5134 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -150,6 +150,7 @@ struct MuxpackWorker } } + std::vector mux_cells; for (auto cell : module->cells()) { if (cell->type.in(ID($mux), ID($pmux)) && !cell->get_bool_attribute(ID::keep)) @@ -179,6 +180,7 @@ struct MuxpackWorker } sig_chain_prev[y_sig] = cell; + mux_cells.push_back(cell); continue; } @@ -187,47 +189,69 @@ struct MuxpackWorker for (auto bit : sigmap(conn.second)) sigbit_with_non_chain_users.insert(bit); } + + // A port can serve as a chain link only if its full sigspec matches + // some chain producer's Y. Bits used by any other input port + // have non-chain users. + for (auto cell : mux_cells) + { + SigSpec a_sig = sigmap(cell->getPort(ID::A)); + SigSpec b_sig; + if (cell->type == ID($mux)) + b_sig = sigmap(cell->getPort(ID::B)); + SigSpec s_sig = sigmap(cell->getPort(ID::S)); + + bool a_is_chain_link = sig_chain_prev.count(a_sig); + bool b_is_chain_link = !b_sig.empty() && sig_chain_prev.count(b_sig); + + if (!a_is_chain_link) + for (auto bit : a_sig) + sigbit_with_non_chain_users.insert(bit); + if (!b_is_chain_link) + for (auto bit : b_sig) + sigbit_with_non_chain_users.insert(bit); + for (auto bit : s_sig) + sigbit_with_non_chain_users.insert(bit); + } + } + + bool is_start_cell(Cell* cell) + { + SigSpec a_sig = sigmap(cell->getPort(ID::A)); + if (cell->type == ID($mux)) { + SigSpec b_sig = sigmap(cell->getPort(ID::B)); + if (sig_chain_prev.count(a_sig) + sig_chain_prev.count(b_sig) != 1) + return true; + + if (!sig_chain_prev.count(a_sig)) + a_sig = b_sig; + } + else if (cell->type == ID($pmux)) { + if (!sig_chain_prev.count(a_sig)) + return true; + } + else log_abort(); + + for (auto bit : a_sig) + if (sigbit_with_non_chain_users.count(bit)) + return true; + + { + Cell *prev_cell = sig_chain_prev.at(a_sig); + log_assert(prev_cell); + SigSpec s_sig = sigmap(cell->getPort(ID::S)); + s_sig.append(sigmap(prev_cell->getPort(ID::S))); + if (!excl_db.query(s_sig)) + return true; + } + return false; } void find_chain_start_cells() { for (auto cell : candidate_cells) - { - log_debug("Considering %s (%s)\n", cell, cell->type.unescape()); - - SigSpec a_sig = sigmap(cell->getPort(ID::A)); - if (cell->type == ID($mux)) { - SigSpec b_sig = sigmap(cell->getPort(ID::B)); - if (sig_chain_prev.count(a_sig) + sig_chain_prev.count(b_sig) != 1) - goto start_cell; - - if (!sig_chain_prev.count(a_sig)) - a_sig = b_sig; - } - else if (cell->type == ID($pmux)) { - if (!sig_chain_prev.count(a_sig)) - goto start_cell; - } - else log_abort(); - - for (auto bit : a_sig) - if (sigbit_with_non_chain_users.count(bit)) - goto start_cell; - - { - Cell *prev_cell = sig_chain_prev.at(a_sig); - log_assert(prev_cell); - SigSpec s_sig = sigmap(cell->getPort(ID::S)); - s_sig.append(sigmap(prev_cell->getPort(ID::S))); - if (!excl_db.query(s_sig)) - goto start_cell; - } - - continue; - - start_cell: - chain_start_cells.insert(cell); - } + if (is_start_cell(cell)) + chain_start_cells.insert(cell); } vector create_chain(Cell *start_cell) @@ -235,7 +259,7 @@ struct MuxpackWorker vector chain; Cell *c = start_cell; - while (c != nullptr) + while (true) { chain.push_back(c); @@ -257,52 +281,39 @@ struct MuxpackWorker if (GetSize(chain) < 2) return; - int cursor = 0; - while (cursor < GetSize(chain)) - { - int cases = GetSize(chain) - cursor; + int cases = GetSize(chain); + Cell *first_cell = chain.front(); + Cell *last_cell = chain.back(); - Cell *first_cell = chain[cursor]; + log("Converting %s.%s ... %s.%s to a pmux with %d cases.\n", + module, first_cell, module, last_cell, cases); - if (cases < 2) { - cursor++; - continue; + mux_count += cases; + pmux_count += 1; + + first_cell->type = ID($pmux); + + SigSpec b_sig = first_cell->getPort(ID::B); + SigSpec s_sig = first_cell->getPort(ID::S); + + for (int i = 1; i < cases; i++) { + Cell* prev_cell = chain[i-1]; + Cell* cursor_cell = chain[i]; + if (sigmap(prev_cell->getPort(ID::Y)) == sigmap(cursor_cell->getPort(ID::A))) { + b_sig.append(cursor_cell->getPort(ID::B)); + s_sig.append(cursor_cell->getPort(ID::S)); + } else { + log_assert(cursor_cell->type == ID($mux)); + b_sig.append(cursor_cell->getPort(ID::A)); + s_sig.append(module->LogicNot(NEW_ID, cursor_cell->getPort(ID::S))); } - - Cell *last_cell = chain[cursor+cases-1]; - - log("Converting %s.%s ... %s.%s to a pmux with %d cases.\n", - module, first_cell, module, last_cell, cases); - - mux_count += cases; - pmux_count += 1; - - first_cell->type = ID($pmux); - SigSpec b_sig = first_cell->getPort(ID::B); - SigSpec s_sig = first_cell->getPort(ID::S); - - for (int i = 1; i < cases; i++) { - Cell* prev_cell = chain[cursor+i-1]; - Cell* cursor_cell = chain[cursor+i]; - if (sigmap(prev_cell->getPort(ID::Y)) == sigmap(cursor_cell->getPort(ID::A))) { - b_sig.append(cursor_cell->getPort(ID::B)); - s_sig.append(cursor_cell->getPort(ID::S)); - } - else { - log_assert(cursor_cell->type == ID($mux)); - b_sig.append(cursor_cell->getPort(ID::A)); - s_sig.append(module->LogicNot(NEW_ID, cursor_cell->getPort(ID::S))); - } - remove_cells.insert(cursor_cell); - } - - first_cell->setPort(ID::B, b_sig); - first_cell->setPort(ID::S, s_sig); - first_cell->setParam(ID::S_WIDTH, GetSize(s_sig)); - first_cell->setPort(ID::Y, last_cell->getPort(ID::Y)); - - cursor += cases; + remove_cells.insert(cursor_cell); } + + first_cell->setPort(ID::B, b_sig); + first_cell->setPort(ID::S, s_sig); + first_cell->setParam(ID::S_WIDTH, GetSize(s_sig)); + first_cell->setPort(ID::Y, last_cell->getPort(ID::Y)); } void cleanup() diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index 9a1e3e824..3bea8f030 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -238,6 +238,16 @@ module case_overlap ( end endmodule +module chain_slice_self_input ( + input [31:0] A, + input [1:0] S, + output [31:0] Y +); + wire [31:0] tmp; + assign tmp = S == 1 ? {A[7:0], A[7:0], A[7:0], A[7:0]} : A; + assign Y = S == 2 ? {A[15:0], tmp[15:0]} : tmp; +endmodule + module case_overlap2 ( input wire [2:0] x, input wire a, b, c, d, e, diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index d73fc44b4..570ac8602 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -249,6 +249,21 @@ design -import gate -as gate miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter +design -load read +hierarchy -top chain_slice_self_input +prep +design -save gold +muxpack +opt +#stat +select -assert-count 2 t:$mux +select -assert-count 0 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter + design -load read hierarchy -top case_overlap2 #prep # Do not prep otherwise $pmux's overlapping entry will get removed