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.
This patch does that. Is the approach reasonable?
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