]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
RISC-V: Fix multiple bugs in riscv_macro_fusion_pair_p
authorJin Ma <jinma@linux.alibaba.com>
Tue, 19 May 2026 09:31:27 +0000 (17:31 +0800)
committerJin Ma <jinma@linux.alibaba.com>
Tue, 26 May 2026 02:12:59 +0000 (10:12 +0800)
Fix several correctness and minor issues in the fusion pair
matching logic:

XINT (prev_set, 1) in RISCV_FUSE_AUIPC_LD incorrectly accesses
the SET node rather than its UNSPEC source operand.  Use
XINT (SET_SRC (prev_set), 1) to match riscv_fuse_auipc_addi.

RISCV_FUSE_CACHE_ALIGNED_STD compared base registers with != instead
of ==, causing it to match stores with different bases rather than
the same base which is required for cache-line alignment analysis.

RISCV_FUSE_B_ALUI sub+smax pattern had a redundant CONST_INT_P
check on the same operand already validated by the CONST0_RTX
comparison.

RISCV_FUSE_LDINDEXED had a duplicate REG_P check on the same
operand.

Also fix a typo ("hte" -> "the") in a comment and correct the
dump output string from "RISCV_FUSE_ALIGNED_STD" to
"RISCV_FUSE_CACHE_ALIGNED_STD" for the cache-aligned case.

Tests are marked XFAIL as no upstream mtune currently enables
AUIPC_LD, CACHE_ALIGNED_STD, B_ALUI, or LDINDEXED.  The
existing fusion-auipc-addi.c test indirectly validates the
XINT fix since AUIPC_ADDI shares the same UNSPEC_AUIPC check
code path.

gcc/ChangeLog:

* config/riscv/riscv-fusion.cc (riscv_macro_fusion_pair_p):
Fix XINT to access SET_SRC (prev_set) in AUIPC_LD case.
Fix base register comparison from != to == in
CACHE_ALIGNED_STD case.  Remove redundant CONST_INT_P
check in B_ALUI sub+smax case.  Remove duplicate REG_P
check in LDINDEXED case.  Fix typo in comment.  Fix dump
output name for CACHE_ALIGNED_STD.

gcc/testsuite/ChangeLog:

* gcc.target/riscv/fusion-auipc-ld.c: New test.
* gcc.target/riscv/fusion-b-alui.c: New test.
* gcc.target/riscv/fusion-cache-aligned-std.c: New test.
* gcc.target/riscv/fusion-ldindexed.c: New test.

gcc/config/riscv/riscv-fusion.cc
gcc/testsuite/gcc.target/riscv/fusion-auipc-ld.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/fusion-b-alui.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/fusion-cache-aligned-std.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/fusion-ldindexed.c [new file with mode: 0644]

index 5bce3eda0a6c4db01f7000ce4072278767cf2708..990eab405a64aae43dceeeb3277711694031774b 100644 (file)
@@ -226,7 +226,6 @@ riscv_macro_fusion_pair_p (rtx_insn *prev, rtx_insn *curr)
       if (MEM_P (SET_SRC (curr_set))
          && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))
          && REG_P (XEXP (SET_SRC (curr_set), 0))
-         && REG_P (XEXP (SET_SRC (curr_set), 0))
          && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno
          && GET_CODE (SET_SRC (prev_set)) == PLUS
          && REG_P (XEXP (SET_SRC (prev_set), 0))
@@ -524,7 +523,7 @@ riscv_macro_fusion_pair_p (rtx_insn *prev, rtx_insn *curr)
                              (mem:DI (plus:DI (reg:DI rD) (const_int IMM12)))) */
 
       if (GET_CODE (SET_SRC (prev_set)) == UNSPEC
-         && XINT (prev_set, 1) == UNSPEC_AUIPC
+         && XINT (SET_SRC (prev_set), 1) == UNSPEC_AUIPC
          && MEM_P (SET_SRC (curr_set))
          && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))
          && GET_CODE (XEXP (SET_SRC (curr_set), 0)) == PLUS)
@@ -560,8 +559,8 @@ riscv_macro_fusion_pair_p (rtx_insn *prev, rtx_insn *curr)
             bases are the same register.  */
          if (base_prev != NULL_RTX && base_curr != NULL_RTX
              && REG_P (base_prev) && REG_P (base_curr)
-             && REGNO (base_prev) != REGNO (base_curr)
-             /* The alignment of hte base pointer is more useful than the
+             && REGNO (base_prev) == REGNO (base_curr)
+             /* The alignment of the base pointer is more useful than the
                 alignment of the memory reference for determining if we're
                 on opposite sides of a cache line.  */
              && REGNO_POINTER_ALIGN (ORIGINAL_REGNO (base_prev)) >= 128)
