Am 20.08.26 um 00:51 schrieb Roger Sayle:

This patch is a revision of my previous patch to use add_optab in
the expansion of bitreverse which improves code generation on x86,
cris, riscv, parisc, sh and possibly other targets.
https://gcc.gnu.org/pipermail/gcc-patches/2026-August/726901.html

This patch addresses Jeff Law's (and Georg-Johann Lay's earlier)
concerns that targets without a shift-add instruction don't benefit
from the use of PLUS, and may potentially hurt optimization.  Alas
it's not sufficient to check whether a target supports an addsi3
optab, and even (the default) rtx_costs can't be relied upon.
The solution here is to introduce an aop_optab (for any_or_plus)
to allow a backend complete control over choices of PLUS vs. IOR
vs. XOR.  For example, x86_64 would prefer IOR (or XOR) over PLUS
for V1TImode.  As a worked example, this patch defines an aop_optab
for AVR to always use PLUS.

Interestingly, testing this functionality on AVR is fairly difficult,
as the backend provides expansions for bitreverse, bswap and rotate,
i.e. all the obvious places where aop_optab would be used.  Fortunately,
I was able to identify an optimization in store_fixed_bitfield_1 that
affects code generation (on avr-elf).

Consider the test case:

typedef struct {
   int a : 1;
   int b : 1;
   int c : 16;
   int d : 14;
} S;

S foo(S x, unsigned char y)
{
   x.c = y;
   return x;
}

Currently, with -O2 x86_64 generates (both sall and orl):

foo:    andl    $-262141, %edi
         movzbl  %sil, %esi
         sall    $2, %esi
         movl    %edi, %eax
         orl     %esi, %eax
         ret

with this revised patch to make use of aop_optab, we now get:

foo:    movzbl  %sil, %esi
         andl    $-262141, %edi
         leal    (%rdi,%rsi,4), %eax
         ret

On avr-elf, without the avr.md change we would get (a PLUS):

foo:    mov r18,r20
         lsl r18
         lsl r18
         andi r22,lo8(3)
         add r22,r18
         clr r23
         bst r20,6
         bld r23,0
         bst r20,7
         bld r23,1
         andi r24,lo8(-4)
         ret

But with avr.md's define_expand for aop<mode>3 we restore the original:

foo:    mov r18,r20
         lsl r18
         lsl r18
         andi r22,lo8(3)
         or r22,r18
         clr r23
         bst r20,6
         bld r23,0
         bst r20,7
         bld r23,1
         andi r24,lo8(-4)
         ret

Hi Roger,

I think the change is ok for avr, though I am not a maintainer
and hence I can't approve.

In the above avr code, AND and OR have exactly the same resource
consumption and operand capabilities.

Johann

This patch has been tested on x86_64-pc-linux-gnu with make bootstrap
and make -k check, both with and without --target_board=unix{-m32}
with no new failures.  Ok for mainline?

If (this approach/patch is) approved, I can document AOP and aop
in a follow-up pach to rtl.texi, but these are currently an internal
detail (work in progress).

2026-08-19  Roger Sayle  <[email protected]>

gcc/ChangeLog
         * config/avr/avr.md (aop<mode>3): New define_expand to specify
         that IOR should always be used to implement any_or_plus (AOP).
         * expmed.cc (store_fixed_bit_field_1): Use new aop_optab when
         writing a value into a fixed size bitfield of a structure.
         * optabs.cc (expand_binop): If target doesn't provide a suitable
         aop<mode>3 instruction, intelligently use PLUS or IOR instead.
         (expand_binop): For rotations, use aop_optab to select AOP
         implementation instead of hard-coding add_optab.
         (expand_bitreverse): Likwise, Use aop_optab instead of ior_optab
         when composing swapped bits and nibbles (allows use of shift_add).
         * optabs.def (aop_optab): New named optab for any_or_plus.
         * rtl.def (AOP): New RTX code to capture any_or_plus semantics.
         * simplify-rtx.cc (simplify_unary_operation_1) <case BSWAP>:
         Canonicalize (BSWAP (BITREVERSE x)) as (BITREVERSE (BSWAP x)).

