From e5c56c6400f04c202302752147c111d39d9de840 Mon Sep 17 00:00:00 2001 From: Daniel M Bouyou Date: Tue, 18 Aug 2026 12:06:48 +0200 Subject: [PATCH] arith_tree: do not flatten a chain link narrower than its consumer sole_chainable_consumer folded a cell into its consumer without ever comparing widths. A link truncates its result at its own Y width, and that truncation is invisible only when the consumer truncates at least as hard, since (x % 2**link) % 2**parent == x % 2**parent holds only when parent <= link. When the consumer is wider, the carry the link discards becomes observable, and flattening the chain silently recovers it. For module top(input [7:0] a, b, c, output [8:0] o); wire [7:0] t = a + b; assign o = t + c; endmodule synth -arith_tree computes a + b + c where the design specifies ((a + b) % 256) + c. The two differ by 256 whenever a + b overflows, for example at a=169 b=135 c=7. alumacc already guards the structurally identical $macc merge using macc_may_overflow(); arith_tree carried no equivalent check. Add two cases to tests/arith_tree/arith_tree_equiv.ys: equiv_double_neg widened to a 5 bit result, and a dedicated equiv_narrow_intermediate. --- passes/techmap/arith_tree.cc | 7 +++++++ tests/arith_tree/arith_tree_equiv.ys | 22 ++++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/passes/techmap/arith_tree.cc b/passes/techmap/arith_tree.cc index 2c5d51386..9281ba00d 100644 --- a/passes/techmap/arith_tree.cc +++ b/passes/techmap/arith_tree.cc @@ -134,6 +134,13 @@ struct ArithTreeWorker { else if (consumer != c) return nullptr; } + // A link truncates its own result at its own Y width. That truncation + // is invisible only if the consumer truncates at least as hard, since + // (x % 2**link) % 2**parent == x % 2**parent only when parent <= link. + // A link narrower than its consumer discards a carry that the wider + // consumer would otherwise see, so it must not be flattened away. + if (consumer != nullptr && GetSize(sig) < GetSize(consumer->getPort(ID::Y))) + return nullptr; return consumer; } diff --git a/tests/arith_tree/arith_tree_equiv.ys b/tests/arith_tree/arith_tree_equiv.ys index 81b2d5007..726aede5a 100644 --- a/tests/arith_tree/arith_tree_equiv.ys +++ b/tests/arith_tree/arith_tree_equiv.ys @@ -163,7 +163,7 @@ design -reset read_verilog <