On Thu, 6 May 2021, Jakub Jelinek via Gcc-patches wrote:

Though, (x&1) == x is equivalent to both (x&~1)==0 and to x < 2U
and from the latter two it isn't obvious which one is better/more canonical.
On aarch64 I don't see differences in number of insns nor in their size:
 10:    13001c00        sxtb    w0, w0
 14:    721f781f        tst     w0, #0xfffffffe
 18:    1a9f17e0        cset    w0, eq  // eq = none
 1c:    d65f03c0        ret
vs.
 20:    12001c00        and     w0, w0, #0xff
 24:    7100041f        cmp     w0, #0x1
 28:    1a9f87e0        cset    w0, ls  // ls = plast
 2c:    d65f03c0        ret
On x86_64 same number of insns, but the comparison is shorter (note, the
spaceship result is a struct with signed char based enum):
 10:    31 c0                   xor    %eax,%eax
 12:    81 e7 fe 00 00 00       and    $0xfe,%edi
 18:    0f 94 c0                sete   %al
 1b:    c3                      retq
 1c:    0f 1f 40 00             nopl   0x0(%rax)
vs.
 20:    31 c0                   xor    %eax,%eax
 22:    40 80 ff 01             cmp    $0x1,%dil
 26:    0f 96 c0                setbe  %al
 29:    c3                      retq
Generally, I'd think that the comparison should be better because it
will be most common in user code that way and VRP will be able to do the
best thing for it.

We can probably do it in 2 steps, first something like

(for cmp (eq ne)
 (simplify
  (cmp (bit_and:c @0 @1) @0)
  (cmp (@0 (bit_not! @1)) { build_zero_cst (TREE_TYPE (@0)); })))

to get rid of the double use, and then simplify X&C==0 to X<=~C if C is a mask 111...000 (I thought we already had a function to detect such masks, or the 000...111, but I can't find them anymore).

I agree that the comparison seems preferable, although if X is signed, the way GIMPLE represents types will add an inconvenient cast. And I think VRP already manages to use the bit test to derive a range.

--
Marc Glisse

Reply via email to