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 <