@@ -582,7 +581,7 @@ riscv_macro_fusion_pair_p (rtx_insn *prev, rtx_insn *curr)
                  && (INTVAL (offset_prev) + 8 == INTVAL (offset_curr)))
                {
                  if (dump_file)
-                   fprintf (dump_file, "RISCV_FUSE_ALIGNED_STD\n");
+                   fprintf (dump_file, "RISCV_FUSE_CACHE_ALIGNED_STD\n");
                  return true;
                }
            }
@@ -720,7 +719,6 @@ riscv_macro_fusion_pair_p (rtx_insn *prev, rtx_insn *curr)
       if (GET_CODE (SET_SRC (prev_set)) == MINUS
          && (XEXP (SET_SRC (prev_set), 0)
              == CONST0_RTX (GET_MODE (SET_SRC (prev_set))))
-         && CONST_INT_P (XEXP (SET_SRC (prev_set), 0))
          && GET_CODE (SET_SRC (curr_set)) == SMAX
          && REG_P (SET_DEST (prev_set))
          && REG_P (SET_DEST (curr_set))
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-auipc-ld.c b/gcc/testsuite/gcc.target/riscv/fusion-auipc-ld.c
new file mode 100644 (file)
index 0000000..e3a24e4
--- /dev/null
@@ -0,0 +1,16 @@
+/* Verify RISCV_FUSE_AUIPC_LD correctly matches auipc+ld pairs.
+   This exercises the fix for XINT accessing SET_SRC (prev_set)
+   instead of prev_set directly.  */
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Os" "-Oz" "-flto" } } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -mtune=sifive-p600-series -mcmodel=medany -mexplicit-relocs -fno-section-anchors -fdump-rtl-sched1" } */
+/* No upstream mtune currently enables RISCV_FUSE_AUIPC_LD.  */
+/* { dg-final { scan-rtl-dump "RISCV_FUSE_AUIPC_LD" "sched1" { xfail *-*-* } } } */
+
+extern long x;
+
+long
+load_global (void)
+{
+  return x;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-b-alui.c b/gcc/testsuite/gcc.target/riscv/fusion-b-alui.c
new file mode 100644 (file)
index 0000000..3ae0295
--- /dev/null
@@ -0,0 +1,13 @@
+/* Verify RISCV_FUSE_B_ALUI correctly matches sub+smax (abs) pattern.
+   This exercises the removal of the redundant CONST_INT_P check.  */
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Os" "-Oz" "-flto" } } */
+/* { dg-options "-march=rv64gc_zbb -mabi=lp64d -mtune=sifive-p600-series -fdump-rtl-sched1" } */
+/* No upstream mtune currently enables RISCV_FUSE_B_ALUI.  */
+/* { dg-final { scan-rtl-dump "RISCV_FUSE_B_ALUI" "sched1" { xfail *-*-* } } } */
+
+long
+abs_val (long x)
+{
+  return x < 0 ? -x : x;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-cache-aligned-std.c b/gcc/testsuite/gcc.target/riscv/fusion-cache-aligned-std.c
new file mode 100644 (file)
index 0000000..5484e0c
--- /dev/null
@@ -0,0 +1,21 @@
+/* Verify RISCV_FUSE_CACHE_ALIGNED_STD correctly matches consecutive
+   stores to the same cache line.  This exercises the fix for base
+   register comparison (changed from != to ==).  */
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Os" "-Oz" "-flto" } } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -mtune=sifive-p600-series -fdump-rtl-sched1" } */
+/* No upstream mtune currently enables RISCV_FUSE_CACHE_ALIGNED_STD.  */
+/* { dg-final { scan-rtl-dump "RISCV_FUSE_CACHE_ALIGNED_STD" "sched1" { xfail *-*-* } } } */
+
+struct pair
+{
+  long a;
+  long b;
+} __attribute__ ((aligned (16)));
+
+void
+store_pair (struct pair *p, long x, long y)
+{
+  p->a = x;
+  p->b = y;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-ldindexed.c b/gcc/testsuite/gcc.target/riscv/fusion-ldindexed.c
new file mode 100644 (file)
index 0000000..7687ede
--- /dev/null
@@ -0,0 +1,13 @@
+/* Verify RISCV_FUSE_LDINDEXED correctly matches add+ld pairs.
+   This exercises the removal of the duplicate REG_P check.  */
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Os" "-Oz" "-flto" } } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -mtune=sifive-p600-series -fdump-rtl-sched1" } */
+/* No upstream mtune currently enables RISCV_FUSE_LDINDEXED.  */
+/* { dg-final { scan-rtl-dump "RISCV_FUSE_LDINDEXED" "sched1" { xfail *-*-* } } } */
+
+long
+load_indexed (long *base, long idx)
+{
+  return base[idx];
+}