From 1af8ded0cb98d9610b624e880d4c3e6f6c0a6c8e Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 24 Jul 2026 17:41:31 +1200 Subject: [PATCH] alumacc: Fix get_lt for oversized output Current behavior uses the output width to determine the MSb(s), however this is not correct if the output is larger than the inputs (which doesn't happen when creating an `$alu` for a compare op, but does when folding a compare op into an arithmetic `$alu`). Co-authored-by: Lofty --- passes/techmap/alumacc.cc | 40 ++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc index 5cce8c0ee..e42585874 100644 --- a/passes/techmap/alumacc.cc +++ b/passes/techmap/alumacc.cc @@ -41,18 +41,22 @@ struct AlumaccWorker std::vector cells; RTLIL::SigSpec a, b, c, y; std::vector> cmp; - bool is_signed, invert_b; + bool is_signed, invert_b, oversized; RTLIL::Cell *alu_cell; RTLIL::SigSpec cached_lt, cached_slt, cached_gt, cached_sgt, cached_eq, cached_ne; RTLIL::SigSpec cached_cf, cached_of, cached_sf; - RTLIL::SigSpec get_lt(bool is_signed) { - if (is_signed) { + RTLIL::SigSpec get_lt(bool this_signed) { + if (this_signed) { if (GetSize(cached_slt) == 0) { - get_of(); get_sf(); - cached_slt = alu_cell->module->Xor(NEW_ID, cached_of, cached_sf); + if (is_signed && oversized) { + cached_slt = cached_sf; + } else { + get_of(); + cached_slt = alu_cell->module->Xor(NEW_ID, cached_of, cached_sf); + } } return cached_slt; @@ -65,10 +69,10 @@ struct AlumaccWorker } } - RTLIL::SigSpec get_gt(bool is_signed) { - if (is_signed) { + RTLIL::SigSpec get_gt(bool this_signed) { + if (this_signed) { if (GetSize(cached_sgt) == 0) { - get_lt(is_signed); + get_lt(this_signed); get_eq(); SigSpec Or = alu_cell->module->Or(NEW_ID, cached_slt, cached_eq); cached_sgt = alu_cell->module->Not(NEW_ID, Or, false, alu_cell->get_src_attribute()); @@ -77,7 +81,7 @@ struct AlumaccWorker return cached_sgt; } else { if (GetSize(cached_gt) == 0) { - get_lt(is_signed); + get_lt(this_signed); get_eq(); SigSpec Or = alu_cell->module->Or(NEW_ID, cached_lt, cached_eq); cached_gt = alu_cell->module->Not(NEW_ID, Or, false, alu_cell->get_src_attribute()); @@ -112,7 +116,14 @@ struct AlumaccWorker if (GetSize(cached_of) == 0) { cached_of = {alu_cell->getPort(ID::CO), alu_cell->getPort(ID::CI)}; log_assert(GetSize(cached_of) >= 2); - cached_of = alu_cell->module->Xor(NEW_ID, cached_of[GetSize(cached_of)-1], cached_of[GetSize(cached_of)-2]); + if (oversized) { + auto max_input = max(GetSize(a), GetSize(b)); + log_assert(max_input >= 1); + cached_of = alu_cell->module->Xor(NEW_ID, cached_of[max_input], cached_of[max_input-1]); + } else { + log_assert(GetSize(y) >= 1); + cached_of = alu_cell->module->Xor(NEW_ID, cached_of[GetSize(y)], cached_of[GetSize(y)-1]); + } } return cached_of; } @@ -120,7 +131,12 @@ struct AlumaccWorker RTLIL::SigSpec get_sf() { if (GetSize(cached_sf) == 0) { cached_sf = alu_cell->getPort(ID::Y); - cached_sf = cached_sf[GetSize(cached_sf)-1]; + log_assert(GetSize(cached_sf) >= 1); + if (oversized && !is_signed) { + cached_sf = cached_sf[max(GetSize(a), GetSize(b))-1]; + } else { + cached_sf = cached_sf[GetSize(y)-1]; + } } return cached_sf; } @@ -357,6 +373,7 @@ struct AlumaccWorker alunode->cells.push_back(n->cell); alunode->is_signed = a_signed; alunode->invert_b = subtract_b; + alunode->oversized = max(GetSize(A), GetSize(B)) < GetSize(n->y); alunode->a = A; alunode->b = B; @@ -448,6 +465,7 @@ struct AlumaccWorker n->y = module->addWire(NEW_ID, max(GetSize(A), GetSize(B))); n->is_signed = is_signed; n->invert_b = true; + n->oversized = false; sig_alu[RTLIL::SigSig(A, B)].insert(n); log(" new $alu\n"); } else {