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
>

Reply via email to