From: Pan Li <pan2...@intel.com> This patch would like to fix one bug when expanding const vector for the interleave case. For example, we have:
base1 = 151 step = 121 For vec_series, we will generate vector in format of v[i] = base + i * step. Then the vec_series will have below result for HImode, and we can find that the result overflow to the highest 8 bits of HImode. v1.b = {151, 255, 7, 0, 119, 0, 231, 0, 87, 1, 199, 1, 55, 2, 167, 2} Aka we expect v1.b should be: v1.b = {151, 0, 7, 0, 119, 0, 231, 0, 87, 0, 199, 0, 55, 0, 167, 0} After that it will perform the IOR with v2 for the base2(aka another series). v2.b = {0, 17, 0, 33, 0, 49, 0, 65, 0, 81, 0, 97, 0, 113, 0, 129} Unfortunately, the base1 + i * step1 in HImode may overflow to the high 8 bits, and the high 8 bits will pollute the v2 and result in incorrect value in const_vector. This patch would like to perform the overflow to smode check before IOR the base2 series, and perform the clean highest bit if the const_vector overflow to smode occurs. If no overflow, there will do nothing here. The below test suites are passed for this patch. * The rv64gcv fully regression test. PR target/118931 gcc/ChangeLog: * config/riscv/riscv-v.cc (expand_const_vector): Add overflow to smode check and clean up highest bits if overflow. * poly-int.h: Add operator =>> for poly. gcc/testsuite/ChangeLog: * gcc.target/riscv/rvv/base/pr118931-run-1.c: New test. Signed-off-by: Pan Li <pan2...@intel.com> --- gcc/config/riscv/riscv-v.cc | 33 ++++++++++++++++++- gcc/poly-int.h | 11 +++++++ .../riscv/rvv/base/pr118931-run-1.c | 19 +++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/pr118931-run-1.c diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc index 7cc15f3d53c..ef8d578995a 100644 --- a/gcc/config/riscv/riscv-v.cc +++ b/gcc/config/riscv/riscv-v.cc @@ -1504,9 +1504,40 @@ expand_const_vector (rtx target, rtx src) && get_vector_mode (new_smode, new_nunits).exists (&new_mode)) { rtx tmp1 = gen_reg_rtx (new_mode); - base1 = gen_int_mode (rtx_to_poly_int64 (base1), new_smode); + poly_int64 base1_poly = rtx_to_poly_int64 (base1); + base1 = gen_int_mode (base1_poly, new_smode); expand_vec_series (tmp1, base1, gen_int_mode (step1, new_smode)); + bool overflow_smode_p = false; + + for (int i = 0; i < XVECLEN (src, 0) / 2; i++) + { + poly_int64 elem = step1 * i + base1_poly; + + elem >>= builder.inner_bits_size (); + + if (maybe_ne (0, elem)) + { + overflow_smode_p = true; + break; + } + } + + if (overflow_smode_p) + { + /* The vec_series base1 may overflow bits to base2 series. */ + rtx vec_mask = gen_vec_duplicate (new_mode, + CONSTM1_RTX (new_smode)); + rtx lshift_vec_mask = gen_reg_rtx (new_mode); + rtx shift = gen_int_mode (builder.inner_bits_size (), Xmode); + rtx lshift_ops[] = {lshift_vec_mask, vec_mask, shift}; + emit_vlmax_insn (code_for_pred_scalar (LSHIFTRT, new_mode), + BINARY_OP, lshift_ops); + rtx and_ops[] = {tmp1, tmp1, lshift_vec_mask}; + emit_vlmax_insn (code_for_pred (AND, new_mode), BINARY_OP, + and_ops); + } + if (rtx_equal_p (base2, const0_rtx) && known_eq (step2, 0)) /* { 1, 0, 2, 0, ... }. */ emit_move_insn (result, gen_lowpart (mode, tmp1)); diff --git a/gcc/poly-int.h b/gcc/poly-int.h index 7c8901a971a..7b695343057 100644 --- a/gcc/poly-int.h +++ b/gcc/poly-int.h @@ -408,6 +408,8 @@ public: poly_int &operator <<= (unsigned int); + poly_int &operator >>= (unsigned int); + bool is_constant () const; template<typename T> @@ -550,6 +552,15 @@ poly_int<N, C>::operator <<= (unsigned int a) return *this; } +template<unsigned int N, typename C> +inline poly_int<N, C>& +poly_int<N, C>::operator >>= (unsigned int a) +{ + for (unsigned int i = 0; i < N; i++) + this->coeffs[i] >>= a; + return *this; +} + /* Return true if the polynomial value is a compile-time constant. */ template<unsigned int N, typename C> diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr118931-run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr118931-run-1.c new file mode 100644 index 00000000000..ef866a72039 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr118931-run-1.c @@ -0,0 +1,19 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-options "-O3 -march=rv64gcv -flto -mrvv-vector-bits=zvl" } */ + +long long m; +char f = 151; +char h = 103; +unsigned char a = 109; + +int main() { + for (char l = 0; l < 255 - 241; l += h - 102) + a *= f; + + m = a; + + if (m != 29) + __builtin_abort (); + + return 0; +} -- 2.43.0