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
