On Thu, Jun 18, 2026 at 9:19 AM Robin Dapp <[email protected]> wrote:
>
> Hi,
>
> This is another small improvement for PR125390. Originally a riscv-specific
> issue and ICE, I noticed poor codegen when we extract values from a tuple
> type. In the optimized dump we have:
>
> vect_array.9 = .MASK_LEN_LOAD_LANES (&c, 32B, { -1, -1, -1, -1 }, _44(D),
> 4, 0);
> _48 = BIT_FIELD_REF <vect_array.9[0], 32, 96>;
> _50 = BIT_FIELD_REF <vect_array.9[1], 32, 96>;
> f_13 = _48 ^ _50;
> a = f_13;
>
> and _48 as well as _50 spill to memory instead of extracting directly.
>
> We end up with
>
> (subreg:RVVMF2SI (reg:RVVMF2x2SI 138 [ vect_array.9 ]) 0)
>
> which, as we pun the with a large integer mode, involves OImode
> that we cannot "move". We might be able to work around that in the
> target in unintuitive ways :) and we could also offer vec_extract for
> all tuple modes but I figured it could be much easier if expand already
> handled the tuple -> vector part for us so just a vector extract is left
> for the target to do.
But the above looks exactly "right"?
>
> This patch does that. Is the approach reasonable?
What does it generate? I'd exect that same subreg for the tuple -> vector
part?
> Bootstrapped and regtested on x86, power10, and aarch64.
> Regtested on riscv64.
>
> Regards
> Robin
>
> PR middle-end/125390
>
> gcc/ChangeLog:
>
> * expr.cc (expand_expr_real_1): Prepare tuple extraction.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.target/riscv/rvv/autovec/pr125390.c: New test.
> ---
> gcc/expr.cc | 32 +++++++++++++++++++
> .../gcc.target/riscv/rvv/autovec/pr125390.c | 16 ++++++++++
> 2 files changed, 48 insertions(+)
> create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/pr125390.c
>
> diff --git a/gcc/expr.cc b/gcc/expr.cc
> index de73215ccc6..e4f0eeb2b5b 100644
> --- a/gcc/expr.cc
> +++ b/gcc/expr.cc
> @@ -12329,6 +12329,38 @@ expand_expr_real_1 (tree exp, rtx target,
> machine_mode tmode,
> must_force_mem = true;
> }
>
> + /* Check if we're dealing with a vector-tuple type extraction.
> + If so, and the bitfield size does not overlap multiple
> + vectors, force the respective single vector into a register
> + and use that for actual extraction further down. */
> + tree from = TREE_OPERAND (exp, 0);
> + if (!must_force_mem
> + && REG_P (op0)
> + && VECTOR_MODE_P (GET_MODE (op0))
> + && TREE_CODE (from) == ARRAY_REF
> + && VECTOR_TYPE_P (TREE_TYPE (from)))
> + {
> + machine_mode vmode = TYPE_MODE (TREE_TYPE (from));
> + poly_uint16 vmodesz = GET_MODE_BITSIZE (vmode);
> +
> + HOST_WIDE_INT vec_idx;
> + poly_uint64 off;
> +
> + if (can_div_trunc_p (bitpos, vmodesz, &vec_idx, &off)
> + && known_le (off + bitsize, vmodesz))
> + {
> + rtx sub = simplify_gen_subreg (vmode, op0, GET_MODE (op0),
> + vec_idx * GET_MODE_SIZE
> (vmode));
> + if (sub)
> + {
> + op0 = force_reg (vmode, sub);
> + orig_op0 = op0;
> + mode2 = vmode;
> + bitpos = off;
> + }
> + }
> + }
> +
> /* If this is a constant, put it in a register if it is a legitimate
> constant and we don't need a memory reference. */
> if (CONSTANT_P (op0)
> diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr125390.c
> b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr125390.c
> new file mode 100644
> index 00000000000..363fc0c8d40
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr125390.c
> @@ -0,0 +1,16 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gcv_zvl256b -mabi=lp64d -mrvv-vector-bits=zvl
> -O2 -fdump-rtl-expand" } */
> +
> +int a, b[64], c[64];
> +
> +void
> +foo (void)
> +{
> + for (unsigned e = 0; e < 8; e += 2)
> + {
> + a = c[e] ^ c[e + 1];
> + b[e] = 0;
> + }
> +}
> +
> +/* { dg-final { scan-rtl-dump-not "virtual-stack-vars" "expand" } } */
> --
> 2.54.0