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