gcc/testsuite/ChangeLog
         * gcc.target/i386/builtin-bitreverse-1.c: New test case.

Thanks again.
Roger
--

-----Original Message-----
From: Jeffrey Law <[email protected]>
Sent: 10 August 2026 00:19
To: Roger Sayle <[email protected]>; 'Patches GCC' <gcc-
[email protected]>
Subject: Re: [middle-end PATCH] Improve bitreverse expansion on x86_64 and
cris.

On 8/8/2026 9:24 AM, Roger Sayle wrote:
My recent patch to improve bitreverse support on cris, posted at
https://gcc.gnu.org/pipermail/gcc-patches/2026-August/726384.html
revealed an optimization opportunity.  If you look closely GCC's
expansion of bitreverse (in optabs.cc) generates a left shift followed
by an IOR in several places.  In these instances, its possible to use
"any_or_plus", and in fact using PLUS would allow cris to use its addi
instruction, and the x86 to use its lea instruction.  I believe PLUS
is always as efficient as IOR for SImode/wordmode, even on processors
that have to use add with carry, i.e. addc[qh]i3.  For other (longer)
modes (such as vector modes), it's better to use IOR, and for shorter
modes I'm not sure there's any advantage to using PLUS.  If I'm wrong
for some targets, we can make aop_optab a real optab.


Previously on x86_64, with -O2 the following function:

unsigned int foo(unsigned int x)
{
    return __builtin_bitreverse32 (x);
}

used to generate:

foo:    movl    %edi, %eax
          bswap   %eax
          movl    %eax, %edi
          andl    $252645135, %eax
          shrl    $4, %edi
          sall    $4, %eax
          andl    $252645135, %edi
          orl     %eax, %edi
          movl    %edi, %edx
          andl    $858993459, %edi
          shrl    $2, %edx
          sall    $2, %edi
          andl    $858993459, %edx
          orl     %edi, %edx
          movl    %edx, %eax
          andl    $1431655765, %edx
          shrl    $1, %eax
          addl    %edx, %edx
          andl    $1431655765, %eax
          orl     %edx, %eax
          ret

with this patch we instead generate:

foo:    bswap   %edi
          movl    %edi, %eax
          andl    $252645135, %edi
          shrl    $4, %eax
          sall    $4, %edi
          andl    $252645135, %eax
          addl    %edi, %eax
          movl    %eax, %edx
          andl    $858993459, %eax
          shrl    $2, %edx
          andl    $858993459, %edx
          leal    (%rdx,%rax,4), %eax
          movl    %eax, %edx
          andl    $1431655765, %eax
          shrl    $1, %edx
          andl    $1431655765, %edx
          leal    (%rdx,%rax,2), %eax
          ret

which is three instructions shorter.  This patch also contains another
transformation (to help bitreverse on cris) which is for simplify-rtx
and combine to canonicalize bswap(bitreverse x) as bitreverse(bswap x).
The two forms are equivalent, so canonicalizing simplifies machine
descriptions.  The (otherwise arbitrary) choice to perform BSWAP
first, is (1) to aid targets like powerpc that can perform bswap on
load and
(2) to place bswap next to bswap on targets that RTL split bitreverse
in a similar order to GCC's default optab expansion above.

This patch has been tested on x86_64-pc-linux-gnu with make bootstrap
and make -k check, both with and without --target_board=unix{-m32}
with no new failures.  Ok for mainline?


2026-08-08  Roger Sayle  <[email protected]>

gcc/ChangeLog
          * optab.cc (expand_bitreverse): Use PLUS instead of IOR when
          composing swapped bits and nibbles (allows use of shift_add).
          * simplify-rtx.cc (simplify_unary_operation_1) <case BSWAP>:
          Canonicalize (BSWAP (BITREVERSE x)) as (BITREVERSE (BSWAP x)).

gcc/testsuite/ChangeLog
          * gcc.target/i386/builtin-bitreverse-1.c: New test case.


So the only concern I have is the special casing of SImode in the optabs.cc
change.   I wonder if we could query if we have addsi?

FWIW, it saves an instruction on RISC-V as well as the new sequence exposes a
sh2add instead of slliw+or.   Which means this likely helps other targets with
shNadd insns.

jeff

Reply via email to