Created attachment 62111 [details] 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.
Created attachment 62112 [details] Disasm of s_sinpi.o (with O0 applied to sinpi())
Do you have the preprocessed source?
(In reply to Andrew Pinski from comment #2) > Do you have the preprocessed source? I will try to extract that. glibc's complex build system makes that a little hard.
Created attachment 62115 [details] preprocessed source code of s_sinpi.c
The round "inlining" is because it is a builtin and GCC knows about it and the target has a round optab included so this is a riscv specific issue.
FWIW while related to rounding, this is related to save/restore of FP Exception flags and not really related to rounding mode save/restore, hence de-linking with PR/120203. A patch has been posted for this issue [1] [1] https://gcc.gnu.org/pipermail/gcc-patches/2025-August/692605.html
The master branch has been updated by Vineet Gupta <vineetg@gcc.gnu.org>: https://gcc.gnu.org/g:f5696e9b1113b0a8e464cabb8cc26c871b1d9289 commit r16-3220-gf5696e9b1113b0a8e464cabb8cc26c871b1d9289 Author: Vineet Gupta <vineetg@rivosinc.com> Date: Wed Aug 13 20:20:34 2025 -0700 RISC-V: fix __builtin_round clobbering FP exceptions flags [PR121534] __builtin_round() fails to save/restore FP exception flags around the FP compare insn which can potentially clobber the same. Worth noting that the fflags restore bracketing is slightly different than the glibc implementation. Both FLT and FCVT can potentially clobber fflags. gcc generates below where even if branch is not taken and FCVT is not executed, FLT still executed. Thus FSFLAGS is placed AFTER the label 'L3'. glibc implementation FLT can't clobber due to early NaN check, so FSFLAGS can be moved under the branch, before the label. | convert_float_to_float_round | ... | frflags a5 | fabs.s fa5,fa0 | flt.s a4,fa5,fa4 <--- can clobber fflags | beq a4,zero,.L3 | fcvt.w.s a4,fa0,rmm <--- also | fcvt.s.w fa5,a4 | fsgnj.s fa0,fa5,fa0 | .L3: | fsflags a5 <-- both code paths Fixes: f652a35877e3 ("This is almost exclusively Jivan's work....") PR target/121534 gcc/ChangeLog: * config/riscv/riscv.md (round_pattern): save/restore fflags. gcc/testsuite/ChangeLog: * gcc.target/riscv/rvv/autovec/vls/math-nearbyint-1.c: Adjust scan pattern for additional instances of frflags/fsrflags. Signed-off-by: Vineet Gupta <vineetg@rivosinc.com>
Thanks for the fix. Would it be possible to also backport this fix to the gcc-15 branch? Thanks in advance.
The releases/gcc-15 branch has been updated by Vineet Gupta <vineetg@gcc.gnu.org>: https://gcc.gnu.org/g:f12a272169523823ff27d69f187f73c4211222ae commit r15-10250-gf12a272169523823ff27d69f187f73c4211222ae Author: Vineet Gupta <vineetg@rivosinc.com> Date: Wed Aug 13 20:20:34 2025 -0700 RISC-V: fix __builtin_round clobbering FP exceptions flags [PR121534] __builtin_round() fails to save/restore FP exception flags around the FP compare insn which can potentially clobber the same. Worth noting that the fflags restore bracketing is slightly different than the glibc implementation. Both FLT and FCVT can potentially clobber fflags. gcc generates below where even if branch is not taken and FCVT is not executed, FLT still executed. Thus FSFLAGS is placed AFTER the label 'L3'. glibc implementation FLT can't clobber due to early NaN check, so FSFLAGS can be moved under the branch, before the label. | convert_float_to_float_round | ... | frflags a5 | fabs.s fa5,fa0 | flt.s a4,fa5,fa4 <--- can clobber fflags | beq a4,zero,.L3 | fcvt.w.s a4,fa0,rmm <--- also | fcvt.s.w fa5,a4 | fsgnj.s fa0,fa5,fa0 | .L3: | fsflags a5 <-- both code paths Fixes: f652a35877e3 ("This is almost exclusively Jivan's work....") PR target/121534 gcc/ChangeLog: * config/riscv/riscv.md (round_pattern): save/restore fflags. gcc/testsuite/ChangeLog: * gcc.target/riscv/rvv/autovec/vls/math-nearbyint-1.c: Adjust scan pattern for additional instances of frflags/fsrflags. Signed-off-by: Vineet Gupta <vineetg@rivosinc.com>
fixed on trunk and backported to gcc-15