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.