When gimple-isel lowers a variable-index element access on a
fixed-length vector into .VEC_SET or .VEC_EXTRACT, the index may be
narrower than Pmode. The vec_set and vec_extract expanders used
gen_lowpart to convert it to Pmode, which only reinterprets the
register and drops the source-level truncation. The full 64-bit
value is then used as the slide amount of vslideup/vslidedown and
wrong code is generated.
Fix this by zero-extending a sub-Pmode index with convert_to_mode
instead.
PR target/126873
gcc/ChangeLog:
* config/riscv/autovec.md (vec_set<mode>): Zero-extend a
sub-Pmode index to Pmode.
(vec_extract<mode><vel>): Likewise.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/pr126873.c: New test.
Signed-off-by: Jin Ma <[email protected]>
---
gcc/config/riscv/autovec.md | 4 +--
gcc/testsuite/gcc.target/riscv/pr126873.c | 37 +++++++++++++++++++++++
2 files changed, 39 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/pr126873.c
diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md
index 964eed927c8..16d08cae30b 100644
--- a/gcc/config/riscv/autovec.md
+++ b/gcc/config/riscv/autovec.md
@@ -1396,7 +1396,7 @@ (define_expand "vec_set<mode>"
/* Here we set VL = offset + 1. */
rtx length = gen_reg_rtx (Pmode);
- operands[2] = gen_lowpart (Pmode, operands[2]);
+ operands[2] = convert_to_mode (Pmode, operands[2], true);
if (CONST_INT_P (operands[2]))
emit_move_insn (length, GEN_INT (INTVAL (operands[2]) + 1));
else
@@ -1452,7 +1452,7 @@ (define_expand "vec_extract<mode><vel>"
/* Emit the slide down to index 0 in a new vector. */
tmp = gen_reg_rtx (<MODE>mode);
- operands[2] = gen_lowpart (Pmode, operands[2]);
+ operands[2] = convert_to_mode (Pmode, operands[2], true);
rtx ops[] = {tmp, operands[1], operands[2]};
riscv_vector::emit_vlmax_insn
(code_for_pred_slide (UNSPEC_VSLIDEDOWN, <MODE>mode),
diff --git a/gcc/testsuite/gcc.target/riscv/pr126873.c
b/gcc/testsuite/gcc.target/riscv/pr126873.c
new file mode 100644
index 00000000000..eab525d0cf2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr126873.c
@@ -0,0 +1,37 @@
+/* { dg-do run { target rv64 } } */
+/* { dg-require-effective-target riscv_v } */
+/* { dg-require-effective-target rvv_zvl128b_ok } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -O1" } */
+
+typedef unsigned short u16 __attribute__ ((vector_size (4)));
+
+unsigned long long g;
+
+void __attribute__ ((noinline))
+f1 (unsigned long long a3)
+{
+ unsigned long long v15
+ = __builtin_bswap64 ((long long) 10398105857157080808ull
+ / (long long) a3);
+ u16 bc13 = (u16) { 29637 };
+ if (0 >= bc13[(unsigned int) v15])
+ __builtin_abort ();
+}
+
+u16 __attribute__ ((noinline))
+f2 (u16 in)
+{
+ in[(unsigned int) g] = 123;
+ return in;
+}
+
+int
+main (void)
+{
+ f1 (17752357569705450221ull);
+ g = 0x0b00000000000000ull;
+ u16 r = f2 ((u16) { 1, 2 });
+ if (r[0] != 123 || r[1] != 2)
+ __builtin_abort ();
+ return 0;
+}
--
2.52.0