https://gcc.gnu.org/g:4157d433df1ccc30ca2db2e4e9448318d730299f

commit r15-9969-g4157d433df1ccc30ca2db2e4e9448318d730299f
Author: Jeff Law <j...@ventanamicro.com>
Date:   Sat Jun 21 08:24:58 2025 -0600

    [RISC-V][PR target/118241] Fix data prefetch predicate/constraint for RISC-V
    
    The RISC-V prefetch support is broken in a few ways.  This addresses the 
data
    side prefetch problems.  I'd mistakenly thought this BZ was a prefetch.i
    related (which has deeper problems).
    
    The basic problem is we were accepting any valid address when in fact there 
are
    restrictions.  This patch more precisely defines the predicate such that we
    allow
    
    REG
    REG+D
    
    Where D must have the low 5 bits clear.  Note that absolute addresses fall 
into
    the REG+D form using the x0 for the register operand since it always has the
    value zero.  The test verifies REG, REG+D, ABS addressing modes that are 
valid
    as well as REG+D and ABS which must be reloaded into a REG because the
    displacement has low bits set.
    
    An earlier version of this patch has gone through testing in my tester on 
rv32
    and rv64.  Obviously I'll wait for pre-commit CI to do its thing before 
moving
    forward.
    
    This is a good backport candidate after simmering on the trunk for a bit.
    
            PR target/118241
    gcc/
            * config/riscv/predicates.md (prefetch_operand): New predicate.
            * config/riscv/constraints.md (Q): New constraint.
            * config/riscv/riscv.md (prefetch): Use new predicate and 
constraint.
            (riscv_prefetchi_<mode>): Similarly.
    
    gcc/testsuite/
            * gcc.target/riscv/pr118241.c: New test.
    
    (cherry picked from commit 49199bb29628365fc6c60bd185808a1bad65086d)

Diff:
---
 gcc/config/riscv/constraints.md           |  4 ++++
 gcc/config/riscv/predicates.md            | 12 ++++++++++++
 gcc/config/riscv/riscv.md                 |  4 ++--
 gcc/testsuite/gcc.target/riscv/pr118241.c | 16 ++++++++++++++++
 4 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
index ba3c6e6a4c44..073336613dea 100644
--- a/gcc/config/riscv/constraints.md
+++ b/gcc/config/riscv/constraints.md
@@ -311,3 +311,7 @@
   "Shifting immediate for SIMD shufflei3."
   (and (match_code "const_int")
        (match_test "IN_RANGE (ival, -64, -1)")))
+
+(define_constraint "Q"
+  "An address operand that is valid for a prefetch instruction"
+  (match_operand 0 "prefetch_operand"))
diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
index f26bafcc688b..3d08c9ba979e 100644
--- a/gcc/config/riscv/predicates.md
+++ b/gcc/config/riscv/predicates.md
@@ -27,6 +27,18 @@
   (ior (match_operand 0 "const_arith_operand")
        (match_operand 0 "register_operand")))
 
+;; REG or REG+D where D fits in a simm12 and has the low 4 bits
+;; off.  The REG+D form can be reloaded into a temporary if needed
+;; after FP elimination if that exposes an invalid offset.
+(define_predicate "prefetch_operand"
+  (ior (match_operand 0 "register_operand")
+       (and (match_test "const_arith_operand (op, VOIDmode)")
+           (match_test "(INTVAL (op) & 0xf) == 0"))
+       (and (match_code "plus")
+           (match_test "register_operand (XEXP (op, 0), word_mode)")
+           (match_test "const_arith_operand (XEXP (op, 1), VOIDmode)")
+           (match_test "(INTVAL (XEXP (op, 1)) & 0xf) == 0"))))
+
 (define_predicate "lui_operand"
   (and (match_code "const_int")
        (match_test "LUI_OPERAND (INTVAL (op))")))
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 32c8e7147a30..61708681f1e2 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -4378,7 +4378,7 @@
 )
 
 (define_insn "prefetch"
-  [(prefetch (match_operand 0 "address_operand" "r")
+  [(prefetch (match_operand 0 "prefetch_operand" "Q")
              (match_operand 1 "imm5_operand" "i")
              (match_operand 2 "const_int_operand" "n"))]
   "TARGET_ZICBOP"
@@ -4398,7 +4398,7 @@
                                      (const_string "4")))])
 
 (define_insn "riscv_prefetchi_<mode>"
-  [(unspec_volatile:X [(match_operand:X 0 "address_operand" "r")
+  [(unspec_volatile:X [(match_operand:X 0 "prefetch_operand" "Q")
               (match_operand:X 1 "imm5_operand" "i")]
               UNSPECV_PREI)]
   "TARGET_ZICBOP"
diff --git a/gcc/testsuite/gcc.target/riscv/pr118241.c 
b/gcc/testsuite/gcc.target/riscv/pr118241.c
new file mode 100644
index 000000000000..f1dc44bce0ca
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr118241.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicbop" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicbop" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+void test1() { __builtin_prefetch((int *)2047); }
+void test2() { __builtin_prefetch((int *)1024); }
+void test3(char *x) { __builtin_prefetch(&x); }
+void test4(char *x) { __builtin_prefetch(&x[2]); }
+void test5(char *x) { __builtin_prefetch(&x[1024]); }
+
+/* So we expect test1, test3 and test4 to be a prefetch
+   with zero offset.  test2 and test5 will have a 1k offset.  */
+/* { dg-final { scan-assembler-times "prefetch.r\t0\\(\[a-x0-9\]+\\)" 3 } } */
+/* { dg-final { scan-assembler-times "prefetch.r\t1024" 2 } } */
+

Reply via email to