]> git.ipfire.org Git - thirdparty/gcc.git/commit
Fold (X<<C1)^(X<<C2) to a multiplication when possible.
authorRoger Sayle <roger@nextmovesoftware.com>
Wed, 4 Aug 2021 13:19:14 +0000 (14:19 +0100)
committerRoger Sayle <roger@nextmovesoftware.com>
Wed, 4 Aug 2021 13:22:51 +0000 (14:22 +0100)
commit96146e61cd7aee62c21c2845916ec42152918ab7
tree99914e14e7b67d97aa6e4789f3159c9e4ad02058
parent0d04fe49239d91787850036599164788f1c87785
Fold (X<<C1)^(X<<C2) to a multiplication when possible.

The easiest way to motivate these additions to match.pd is with the
following example:

unsigned int foo(unsigned char i) {
  return i | (i<<8) | (i<<16) | (i<<24);
}

which mainline with -O2 on x86_64 currently generates:
foo: movzbl  %dil, %edi
movl    %edi, %eax
movl    %edi, %edx
sall    $8, %eax
sall    $16, %edx
orl     %edx, %eax
orl     %edi, %eax
sall    $24, %edi
orl     %edi, %eax
ret

but with this patch now becomes:
foo: movzbl  %dil, %eax
        imull   $16843009, %eax, %eax
        ret

Interestingly, this transformation is already applied when using
addition, allowing synth_mult to select an optimal sequence, but
not when using the equivalent bit-wise ior or xor operators.

The solution is to use tree_nonzero_bits to check that the
potentially non-zero bits of each operand don't overlap, which
ensures that BIT_IOR_EXPR and BIT_XOR_EXPR produce the same
results as PLUS_EXPR, which effectively generalizes the old
fold_plusminus_mult_expr.  Technically, the transformation
is to canonicalize (X*C1)|(X*C2) and (X*C1)^(X*C2) to
X*(C1+C2) where X and X<<C are considered special cases.

2021-08-04  Roger Sayle  <roger@nextmovesoftware.com>
    Marc Glisse  <marc.glisse@inria.fr>

gcc/ChangeLog
* match.pd (bit_ior, bit_xor): Canonicalize (X*C1)|(X*C2) and
(X*C1)^(X*C2) as X*(C1+C2), and related variants, using
tree_nonzero_bits to ensure that operands are bit-wise disjoint.

gcc/testsuite/ChangeLog
* gcc.dg/fold-ior-4.c: New test.
gcc/match.pd
gcc/testsuite/gcc.dg/fold-ior-4.c [new file with mode: 0644]