This is based on Zhijin Zeng's v3 patch
(https://gcc.gnu.org/pipermail/gcc-patches/2025-January/673406.html).
This commit modifies riscv_can_change_mode_class and
riscv_hard_regno_mode_ok to allow IRA to allocate an FPR to a pseudo
that is used in a interger mode in some places.

A typical scenario would be cases with bit-level uses of floating-point
variables.  The current IRA can only allocate them in GPRs, and any FP
use of it would create a new FPR reload, which can lead to lots of
redundant fmv.d.x instructions in the function.  The attached case
(LLM-generated) is a reduced one that can still show the underlying
issue.

I am not using Zhijin's original testcase in this version because
register renaming has accidentally helped eliminate the redundant fmv
instructions in that case.

Also note that the tiebility change in that patch is not included in
this version.  We found that change can lead to more regressions and
would require special handling.  Nonetheless, we found one redundant
fmv.x.d instruction in our complete lgamma case downstream, not verified
with the trunk though, which can be eliminated with the tieability
change.  (After all, FP and integer modes being tieable makes it hard
track separate live ranges of integer uses and FP uses of the same
variable.)  We may submit a separate tieability patch after gathering
enough evidence that this could lead to real performance issues.

Regtested on rv64gcv and rv32gcv, no regression.

Assisted-by: Codex
Co-authored-by: Zhijin Zeng <[email protected]>

gcc/ChangeLog:

        * config/riscv/riscv.cc (riscv_hard_regno_mode_ok): Allow SImode
        and DImode in GPRs.
        (riscv_can_change_mode_class): Allow mode changing between
        integer and FP modes.
        * config/riscv/riscv.md: Add f,f constraints to SI and HI moves.
        * config/riscv/vector.md: Restore X constraint for vr,vr LRA
        move patterns to prevent ICE caused by FPR-allocated scratch.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/fmv-lgamma.c: New test.
---
 gcc/config/riscv/riscv.cc                   | 29 ++++++++++++++++++++-
 gcc/config/riscv/riscv.md                   | 20 +++++++-------
 gcc/config/riscv/vector.md                  |  6 ++---
 gcc/testsuite/gcc.target/riscv/fmv-lgamma.c | 20 ++++++++++++++
 4 files changed, 61 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/fmv-lgamma.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index f8b54fc4ae6..0b502515d67 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -11535,7 +11535,10 @@ riscv_hard_regno_mode_ok (unsigned int regno, 
machine_mode mode)
        return false;
 
       if (GET_MODE_CLASS (mode) != MODE_FLOAT
-         && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
+         && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT
+         && !((mode == DImode && TARGET_DOUBLE_FLOAT && TARGET_64BIT)
+              || (mode == SImode && TARGET_HARD_FLOAT)
+              || (mode == HImode && TARGET_ZFHMIN)))
        return false;
 
       /* Only use callee-saved registers if a potential callee is guaranteed
@@ -13181,6 +13184,30 @@ riscv_can_change_mode_class (machine_mode from, 
machine_mode to,
       && !ordered_p (BITS_PER_RISCV_VECTOR, GET_MODE_PRECISION (from)))
       return false;
 
+  if ((SCALAR_INT_MODE_P (to) || SCALAR_FLOAT_MODE_P (to))
+      && (rclass == FP_REGS || rclass == RVC_FP_REGS
+         || rclass == GR_REGS || rclass == RVC_GR_REGS
+         || rclass == JALR_REGS))
+    {
+      /* fmv.x.w or fmv.w.x.  */
+      if (TARGET_HARD_FLOAT)
+       if ((from == SFmode && to == SImode)
+           || (from == SImode && to == SFmode))
+         return true;
+
+      /* fmv.x.d or fmv.d.x.  */
+      if (TARGET_DOUBLE_FLOAT && TARGET_64BIT)
+       if ((from == DFmode && to == DImode)
+           || (from == DImode && to == DFmode))
+         return true;
+
+      /* fmv.x.h or fmv.h.x.  */
+      if (TARGET_ZFHMIN)
+       if ((from == HFmode && to == HImode)
+           || (from == HImode && to == HFmode))
+         return true;
+    }
+
   return !reg_classes_intersect_p (FP_REGS, rclass);
 }
 
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index bd308e3d056..e6f0d053a5d 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -2657,16 +2657,16 @@ (define_expand "mov<mode>"
 })
 
 (define_insn "*movsi_internal"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r, m,  *f,*f,*r,*m,r")
-       (match_operand:SI 1 "move_operand"         " 
r,T,m,rJ,*r*J,*m,*f,*f,vp"))]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r, m,  
*f,*f,*r,*f,*m,r")
+       (match_operand:SI 1 "move_operand"         " 
r,T,m,rJ,*r*J,*m,*f,*f,*f,vp"))]
   "(register_operand (operands[0], SImode)
     || reg_or_0_operand (operands[1], SImode))
     && !(REG_P (operands[1]) && VL_REG_P (REGNO (operands[1])))"
   { return riscv_output_move (operands[0], operands[1]); }
-  [(set_attr "move_type" 
"move,const,load,store,mtc,fpload,mfc,fpstore,rdvlenb")
+  [(set_attr "move_type" 
"move,const,load,store,mtc,fpload,mfc,fmove,fpstore,rdvlenb")
    (set_attr "mode" "SI")
-   (set_attr "type" "move,move,load,store,mtc,fpload,mfc,fpstore,move")
-   (set_attr "ext" "base,base,base,base,f,f,f,f,vector")])
+   (set_attr "type" "move,move,load,store,mtc,fpload,mfc,fmove,fpstore,move")
+   (set_attr "ext" "base,base,base,base,f,f,f,f,f,vector")])
 
 ;; 16-bit Integer moves
 
