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