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; +} +