https://gcc.gnu.org/g:36b3488034929c2ff02c6a4a1946ea81376200a4

commit r16-1570-g36b3488034929c2ff02c6a4a1946ea81376200a4
Author: Kito Cheng <kito.ch...@sifive.com>
Date:   Tue Jun 17 12:56:17 2025 +0800

    RISC-V: Adding cost model for zilsd
    
    Motivation of this patch is we want to use ld/sd if possible when zilsd
    is enabled, however the subreg pass may split that into two lw/sw
    instructions because the cost, and it only check cost for 64 bits reg move,
    that's why we need adjust cost for 64 bit reg move as well.
    
    However even we adjust the cost model, 64 bit shift still use 32 bit
    load because it already got split at expand time, this may need to fix
    on the expander side, and this apparently need few more time to
    investigate, so I just added a testcase with XFAIL to show the current 
behavior,
    and we can fix that...when we have time.
    
    For long term, we may adding a new field to riscv_tune_param to control
    the cost model for that.
    
    gcc/ChangeLog:
    
            * config/riscv/riscv.cc (riscv_cost_model): Add cost model for
            zilsd.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/riscv/zilsd-code-gen-split-subreg-1.c: New test.
            * gcc.target/riscv/zilsd-code-gen-split-subreg-2.c: New test.

Diff:
---
 gcc/config/riscv/riscv.cc                          | 41 ++++++++++++++++++++++
 .../riscv/zilsd-code-gen-split-subreg-1.c          | 12 +++++++
 .../riscv/zilsd-code-gen-split-subreg-2.c          | 16 +++++++++
 3 files changed, 69 insertions(+)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index de8bde948f66..7de12f41c113 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -814,6 +814,16 @@ void riscv_frame_info::reset(void)
   arg_pointer_offset = 0;
 }
 
+/* Check if the mode is twice the size of the XLEN mode.  */
+
+static bool
+riscv_2x_xlen_mode_p (machine_mode mode)
+{
+  poly_int64 mode_size = GET_MODE_SIZE (mode);
+  return mode_size.is_constant ()
+        && (mode_size.to_constant () == UNITS_PER_WORD * 2);
+}
+
 /* Implement TARGET_MIN_ARITHMETIC_PRECISION.  */
 
 static unsigned int
@@ -4023,10 +4033,41 @@ riscv_rtx_costs (rtx x, machine_mode mode, int 
outer_code, int opno ATTRIBUTE_UN
              *total = COSTS_N_INSNS (1);
              return true;
            }
+
+         /* Register move for XLEN * 2.  */
+         if (TARGET_ZILSD
+             && register_operand (SET_SRC (x), GET_MODE (SET_SRC (x)))
+             && riscv_2x_xlen_mode_p (mode))
+           {
+             /* We still need two instruction for move with ZILSD,
+                but let minus one cost to let subreg split don't.
+                TODO: Add riscv_tune_param for this.  */
+             *total = COSTS_N_INSNS (2) - 1;
+             return true;
+           }
+
+         /* Load for XLEN * 2.  */
+         if (TARGET_ZILSD && MEM_P (SET_SRC (x))
+             && riscv_2x_xlen_mode_p (mode))
+           {
+             /* TODO: Add riscv_tune_param for this.  */
+             *total = COSTS_N_INSNS (1);
+             return true;
+           }
+
          riscv_rtx_costs (SET_SRC (x), mode, SET, opno, total, speed);
          return true;
        }
 
+      /* Store for XLEN * 2.  */
+      if (TARGET_ZILSD && MEM_P (SET_DEST (x)) && REG_P (SET_SRC (x))
+         && riscv_2x_xlen_mode_p (mode))
+       {
+         /* TODO: Add riscv_tune_param for this.  */
+         *total = COSTS_N_INSNS (1);
+         return true;
+       }
+
       /* Otherwise return FALSE indicating we should recurse into both the
         SET_DEST and SET_SRC combining the cost of both.  */
       return false;
diff --git a/gcc/testsuite/gcc.target/riscv/zilsd-code-gen-split-subreg-1.c 
b/gcc/testsuite/gcc.target/riscv/zilsd-code-gen-split-subreg-1.c
new file mode 100644
index 000000000000..36026269c13a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zilsd-code-gen-split-subreg-1.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32i_zilsd -mabi=ilp32" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+long long y;
+long long foo(long long x)
+{
+    return y + x;
+}
+
+/* { dg-final { scan-assembler-times "ld\t" 1 } } */
+/* { dg-final { scan-assembler-not "lw\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zilsd-code-gen-split-subreg-2.c 
b/gcc/testsuite/gcc.target/riscv/zilsd-code-gen-split-subreg-2.c
new file mode 100644
index 000000000000..3adcd21ea061
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zilsd-code-gen-split-subreg-2.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32i_zilsd -mabi=ilp32" } */
+
+long long y;
+long long foo(long long x)
+{
+    return y >> x;
+}
+/* TODO: We should not split that 64 bit load into two 32 bit load if we have
+   zilsd, but we split that during the expand time, so it's hard to fix via 
cost
+   model turning, we could either fix that for expander, or...combine those two
+   32 bit load back later.  */
+/* { dg-final { scan-assembler-times "ld\t" 1 { xfail riscv*-*-*  } } } */
+
+/* Os and Oz will use libcall, so the 64 bit load won't be split.  */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" } } */

Reply via email to