Hi Kito and all, Gentle ping for this v2 patch: https://inbox.sourceware.org/gcc-patches/CAHZ=VLp7qjp2cS2yYaqq5sYmEtyTnb9czwe=eo-1rwd4-+h...@mail.gmail.com/T/#u
Let me know if any updates are needed. Thanks, Meng-Tsung Tsai Meng-Tsung Tsai <[email protected]> 於 2025年12月21日週日 下午5:10寫道: > > When the target lacks standalone floating-point registers (FPRs), such > as in soft-float configurations or with the Zfinx extension, > floating-point values reside in general-purpose registers (GPRs). Which > means we may be able to materialize FP constants using int instruction. > > Currently, however, FP constants are typically loaded from constant > pool via memory loads, even when they reside in GPRs. > > This patch allows the compiler to materialize FP constants directly in > GPRs using integer instructions (e.g., lui, addi) if the target lacks > standalone FPRs and the cost is sufficiently low. > > For example, given the following C code: > float foo() { > // 0x3fc00000 > return 1.5f; > } > > Original codegen (with Zfinx): > foo(): > lui a5,%hi(.LC0) > lw a0,%lo(.LC0)(a5) > ret > .LC0: > .word 1069547520 > > After this patch: > foo(): > lui a0, 261120 # hex(261120) = 0x3FC00 > ret > > gcc/ChangeLog: > * config/riscv/predicates.md (move_operand): Disallow > CONST_DOUBLE for soft-float and zfinx to prevent reload from > forcing them to memory. > > * config/riscv/riscv.cc (riscv_const_fp_to_int): New static > helper function to get int representaion for a compile-time > const FP value. > (riscv_const_insns): Calculate cost for materializing FP > constants as integers when the target lacks standalone FPRs. > (riscv_legitimize_const_move): Attempt to materialize FP > constants using integer instructions. > > gcc/testsuite/ChangeLog: > * gcc.target/riscv/zfinx-const-li.c: New test for FP > materialization when zfinx-like extension is enabled. > > * gcc.target/riscv/softfloat-const-li.c: New test for FP > materialization when target is in softfloat mode. > > Signed-off-by: Meng-Tsung Tsai <[email protected]> > --- > Changes in v2: > - Extended the optimization scope from just Zfinx to all soft-float > targets (!TARGET_HARD_FLOAT). > > - Remove unneeded pattern from iterator.md > > - Moved the materialization logic to riscv_legitimize_const_move in > riscv.cc > > - Introduced a new helper function riscv_const_fp_to_int to get int > representaion for a compile-time const FP value. > > - A new test suite softfloat-const-li.c is introduced for rv32i/rv64i > target. > > > > gcc/config/riscv/predicates.md | 3 ++ > gcc/config/riscv/riscv.cc | 43 +++++++++++++++ > .../gcc.target/riscv/softfloat-const-li.c | 52 +++++++++++++++++++ > .../gcc.target/riscv/zfinx-const-li.c | 52 +++++++++++++++++++ > 4 files changed, 150 insertions(+) > create mode 100644 gcc/testsuite/gcc.target/riscv/softfloat-const-li.c > create mode 100644 gcc/testsuite/gcc.target/riscv/zfinx-const-li.c > > diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md > index 5b44165ec99..a79e5f7db76 100644 > --- a/gcc/config/riscv/predicates.md > +++ b/gcc/config/riscv/predicates.md > @@ -341,6 +341,9 @@ > case SUBREG: > return REG_P (SUBREG_REG (op)); > > + case CONST_DOUBLE: > + return TARGET_HARD_FLOAT; > + > default: > return true; > } > diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc > index 96519c96a2b..ccdfec65b46 100644 > --- a/gcc/config/riscv/riscv.cc > +++ b/gcc/config/riscv/riscv.cc > @@ -2579,6 +2579,22 @@ riscv_address_insns (rtx x, machine_mode mode, bool > might_split_p) > return n; > } > > +static unsigned HOST_WIDE_INT > +riscv_const_fp_to_int (rtx src, machine_mode mode) > +{ > + long target_vals[2] = {0}; > + real_to_target (target_vals, CONST_DOUBLE_REAL_VALUE (src), mode); > + > + int order = BYTES_BIG_ENDIAN ? 1 : 0; > + unsigned HOST_WIDE_INT lo = target_vals[order]; > + unsigned HOST_WIDE_INT hi = target_vals[1 - order]; > + unsigned HOST_WIDE_INT val = (hi << 32) | lo; > + > + val &= GET_MODE_MASK (mode); > + > + return val; > +} > + > /* Return the number of instructions needed to load constant X. > Return 0 if X isn't a valid constant. > > @@ -2614,6 +2630,16 @@ riscv_const_insns (rtx x, bool allow_new_pseudos) > if (satisfies_constraint_zfli (x)) > return 1; > > + /* When target support Zfinx-like extension, we can use li to > + materialize FP constants. */ > + if (!TARGET_HARD_FLOAT > + && known_le (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)) > + { > + unsigned HOST_WIDE_INT val = riscv_const_fp_to_int (x, GET_MODE (x)); > + int cost = riscv_integer_cost (val, allow_new_pseudos); > + return cost < 4 ? cost : 0; > + } > + > /* We can use x0 to load floating-point zero. */ > return x == CONST0_RTX (GET_MODE (x)) ? 1 : 0; > case CONST_VECTOR: > @@ -3437,6 +3463,23 @@ riscv_legitimize_const_move (machine_mode mode, rtx > dest, rtx src) > return; > } > > + /* We can use integer instructions to materialize FP constants for > + soft-float or Zfinx-like targets. */ > + bool fits_in_gpr = known_le (GET_MODE_SIZE (mode), UNITS_PER_WORD); > + if (!TARGET_HARD_FLOAT && GET_CODE (src) == CONST_DOUBLE && fits_in_gpr) > + { > + unsigned HOST_WIDE_INT val = riscv_const_fp_to_int (src, mode); > + val &= GET_MODE_MASK (mode); > + int cost = riscv_integer_cost (val, true); > + if (cost < 4) > + { > + machine_mode int_mode = int_mode_for_mode (mode).require (); > + rtx int_reg = gen_lowpart (int_mode, dest); > + riscv_move_integer (int_reg, int_reg, val, int_mode); > + return; > + } > + } > + > src = force_const_mem (mode, src); > > /* When using explicit relocs, constant pool references are sometimes > diff --git a/gcc/testsuite/gcc.target/riscv/softfloat-const-li.c > b/gcc/testsuite/gcc.target/riscv/softfloat-const-li.c > new file mode 100644 > index 00000000000..5c822ebbf20 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/softfloat-const-li.c > @@ -0,0 +1,52 @@ > +/* { dg-do compile } */ > +/* { dg-options "-march=rv64i -mabi=lp64" { target rv64 } } */ > +/* { dg-options "-march=rv32i -mabi=ilp32" { target rv32 } } */ > +/* { dg-skip-if "" { *-*-* } { "-O0" } } */ > + > +float foo_sf () { > + /* 1.5f = 0x3fc00000 in float */ > + > + /* > + li a0,1069547520 > + ret > + */ > + return 1.5; > +} > + > +double foo_df () { > + /* 1.5f = 0x3ff8000000000000 in double */ > + > + /* > + target rv64: > + li a0,2047 > + slli a0,a0,51 > + ret > + > + target rv32: > + lui a5,%hi(.LC0) > + lw a0,%lo(.LC0)(a5) > + lw a1,%lo(.LC0+4)(a5) > + ret > + .LC0: > + .word 0 > + .word 1073217536 > + */ > + return 1.5; > +} > + > +_Float16 foo_hf () { > + /* 1.5 = 0x3e00 in half-float */ > + > + /* > + li a0,16384 > + addi a0,a0,-512 > + ret > + */ > + return 1.5; > +} > + > +/* { dg-final { scan-assembler "li|lui" } } */ > +/* For rv64 target, there should be no lw */ > +/* { dg-final { scan-assembler-not "\tlw\t" { target { rv64 } } } } */ > +/* For rv32 target, only foo_df will emit 2 lw */ > +/* { dg-final { scan-assembler-times "\tlw\t" 2 { target { rv32 } } } } */ > diff --git a/gcc/testsuite/gcc.target/riscv/zfinx-const-li.c > b/gcc/testsuite/gcc.target/riscv/zfinx-const-li.c > new file mode 100644 > index 00000000000..b0a312fbf65 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/zfinx-const-li.c > @@ -0,0 +1,52 @@ > +/* { dg-do compile } */ > +/* { dg-options "-march=rv64i_zfinx -mabi=lp64" { target rv64 } } */ > +/* { dg-options "-march=rv32i_zfinx -mabi=ilp32" { target rv32 } } */ > +/* { dg-skip-if "" { *-*-* } { "-O0" } } */ > + > +float foo_sf () { > + /* 1.5f = 0x3fc00000 in float */ > + > + /* > + li a0,1069547520 > + ret > + */ > + return 1.5; > +} > + > +double foo_df () { > + /* 1.5f = 0x3ff8000000000000 in double */ > + > + /* > + target rv64: > + li a0,2047 > + slli a0,a0,51 > + ret > + > + target rv32: > + lui a5,%hi(.LC0) > + lw a0,%lo(.LC0)(a5) > + lw a1,%lo(.LC0+4)(a5) > + ret > + .LC0: > + .word 0 > + .word 1073217536 > + */ > + return 1.5; > +} > + > +_Float16 foo_hf () { > + /* 1.5 = 0x3e00 in half-float */ > + > + /* > + li a0,16384 > + addi a0,a0,-512 > + ret > + */ > + return 1.5; > +} > + > +/* { dg-final { scan-assembler "li|lui" } } */ > +/* For rv64 target, there should be no lw */ > +/* { dg-final { scan-assembler-not "\tlw\t" { target { rv64 } } } } */ > +/* For rv32 target, only foo_df will emit 2 lw */ > +/* { dg-final { scan-assembler-times "\tlw\t" 2 { target { rv32 } } } } */ > -- > 2.43.0 >
