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.