]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[RISC-V][PR target/118241] Fix data prefetch predicate/constraint for RISC-V
authorJeff Law <jlaw@ventanamicro.com>
Sat, 21 Jun 2025 14:24:58 +0000 (08:24 -0600)
committerJeff Law <jlaw@ventanamicro.com>
Sat, 21 Jun 2025 14:26:33 +0000 (08:26 -0600)
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.

gcc/config/riscv/constraints.md
gcc/config/riscv/predicates.md
gcc/config/riscv/riscv.md
gcc/testsuite/gcc.target/riscv/pr118241.c [new file with mode: 0644]

index 58355cf03f2fd56f2295dd7470f0519fff45809a..ccab1a2e29dfa0f7ba3bbcd24d0d81b7ebac19db 100644 (file)
   "A 2-bit unsigned immediate."
   (and (match_code "const_int")
        (match_test "IN_RANGE (ival, 0, 3)")))
+
+(define_constraint "Q"
+  "An address operand that is valid for a prefetch instruction"
+  (match_operand 0 "prefetch_operand"))
index 23690792b32e645a2e588625be95d513185b158b..8072d67fbd97ad9a88ba3c148cc5c76be1845848 100644 (file)
   (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))")))
index 3aed25c2588042e89f654a19ee892b7b02ef99a4..3406b50518edcf923accd8c776a9532b8a53d8fc 100644 (file)
 )
 
 (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"
                                      (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 (file)
index 0000000..f1dc44b
--- /dev/null
@@ -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 } } */
+