opt_expr: Optimize div/mod by const 1.
authorMarcelina Kościelnicka <mwk@0x04.net>
Wed, 9 Jun 2021 14:14:16 +0000 (16:14 +0200)
committerMarcelina Kościelnicka <mwk@0x04.net>
Wed, 9 Jun 2021 15:42:30 +0000 (17:42 +0200)
Turns out the code for div by a power of 2 is already almost capable of
optimizing this to a shift-by-0 or and-with-0, which will be further
folded into nothingness; let's beef it up to handle div by 1 as well.

Fixes #2820.

passes/opt/opt_expr.cc

index 84f07c8a9765cc7f3d05de78b77d086d6b57c250..0230a5c402fb9f1560cc4bbcb2df651a341d2ae5 100644 (file)
@@ -1648,7 +1648,7 @@ skip_identity:
                                        goto next_cell;
                                }
 
-                               for (int i = 1; i < (b_signed ? sig_b.size()-1 : sig_b.size()); i++)
+                               for (int i = 0; i < (b_signed ? sig_b.size()-1 : sig_b.size()); i++)
                                        if (b_val == (1 << i))
                                        {
                                                if (cell->type.in(ID($div), ID($divfloor)))
@@ -1672,7 +1672,7 @@ skip_identity:
 
                                                        // Truncating division is the same as flooring division, except when
                                                        // the result is negative and there is a remainder - then trunc = floor + 1
-                                                       if (is_truncating && a_signed) {
+                                                       if (is_truncating && a_signed && i != 0) {
                                                                Wire *flooring = module->addWire(NEW_ID, sig_y.size());
                                                                cell->setPort(ID::Y, flooring);
 
@@ -1698,7 +1698,7 @@ skip_identity:
 
                                                        std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i);
 
-                                                       if (b_signed)
+                                                       if (b_signed || i == 0)
                                                                new_b.push_back(State::S0);
 
                                                        cell->type = ID($and);
@@ -1707,7 +1707,7 @@ skip_identity:
 
                                                        // truncating modulo has the same masked bits as flooring modulo, but
                                                        // the sign bits are those of A (except when R=0)
-                                                       if (is_truncating && a_signed) {
+                                                       if (is_truncating && a_signed && i != 0) {
                                                                Wire *flooring = module->addWire(NEW_ID, sig_y.size());
                                                                cell->setPort(ID::Y, flooring);
                                                                SigSpec truncating = SigSpec(flooring).extract(0, i);