From: Richard Sandiford Date: Wed, 3 Jan 2018 21:46:38 +0000 (+0000) Subject: Use extract_bit_field_as_subreg for vectors X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b194a722446f51ffa11ea49affe6893a6361cfac;p=gcc.git Use extract_bit_field_as_subreg for vectors extract_bit_field_1 tries to use vec_extract to extract part of a vector. However, if that pattern isn't defined or if the operands aren't suitable, another good approach is to try a direct subreg reference. This is particularly useful for multi-vector modes on SVE (e.g. when extracting one vector from an LD2 result). The function would go on to try the same thing anyway, but only if there is an integer mode with the same size as the vector mode, which isn't true for SVE modes (and doesn't seem a good thing to require in general). Even when there is an integer mode, doing the operation on the original modes avoids some unnecessary bitcasting. 2018-01-03 Richard Sandiford Alan Hayward David Sherwood gcc/ * expmed.c (extract_bit_field_1): For vector extracts, fall back to extract_bit_field_as_subreg if vec_extract isn't available. Co-Authored-By: Alan Hayward Co-Authored-By: David Sherwood From-SVN: r256209 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a151f622738..5dbf3ba5524 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2018-01-03 Richard Sandiford + Alan Hayward + David Sherwood + + * expmed.c (extract_bit_field_1): For vector extracts, + fall back to extract_bit_field_as_subreg if vec_extract + isn't available. + 2018-01-03 Richard Sandiford Alan Hayward David Sherwood diff --git a/gcc/expmed.c b/gcc/expmed.c index 4433460033b..d88ea3508e4 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -1709,33 +1709,49 @@ extract_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum, } /* Use vec_extract patterns for extracting parts of vectors whenever - available. */ + available. If that fails, see whether the current modes and bitregion + give a natural subreg. */ machine_mode outermode = GET_MODE (op0); - scalar_mode innermode = GET_MODE_INNER (outermode); - poly_uint64 pos; - if (VECTOR_MODE_P (outermode) - && !MEM_P (op0) - && (convert_optab_handler (vec_extract_optab, outermode, innermode) - != CODE_FOR_nothing) - && known_eq (bitsize, GET_MODE_BITSIZE (innermode)) - && multiple_p (bitnum, GET_MODE_BITSIZE (innermode), &pos)) + if (VECTOR_MODE_P (outermode) && !MEM_P (op0)) { - struct expand_operand ops[3]; + scalar_mode innermode = GET_MODE_INNER (outermode); enum insn_code icode = convert_optab_handler (vec_extract_optab, outermode, innermode); + poly_uint64 pos; + if (icode != CODE_FOR_nothing + && known_eq (bitsize, GET_MODE_BITSIZE (innermode)) + && multiple_p (bitnum, GET_MODE_BITSIZE (innermode), &pos)) + { + struct expand_operand ops[3]; - create_output_operand (&ops[0], target, innermode); - ops[0].target = 1; - create_input_operand (&ops[1], op0, outermode); - create_integer_operand (&ops[2], pos); - if (maybe_expand_insn (icode, 3, ops)) + create_output_operand (&ops[0], target, innermode); + ops[0].target = 1; + create_input_operand (&ops[1], op0, outermode); + create_integer_operand (&ops[2], pos); + if (maybe_expand_insn (icode, 3, ops)) + { + if (alt_rtl && ops[0].target) + *alt_rtl = target; + target = ops[0].value; + if (GET_MODE (target) != mode) + return gen_lowpart (tmode, target); + return target; + } + } + /* Using subregs is useful if we're extracting the least-significant + vector element, or if we're extracting one register vector from + a multi-register vector. extract_bit_field_as_subreg checks + for valid bitsize and bitnum, so we don't need to do that here. + + The mode check makes sure that we're extracting either + a single element or a subvector with the same element type. + If the modes aren't such a natural fit, fall through and + bitcast to integers first. */ + if (GET_MODE_INNER (mode) == innermode) { - if (alt_rtl && ops[0].target) - *alt_rtl = target; - target = ops[0].value; - if (GET_MODE (target) != mode) - return gen_lowpart (tmode, target); - return target; + rtx sub = extract_bit_field_as_subreg (mode, op0, bitsize, bitnum); + if (sub) + return sub; } }