https://gcc.gnu.org/g:d4e6fc510f90b0e6895841febfa9da8858653cfe

commit r16-6299-gd4e6fc510f90b0e6895841febfa9da8858653cfe
Author: Robin Dapp <[email protected]>
Date:   Thu Dec 18 11:19:57 2025 +0100

    RISC-V: Fix overflow check in interleave pattern [PR122970].
    
    In the pattern where we interpret and code-gen two interleaving series as if
    they were represented in a larger type we check for overflow.
    The overflow check is basically
     if (base + (nelems - 1) * step >> inner_bits != 0)
         overflow = true;
    
    In the PR, base is negative and we interpret it as negative uint64
    value.  Thus, e.g. base + (nelems - 1) * step  = -32 + 7 * 8 = 24.
    24 fits uint8 and we wrongly assume that no overflow happens.
    
    This patch reinterprets base as type of inner bit size which makes the
    overflow check work.
    
            PR target/122970
    
    gcc/ChangeLog:
    
            * config/riscv/riscv-v.cc 
(expand_const_vector_interleaved_stepped_npatterns):
            Reinterpret base as smaller type.
    
    gcc/testsuite/ChangeLog:
    
            * lib/target-supports.exp: Add rvv_zvl128b_ok.
            * gcc.target/riscv/rvv/autovec/pr122970.c: New test.

Diff:
---
 gcc/config/riscv/riscv-v.cc                        |  6 +-
 .../gcc.target/riscv/rvv/autovec/pr122970.c        | 71 ++++++++++++++++++++++
 gcc/testsuite/lib/target-supports.exp              | 18 ++++++
 3 files changed, 94 insertions(+), 1 deletion(-)

diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index 321b5172783d..d64acff8e0f8 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -1632,7 +1632,11 @@ expand_const_vector_interleaved_stepped_npatterns (rtx 
target, rtx src,
     {
       int elem_count = XVECLEN (src, 0);
       uint64_t step1_val = step1.to_constant ();
-      uint64_t base1_val = base1_poly.to_constant ();
+      int64_t base1_signed = base1_poly.to_constant ();
+      /* Reinterpret as type of inner bits size so we can properly check
+        overflow.  */
+      uint64_t base1_val
+       = base1_signed & ((1ULL << builder->inner_bits_size ()) - 1);
       uint64_t elem_val = base1_val + (elem_count - 1) * step1_val;
 
       if ((elem_val >> builder->inner_bits_size ()) != 0)
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122970.c 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122970.c
new file mode 100644
index 000000000000..be2ac4a62aeb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122970.c
@@ -0,0 +1,71 @@
+/* { dg-do run } */
+/* { dg-require-effective-target riscv_v_ok } */
+/* { dg-require-effective-target rvv_zvl128b_ok } */
+/* { dg-require-effective-target rv64 } */
+/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -mrvv-vector-bits=zvl 
-mrvv-max-lmul=m4" } */
+
+typedef unsigned char uint8_t;
+
+void
+f (uint8_t *restrict a, uint8_t *restrict c, uint8_t *restrict d, int n)
+{
+  for (int i = 0; i < n; ++i)
+    {
+      a[i * 8] = c[i * 8] + d[i * 8];
+      a[i * 8 + 1] = c[i * 8] + d[i * 8 + 1];
+      a[i * 8 + 2] = c[i * 8 + 2] + d[i * 8 + 2];
+      a[i * 8 + 3] = c[i * 8 + 2] + d[i * 8 + 3];
+      a[i * 8 + 4] = c[i * 8 + 4] + d[i * 8 + 4]; a[i * 8 + 5] = c[i * 8 + 4] 
+ d[i * 8 + 5];
+      a[i * 8 + 6] = c[i * 8 + 6] + d[i * 8 + 6];
+      a[i * 8 + 7] = c[i * 8 + 6] + d[i * 8 + 7];
+    }
+}
+
+void __attribute__ ((noipa))
+f_golden (uint8_t *restrict a, uint8_t *restrict c, uint8_t *restrict d, int n)
+{
+#pragma GCC novector
+  for (int i = 0; i < n; ++i)
+    {
+      a[i * 8] = c[i * 8] + d[i * 8];
+      a[i * 8 + 1] = c[i * 8] + d[i * 8 + 1];
+      a[i * 8 + 2] = c[i * 8 + 2] + d[i * 8 + 2];
+      a[i * 8 + 3] = c[i * 8 + 2] + d[i * 8 + 3];
+      a[i * 8 + 4] = c[i * 8 + 4] + d[i * 8 + 4];
+      a[i * 8 + 5] = c[i * 8 + 4] + d[i * 8 + 5];
+      a[i * 8 + 6] = c[i * 8 + 6] + d[i * 8 + 6];
+      a[i * 8 + 7] = c[i * 8 + 6] + d[i * 8 + 7];
+    }
+}
+
+#define LIMIT 256
+#define NUM 32
+
+int
+main (void)
+{
+  uint8_t a[NUM * 8 + 8] = {0};
+  uint8_t a_golden[NUM * 8 + 8] = {0};
+  uint8_t c[NUM * 8 + 8] = {0};
+  uint8_t d[NUM * 8 + 8] = {0};
+
+  for (int i = 0; i < NUM * 8 + 8; i++)
+    {
+      if (i % NUM == 0)
+       c[i] = (i + NUM) % LIMIT;
+      else
+       c[i] = (i * 3) % LIMIT;
+      if (i % 2 == 0)
+       d[i] = i % LIMIT;
+      else
+       d[i] = (i * 7) % LIMIT;
+    }
+
+  f (a, c, d, NUM);
+  f_golden (a_golden, c, d, NUM);
+
+  if (a[241] != 103)
+    __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/lib/target-supports.exp 
b/gcc/testsuite/lib/target-supports.exp
index 27759094d852..4d2d1e939d25 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -2127,6 +2127,24 @@ proc check_effective_target_riscv_v { } {
     }]
 }
 
+# Return 1 if the target runtime supports 128-bit vectors, 0 otherwise.
+# Cache the result.
+
+proc check_effective_target_rvv_zvl128b_ok { } {
+    # Check if the target has a VLENB of 16.
+    set gcc_march [riscv_get_arch]
+    return [check_runtime ${gcc_march}_exec {
+       int main()
+       {
+         int vlenb = 0;
+         asm ("csrr %0,vlenb" : "=r" (vlenb) : : );
+         if (vlenb == 16)
+           return 0;
+         return 1;
+       }
+      } "-march=${gcc_march}"]
+}
+
 # Return 1 if the target runtime supports 256-bit vectors, 0 otherwise.
 # Cache the result.

Reply via email to