diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index 250352656..ee0d2d449 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,6 +189,30 @@ 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) diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index 752f9ba48..928029a4d 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