https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121268

            Bug ID: 121268
           Summary: RISC-V: Possible optimization when manipulating
                    rightmost bits with zbb enabled
           Product: gcc
           Version: 16.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: dusan.stojko...@rt-rk.com
  Target Milestone: ---

Hello,
Consider the following three functions:

```
unsigned int f1(unsigned int x)
{
    return ~(x | -x);
}

unsigned int f2(unsigned int x)
{
    return ~x & (x - 1);
}

unsigned int f3(unsigned int x)
{
    return (x & -x) - 1;
}
```

The functions effectively create ones in the trailing 0s in x and 0s elsewhere,
producing 0 if none (ex. 0x00100000 → 0x000fffff). They are equivalent
logically, but GCC produces different assembly code for each one:

```
f1(unsigned int):
        negw    a5,a0
        or      a0,a5,a0
        not     a0,a0
        ret
f2(unsigned int):
        addiw   a5,a0,-1
        andn    a0,a5,a0
        ret
f3(unsigned int):
        negw    a5,a0
        and     a0,a5,a0
        addiw   a0,a0,-1
        ret 
```

Compiled with -O3 -march=rv64gc_zbb.
Could GCC match f1 and f3 combinations and transform them into f2?

For -O3 -march=rv32gc_zbb we get:

```
f1(unsigned int):
        addi    a5,a0,-1
        andn    a0,a5,a0
        ret
f2(unsigned int):
        addi    a5,a0,-1
        andn    a0,a5,a0
        ret
f3(unsigned int):
        neg     a5,a0
        and     a0,a5,a0
        addi    a0,a0,-1
        ret
```

Here, f3 could be combined to f1 or f2.

Reply via email to