https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101179

Daniel Henrique Barboza <daniel.barboza at oss dot qualcomm.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |daniel.barboza at oss dot 
qualcomm
                   |                            |.com

--- Comment #12 from Daniel Henrique Barboza <daniel.barboza at oss dot 
qualcomm.com> ---
Here's a patch that addresses most of the cases (f1, f3 and f4):

https://gcc.gnu.org/pipermail/gcc-patches/2026-July/724039.html

This patch adds phiopt code that turns MOD/DIV into bit_and/rshift if the
phiargs are all pow2.  This is enough to bring f1, f3 and f4 to the same
aarch64 code.

f2 remains not optimized:

int f2(int y)
{
    const bool x = y % 100 == 0;
    return y % (4 << (x * 2)) == 0;
}

The reason is that its Gimple does not have a cond:

  _1 = yD.4471 % 100;
  xD.4474 = _1 == 0;
  _2 = (intD.7) xD.4474;
  _3 = _2 * 2;
  _4 = 4 << _3;
  _5 = yD.4471 % _4;
  _6 = _5 == 0;
  D.4498 = (intD.7) _6;
  return D.4498;

If this was a conditional I could address it with that patch.  It doesn't, so
we would need code elsewhere to figure out that the MOD result is a single use
variable with a zero comparison and pow2 divisors, i.e. we could simplify it to
a bit_and.  VRP does not recognize "_4" as a valid pow2 value even though it
has a pow2-pow2 range.  From phiopt1:

  # RANGE [irange] int [-99, 99]
  _1 = y_7(D) % 100;
  x_8 = _1 == 0;
  # RANGE [irange] int [0, 1] MASK 0x1 VALUE 0x0
  _2 = (intD.7) x_8;
  # RANGE [irange] int [0, 0][2, 2] MASK 0x2 VALUE 0x0
  _3 = _2 * 2;
  # RANGE [irange] int [4, 4][16, 16] MASK 0x14 VALUE 0x0
  _4 = 4 << _3;
  # RANGE [irange] int [-15, 15]
  _5 = y_7(D) % _4;
  _6 = _5 == 0;


I'm not sure how to address this case since in this format we have constants
that are implicit, i.e. "_3" has values 16,4 that are scattered across multiple
stmts.  One idea would be to recognize this format and turn it back to PHIOPT
to be optimized, although I'm not sure where we would do that.

As a side note: we have match.pd code for the unsigned version of f2 (lines
997-1015):

 (simplify
  (mod @0 (convert? (power_of_two_cand@1 @2)))
  (if ((TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (@0))
   (....)
       (bit_and @0 (convert (minus (convert:utype @1)
                                { build_one_cst (utype); })))))))


This is applied right on 'original' turning the MOD into bit_and right away, so
at least this case is already handled.

Reply via email to