lgtm
> From: "Robin Dapp"<[email protected]>
> Date: Thu, Dec 18, 2025, 20:17
> Subject: [PATCH] RISC-V: Fix overflow check in interleave pattern [PR122970].
> To: "gcc-patches"<[email protected]>
> Cc: <[email protected]>, <[email protected]>, <[email protected]>,
> <[email protected]>, <[email protected]>
> Hi,
>
>
> 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.
>
>
> Regtested on rv64gcv_zvl512b.
>
>
> Regards
> Robin
>
>
> PR target/122970
>
>
> gcc/ChangeLog:
>
>
> * config/riscv/riscv-v.cc<http://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.
> ---
> gcc/config/riscv/riscv-v.cc<http://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(-)
> create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122970.c
>
>
> diff --git a/gcc/config/riscv/riscv-v.cc<http://riscv-v.cc>
> b/gcc/config/riscv/riscv-v.cc<http://riscv-v.cc>
index 321b5172783..d64acff8e0f 100644
> --- a/gcc/config/riscv/riscv-v.cc<http://riscv-v.cc>
+++ b/gcc/config/riscv/riscv-v.cc<http://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 00000000000..be2ac4a62ae
> --- /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 7f7e6ee2c60..ccd78f9f56f 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.
>
--
> 2.51.1