i386: Improve expansion of __builtin_parity
authorUros Bizjak <ubizjak@gmail.com>
Sun, 7 Jun 2020 20:07:28 +0000 (22:07 +0200)
committerUros Bizjak <ubizjak@gmail.com>
Sun, 7 Jun 2020 20:09:49 +0000 (22:09 +0200)
commitf08995eefbf579acfe40f0204727d5ce388e3d0a
treeef2c088a1e449d8776e3721cef11cf1e0cc7690f
parentfced594b313ddfb941913b2f59b10ce3514faaf6
i386: Improve expansion of __builtin_parity

GCC currently hides the shift and xor reduction inside a backend
specific UNSPEC PARITY, making it invisible to the RTL optimizers until
very late during compilation.  It is normally reasonable for the
middle-end to maintain wider mode representations for as long as possible
and split them later, but this only helps if the semantics are visible
at the RTL-level (to combine and other passes), but UNSPECs are black
boxes, so in this case splitting early (during RTL expansion) is a
better strategy.

It turns out that that popcount instruction on modern x86_64 processors
has (almost) made the integer parity flag in the x86 ALU completely
obsolete, especially as POPCOUNT's integer semantics are a much better
fit to RTL.  The one remaining case where these transistors are useful
is where __builtin_parity is immediately tested by a conditional branch,
and therefore the result is wanted in a flags register rather than as
an integer.  This case is captured by two peephole2 optimizations in
the attached patch.

2020-06-07  Roger Sayle  <roger@nextmovesoftware.com>

gcc/ChangeLog:

* config/i386/i386.md (paritydi2, paritysi2): Expand reduction
via shift and xor to an USPEC PARITY matching a parityhi2_cmp.
(paritydi2_cmp, paritysi2_cmp): Delete these define_insn_and_split.
(parityhi2, parityqi2): New expanders.
(parityhi2_cmp): Implement set parity flag with xorb insn.
(parityqi2_cmp): Implement set parity flag with testb insn.
New peephole2s to use these insns (UNSPEC PARITY) when appropriate.

gcc/testsuite/ChangeLog:

* gcc.target/i386/parity-3.c: New test.
* gcc.target/i386/parity-4.c: Likewise.
* gcc.target/i386/parity-5.c: Likewise.
* gcc.target/i386/parity-6.c: Likewise.
* gcc.target/i386/parity-7.c: Likewise.
* gcc.target/i386/parity-8.c: Likewise.
* gcc.target/i386/parity-9.c: Likewise.
gcc/config/i386/i386.md
gcc/testsuite/gcc.target/i386/parity-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/parity-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/parity-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/parity-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/parity-7.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/parity-8.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/parity-9.c [new file with mode: 0644]