Hi All, The current vector extract pattern can only extract from a vector when the position to extract is a multiple of the vector bitsize as a whole. That means extract something like a V2SI from a V4SI vector from position 32 isn't possible as 32 is not a multiple of 64. Ideally this optab should have worked on multiple of the element size, but too many targets rely on this semantic now. So instead add a new case which allows any extraction as long as the bit pos is a multiple of the element size. We use a VEC_PERM to shuffle the elements into the bottom parts of the vector and then use a subreg to extract the values out. This now allows various vector operations that before were being decomposed into very inefficient scalar operations. NOTE: I added 3 testcases, I only fixed the 3rd one. The 1st one missed because we don't optimize VEC_PERM expressions into bitfields. The 2nd one is missed because extract_bit_field only works on vector modes. In this case the intermediate extract is DImode. On targets where the scalar mode is tiable to vector modes the extract should work fine. However I ran out of time to fix the first two and so will do so in GCC 14. For now this catches the case that my pattern now introduces more easily. Bootstrapped Regtested on aarch64-none-linux-gnu, x86_64-pc-linux-gnu and no issues. Ok for master? Thanks, Tamar gcc/ChangeLog: * expmed.cc (extract_bit_field_1): Add support for vector element extracts. gcc/testsuite/ChangeLog: * gcc.target/aarch64/ext_1.c: New. --- inline copy of patch -- diff --git a/gcc/expmed.cc b/gcc/expmed.cc index bab020c07222afa38305ef8d7333f271b1965b78..ffdf65210d17580a216477cfe4ac1598941ac9e4 100644 --- a/gcc/expmed.cc +++ b/gcc/expmed.cc @@ -1718,6 +1718,45 @@ extract_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum, return target; } } + else if (!known_eq (bitnum, 0U) + && multiple_p (GET_MODE_UNIT_BITSIZE (tmode), bitnum, &pos)) + { + /* The encoding has a single stepped pattern. */ + poly_uint64 nunits = GET_MODE_NUNITS (new_mode); + int nelts = nunits.to_constant (); + vec_perm_builder sel (nunits, nelts, 1); + int delta = -pos.to_constant (); + for (int i = 0; i < nelts; ++i) + sel.quick_push ((i - delta) % nelts); + vec_perm_indices indices (sel, 1, nunits); + + if (can_vec_perm_const_p (new_mode, new_mode, indices, false)) + { + class expand_operand ops[4]; + machine_mode outermode = new_mode; + machine_mode innermode = tmode; + enum insn_code icode + = direct_optab_handler (vec_perm_optab, outermode); + target = gen_reg_rtx (outermode); + if (icode != CODE_FOR_nothing) + { + rtx sel = vec_perm_indices_to_rtx (outermode, indices); + create_output_operand (&ops[0], target, outermode); + ops[0].target = 1; + create_input_operand (&ops[1], op0, outermode); + create_input_operand (&ops[2], op0, outermode); + create_input_operand (&ops[3], sel, outermode); + if (maybe_expand_insn (icode, 4, ops)) + return simplify_gen_subreg (innermode, target, outermode, 0); + } + else if (targetm.vectorize.vec_perm_const != NULL) + { + if (targetm.vectorize.vec_perm_const (outermode, outermode, + target, op0, op0, indices)) + return simplify_gen_subreg (innermode, target, outermode, 0); + } + } + } } /* See if we can get a better vector mode before extracting. */ diff --git a/gcc/testsuite/gcc.target/aarch64/ext_1.c b/gcc/testsuite/gcc.target/aarch64/ext_1.c new file mode 100644 index 0000000000000000000000000000000000000000..18a10a14f1161584267a8472e571b3bc2ddf887a --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/ext_1.c @@ -0,0 +1,54 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O" } */ +/* { dg-final { check-function-bodies "**" "" "" } } */ + +#include + +typedef unsigned int v4si __attribute__((vector_size (16))); +typedef unsigned int v2si __attribute__((vector_size (8))); + +/* +** extract: { xfail *-*-* } +** ext v0.16b, v0.16b, v0.16b, #4 +** ret +*/ +v2si extract (v4si x) +{ + v2si res = {x[1], x[2]}; + return res; +} + +/* +** extract1: { xfail *-*-* } +** ext v0.16b, v0.16b, v0.16b, #4 +** ret +*/ +v2si extract1 (v4si x) +{ + v2si res; + memcpy (&res, ((int*)&x)+1, sizeof(res)); + return res; +} + +typedef struct cast { + int a; + v2si b __attribute__((packed)); +} cast_t; + +typedef union Data { + v4si x; + cast_t y; +} data; + +/* +** extract2: +** ext v0.16b, v0.16b, v0.16b, #4 +** ret +*/ +v2si extract2 (v4si x) +{ + data d; + d.x = x; + return d.y.b; +} + --