Jeff, The +0.0 case is fine — sd zero,0(a0) and sw zero,0(a0). No fmv.d.x or fmv.s.x. The synthesis patch correctly avoids synthesizing 0.0 via integer instructions since storing integer zero is cheaper.
With this patch, I get the following assembly for the function from PR110748: > .attribute arch, > "rv64i2p1_m2p0_a2p1_f2p2_d2p2_zicsr2p0_zifencei2p0_zmmul1p0" > .attribute unaligned_access, 0 > .attribute stack_align, 16 > .text > .align 2 > .globl zd > .type zd, @function > zd: > .LFB0: > .cfi_startproc > sd zero,0(a0) > ret > .cfi_endproc > .LFE0: > .size zd, .-zd > .ident "GCC: (GNU) 16.0.1 20260227 (experimental)" Thanks, Philipp On Sun, 29 Mar 2026 at 19:50, Jeffrey Law <[email protected]> wrote: > > > > On 3/24/2026 9:18 AM, Philipp Tomsich wrote: > > From: Konstantinos Eleftheriou <[email protected]> > > > > Non-zero floating-point constants that are not Zfa FLI candidates are > > currently always loaded from the constant pool (lui + flw/fld), even > > when the IEEE 754 bit pattern can be cheaply built in a GP register > > and transferred via fmv.s.x/fmv.d.x with no memory access. > > > > Add expand-time synthesis in riscv_legitimize_move: decompose the > > CONST_DOUBLE into an integer build (riscv_move_integer) followed by > > a GP-to-FP transfer. The constant is synthesized when the integer > > build cost is < 3 instructions, keeping the total (including fmv) > > at <= 3 — competitive with the 2-instruction + memory-access > > constant pool alternative. > > > > For SFmode (RV32 and RV64 with F), every float constant qualifies > > since any 32-bit value can be built in at most 2 instructions. > > For DFmode (RV64 with D), constants whose bit pattern can be built > > in 1-2 instructions are covered: all powers of 2, simple fractions, > > small integers, and many common engineering constants. Transcendental > > constants like pi and e still use the constant pool. > > > > Examples (RV64GC, -O2): > > 1.0f: lui+flw (2 insns + mem) -> li+fmv.s.x (2 insns) > > 1.0: lui+fld (2 insns + mem) -> li+slli+fmv.d.x (3 insns) > > pi: unchanged (constant pool, integer build too expensive) > > > > gcc/ChangeLog: > > > > * config/riscv/riscv.cc (riscv_reinterpret_float_as_int): New > > function to extract IEEE 754 bit pattern from CONST_DOUBLE. > > (riscv_float_const_rtx_p): New function to decide if integer > > synthesis is profitable; returns the sign-extended integer > > value through an output parameter. > > (riscv_cannot_force_const_mem): Return true for synthesizable > > FP constants to prevent constant pool spilling. > > (riscv_const_insns): Return synthesis cost for eligible FP > > constants so they are treated as legitimate constants. > > (riscv_legitimize_move): Add synthesis of FP constants via > > integer instructions and fmv.[sd].x. > > > > gcc/testsuite/ChangeLog: > > > > * gcc.dg/fold-overflow-1.c: Expect 2139095040 three times on > > RISC-V due to FP constant synthesis of FLT_MAX. > > * gcc.target/riscv/pr105666.c: Remove scan-assembler-not for > > fmv.d.x since it now appears for FP constant synthesis. Keep > > the fmv.x.d check for GP-to-FP spill avoidance. > > * gcc.target/riscv/fp-const-synth-df-boundary.c: New test. > > * gcc.target/riscv/fp-const-synth-df-rv32.c: New test. > > * gcc.target/riscv/fp-const-synth-df.c: New test. > > * gcc.target/riscv/fp-const-synth-run.c: New test. > > * gcc.target/riscv/fp-const-synth-sf-rv32.c: New test. > > * gcc.target/riscv/fp-const-synth-sf.c: New test. > > * gcc.target/riscv/fp-const-synth-special-sf.c: New test. > > * gcc.target/riscv/fp-const-synth-zfa.c: New test. > Not a review, but a note that I believe this will resolve the remaining > issues with 110748 as -0.0 is just a bset dst, x0, 31/63 when ZBB is > available. More importantly I think as-written it should silently "just > work" for any constant we can easily synthesize. So I'm definitely > supportive of basic idea. Just need to get inside the implementation > details now. > > > Jeff