@@ -2685,15 +2685,15 @@ (define_expand "movhi"
 })
 
 (define_insn "*movhi_internal"
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r, m,  *f,*r,r")
-       (match_operand:HI 1 "move_operand"         " r,T,m,rJ,*r*J,*f,vp"))]
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r, m,  *f,*r,*f,r")
+       (match_operand:HI 1 "move_operand"         " r,T,m,rJ,*r*J,*f,*f,vp"))]
   "(register_operand (operands[0], HImode)
     || reg_or_0_operand (operands[1], HImode))"
   { return riscv_output_move (operands[0], operands[1]); }
-  [(set_attr "move_type" "move,const,load,store,mtc,mfc,rdvlenb")
+  [(set_attr "move_type" "move,const,load,store,mtc,mfc,fmove,rdvlenb")
    (set_attr "mode" "HI")
-   (set_attr "type" "move,move,load,store,mtc,mfc,move")
-   (set_attr "ext" "base,base,base,base,f,f,vector")])
+   (set_attr "type" "move,move,load,store,mtc,mfc,fmove,move")
+   (set_attr "ext" "base,base,base,base,f,f,f,vector")])
 
 ;; HImode constant generation; see riscv_move_integer for details.
 ;; si+si->hi without truncation is legal because of
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index e760f708faf..6ddd456172e 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -1349,7 +1349,7 @@ (define_expand "@mov<VB:mode><P:mode>_lra"
 (define_insn_and_split "*mov<V_FRACT:mode><P:mode>_lra"
   [(set (match_operand:V_FRACT 0 "reg_or_mem_operand" "=vr, m,vr")
        (match_operand:V_FRACT 1 "reg_or_mem_operand" "  m,vr,vr"))
-   (clobber (match_scratch:P 2 "=&r,&r,r"))]
+   (clobber (match_operand:P 2 "" "=&r,&r,X"))]
   "TARGET_VECTOR && (lra_in_progress || reload_completed)"
   "#"
   "&& reload_completed"
@@ -1371,7 +1371,7 @@ (define_insn_and_split "*mov<V_FRACT:mode><P:mode>_lra"
 (define_insn_and_split "*mov<VB:mode><P:mode>_lra"
   [(set (match_operand:VB 0 "reg_or_mem_operand" "=vr, m,vr")
        (match_operand:VB 1 "reg_or_mem_operand" "  m,vr,vr"))
-   (clobber (match_scratch:P 2 "=&r,&r,r"))]
+   (clobber (match_operand:P 2 "" "=&r,&r,X"))]
   "TARGET_VECTOR && (lra_in_progress || reload_completed)"
   "#"
   "&& reload_completed"
@@ -1499,7 +1499,7 @@ (define_expand "@mov<VLS_AVL_REG:mode><P:mode>_lra"
 (define_insn_and_split "*mov<VLS_AVL_REG:mode><P:mode>_lra"
   [(set (match_operand:VLS_AVL_REG 0 "reg_or_mem_operand" "=vr, m,vr")
        (match_operand:VLS_AVL_REG 1 "reg_or_mem_operand" "  m,vr,vr"))
-   (clobber (match_scratch:P 2 "=&r,&r,r"))]
+   (clobber (match_operand:P 2 "" "=&r,&r,X"))]
   "TARGET_VECTOR && (lra_in_progress || reload_completed)
    && (register_operand (operands[0], <VLS_AVL_REG:MODE>mode)
        || register_operand (operands[1], <VLS_AVL_REG:MODE>mode))"
diff --git a/gcc/testsuite/gcc.target/riscv/fmv-lgamma.c 
b/gcc/testsuite/gcc.target/riscv/fmv-lgamma.c
new file mode 100644
index 00000000000..dabd143d212
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fmv-lgamma.c
@@ -0,0 +1,20 @@
+/* { dg-do compile { target { rv64 } } } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -mtune=xt-c9501fdvt" } */
+
+/* Keep the floating-point value in an FPR when its bits are also used by
+   an integer comparison.  Reduced from lgamma.  */
+
+double
+f (double x)
+{
+  if (((union { double d; unsigned long u; }) { x }).u)
+    return 0;
+
+  return x * (x * 3);
+}
+
+/* The floating-point operations must not reload x from a GPR or a spill
+   slot after the integer comparison.  Allow fmv.d.x from zero, which
+   constructs the return value of zero.  */
+/* { dg-final { scan-assembler-not {\tfmv\.d\.x\t[^,\n]+,(?!zero)} } } */
+/* { dg-final { scan-assembler-not {\tfsd\t} } } */
-- 
2.47.1

Reply via email to