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

            Bug ID: 116024
           Summary: [14/15 Regression] unnecessary integer comparison(s)
                    for a simple loop
           Product: gcc
           Version: 14.1.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: ipa
          Assignee: unassigned at gcc dot gnu.org
          Reporter: artemiy at synopsys dot com
                CC: jh at suse dot cz
  Target Milestone: ---
            Target: riscv32-unknown-elf

gcc 14 and later emits unnecessary instructions when compiling the i() function
in the following code:
$ cat test.i
# 0 "test.c"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 "test.c"
typedef enum { a, b } c;
extern char d, e;
c f()
{
  if (d)
    return a;
  d = e;
  return b;
}
void i()
{
  int l = 2;
  while (l <= 2)
    if (f() == a)
      l++;
}

$ riscv32-unknown-elf-gcc test.i -S -O3 -fno-inline -Wall -Wextra
$ cat test.s
[snip]
i:
        addi    sp,sp,-16
        sw      s0,8(sp)
        sw      s1,4(sp)
        sw      ra,12(sp)
        li      s1,3
        li      s0,2
.L6:
        call    f
        sub     a0,s1,a0
        beq     a0,s0,.L6
[snip]

gcc 13.2.0 doesn’t load any immediates and just emits a branch-if-not-zero:

[snip]
i:
        addi    sp,sp,-16
        sw      ra,12(sp)
.L6:
        call    f
        bne     a0,zero,.L6
[snip]

I have bisected the introduction of this behavior down to:

commit 53ba8d669550d3a1f809048428b97ca607f95cf5
Author: Jan Hubicka <j...@suse.cz>
Date:   Mon Nov 20 19:35:53 2023 +0100

    inter-procedural value range propagation

I can't be too sure, but I think what ends up happening is that the ipa-cp pass
propagates the range of return values of f() ({0,1}), then later on phiopt2
uses this to expand the PHI node to something like 3 - f() == 2:

 <bb 3> [local count: 955630224]:
  # DEBUG BEGIN_STMT
  _1 = f ();
  _6 = (int) _1;
  _8 = 3 - _6;

  <bb 4> [local count: 1073741824]:
  # l_2 = PHI <_8(3), 2(2)>
  # DEBUG l => l_2
  # DEBUG BEGIN_STMT
  if (l_2 == 2)
    goto <bb 3>; [89.00%]
  else
    goto <bb 5>; [11.00%]

And the aforementioned expression never gets simplified back to f() != 0,
resulting in more complicated assembly code.  Indeed, specifying -fno-ipa-vrp
(or -fno-ssa-phiopt) works as a temporary workaround.

godbolt for convenience: https://godbolt.org/z/xr1oTrW51
gcc -v output: 
$ riscv32-unknown-elf-gcc -v
Using built-in specs.
COLLECT_GCC=riscv32-unknown-elf-gcc
COLLECT_LTO_WRAPPER=/home/art/work/install/riscv-gnu-toolchain/libexec/gcc/riscv32-unknown-elf/15.0.0/lto-wrapper
Target: riscv32-unknown-elf
Configured with: /home/art/work/src/gcc/configure --target=riscv32-unknown-elf
--prefix=/home/art/work/install/riscv-gnu-toolchain --disable-shared
--disable-threads --enable-languages=c,c++ --with-pkgversion=g80c37335baf
--with-system-zlib --enable-tls --with-newlib
--with-sysroot=/home/art/work/install/riscv-gnu-toolchain/riscv32-unknown-elf
--with-native-system-header-dir=/include --disable-libmudflap --disable-libssp
--disable-libquadmath --disable-libgomp --disable-nls
--disable-tm-clone-registry --src=/home/art/work/src/gcc --enable-multilib
--with-abi=ilp32 --with-arch=rv32gc --with-tune=rocket --with-isa-spec=20191213
'CFLAGS_FOR_TARGET=-Os    ' 'CXXFLAGS_FOR_TARGET=-Os    '
Thread model: single
Supported LTO compression algorithms: zlib
gcc version 15.0.0 20240721 (experimental) (g80c37335baf)

Reply via email to