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

            Bug ID: 121534
           Summary: GCC misoptimizes C23 sinpi/cospi/tanpi during inlining
                    of round()
           Product: gcc
           Version: 15.1.1
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: normal
          Priority: P3
         Component: ipa
          Assignee: unassigned at gcc dot gnu.org
          Reporter: rsworktech at outlook dot com
  Target Milestone: ---
              Host: riscv64-linux-gnu
            Target: riscv64-linux-gnu
             Build: riscv64-linux-gnu

Created attachment 62111
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=62111&action=edit
Disasm of miscompiled s_sinpi.o

When building glibc 2.42+r3+gbc13db739377-1 with gcc 15.1.1+r7+gf36ec88aa85a-1,
additional test failures occurs for C23 trigonometric pi-based
functions(sinpi/cospi/tanpi):

FAIL: math/test-double-cospi                      
FAIL: math/test-double-sinpi
FAIL: math/test-double-tanpi
FAIL: math/test-float32x-cospi
FAIL: math/test-float32x-sinpi
FAIL: math/test-float32x-tanpi
FAIL: math/test-float64-cospi
FAIL: math/test-float64-sinpi
FAIL: math/test-float64-tanpi

All the failures are caused by unexpected "Invalid operation" exception from
fflags.

Failure: sinpi (qNaN): Exception "Invalid operation" set
Failure: sinpi (-qNaN): Exception "Invalid operation" set
Failure: sinpi_downward (qNaN): Exception "Invalid operation" set
Failure: sinpi_downward (-qNaN): Exception "Invalid operation" set
Failure: sinpi_towardzero (qNaN): Exception "Invalid operation" set
Failure: sinpi_towardzero (-qNaN): Exception "Invalid operation" set
Failure: sinpi_upward (qNaN): Exception "Invalid operation" set
Failure: sinpi_upward (-qNaN): Exception "Invalid operation" set

My investigation determines that it is caused by a misoptimization
done by gcc during the inlining of round() into __{sin,cos,tan}pi functions.

This does not occur when using GCC 14.3.1+r25+g42e99e057bd7-1, which chooses to
not inline the round() call.

Labeling __round() in glibc with __attribute__((noipa)) could not solve it. I
am not sure whether it's caused by symbol aliasing (__round -> round) or it is
not ipa that misoptimizes it.

The command-line to build the misoptimized object is gcc
/build/glibc/src/glibc-build/math/s_sinpi.c -c -std=gnu11 -fgnu89-inline 
-march=rv64gc -mabi=lp64d -O2 -pipe -fexceptions -Wformat
-Werror=format-security -fstack-clash-protection -g
-ffile-prefix-map=/build/glibc/src=/usr/src/debug/glibc -Wall -Wwrite-strings
-Wundef -Wimplicit-fallthrough -fmerge-all-constants -frounding-math
-fstack-protector-strong -fno-common -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3
-Wstrict-prototypes -Wold-style-definition  -fno-math
-errno   -fno-omit-frame-pointer -fPIE   -fno-builtin-sinpif32x
-fno-builtin-sinpif64       -I../include -I/build/glibc/src/glibc-build/math 
-I/build/glibc/src/glibc-build  -I../sysdeps/unix/sysv/linux/riscv/rv64 
-I../sysdeps/unix/sysv/linux/riscv/include -I../sysdeps/unix/sysv/linux/riscv 
-I../sysdeps/riscv/nptl  -I../sysdeps/unix/sysv/linux/wordsize-64 
-I../sysdeps/unix/sysv/linux/riscv/multiarch 
-I../sysdeps/unix/sysv/linux/include -I../sysdeps/unix/sysv/linux 
-I../sysdeps/nptl  -I../sysdeps/pthread  -I../sysdeps/gnu 
-I../sysdeps/unix/inet  -I../sysdeps/unix/sysv  -I../sysdeps/unix 
-I../sysdeps/posix  -I../sysdeps/riscv/rv64/rvd  -I../sysdeps/riscv/rv64/rvf 
-I../sysdeps/riscv/rvf  -I../s
ysdeps/riscv/rvd  -I../sysdeps/riscv/rv64  -I../sysdeps/riscv/multiarch 
-I../sysdeps/riscv  -I../sysdeps/ieee754/ldbl-128  -I../sysdeps/ieee754/dbl-64 
-I../sysdeps/ieee754/flt-32  -I../sysdeps/wordsize-64  -I../sysdeps/ieee754 
-I../sysdeps/generic  -I.. -I../libio -I. -nostdinc -isystem
/usr/lib/gcc/riscv64-unknown-linux-gnu/14.2.1/include -isystem
/usr/lib/gcc/riscv64-unknown-linux-gnu/14.2.1/include-fixed -isystem
/usr/include -D_LIBC_REENTRANT -include
/build/glibc/src/glibc-build/libc-modules.h -DMODULE_NAME=libm -include
../include/libc-symbols.h  -DPIC     -DTOP_NAMESPACE=glibc -o
/build/glibc/src/glibc-build/math/s_sinpi.o -MD -MP -MF
/build/glibc/src/glibc-build/math/s_sinpi.o.dt -MT
/build/glibc/src/glibc-build/math/s_sinpi.o   

Notably, it uses O2 and does not enable unsafe math optimizations like
-ffast-math.

The round() function is from sysdeps/riscv/rv64/rvd/s_round.c for double type
on riscv64.
It contains fflags save/restore code and code for handling NaN special case.
In the misoptimized assembly, fflags save/restore and NaN special case are all
gone after inlining of round().

The most relevant part of the misoptimized code is:

  66:   a2c71753                flt.d   a4,fa4,fa2
  6a:   e351                    bnez    a4,ee <.L24>

The fflags save/restore code is incorrectly optimized away and
flt.d performs a signaling comparison here even for quiet NaN.
When qNaN is passed in, the NV bit of fflags will be set, which finally causes
glibc test to fail.


The misoptimized assembly and normal assembly with attribute((optimize("O0")))
are attached.

Reply via email to