From: Richard Sandiford Date: Sat, 13 Jan 2018 17:50:13 +0000 (+0000) Subject: Extra subreg fold for variable-length CONST_VECTORs X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=646e47bcd15483fcafcc695efefd7a0ddeb4c716;p=gcc.git Extra subreg fold for variable-length CONST_VECTORs The SVE support for the new CONST_VECTOR encoding needs to be able to extract the first N bits of the vector and duplicate it. This patch adds a simplify_subreg rule for that. The code is covered by the gcc.target/aarch64/sve_slp_*.c tests. 2018-01-13 Richard Sandiford gcc/ * simplify-rtx.c (simplify_immed_subreg): Add an inner_bytes parameter and use it instead of GET_MODE_SIZE (innermode). Use inner_bytes * BITS_PER_UNIT instead of GET_MODE_BITSIZE (innermode). Use CEIL (inner_bytes, GET_MODE_UNIT_SIZE (innermode)) instead of GET_MODE_NUNITS (innermode). Also add a first_elem parameter. Change innermode from fixed_mode_size to machine_mode. (simplify_subreg): Update call accordingly. Handle a constant-sized subreg of a variable-length CONST_VECTOR. From-SVN: r256610 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 561fd708dae..3f1919e774f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2018-01-13 Richard Sandiford + + * simplify-rtx.c (simplify_immed_subreg): Add an inner_bytes + parameter and use it instead of GET_MODE_SIZE (innermode). Use + inner_bytes * BITS_PER_UNIT instead of GET_MODE_BITSIZE (innermode). + Use CEIL (inner_bytes, GET_MODE_UNIT_SIZE (innermode)) instead of + GET_MODE_NUNITS (innermode). Also add a first_elem parameter. + Change innermode from fixed_mode_size to machine_mode. + (simplify_subreg): Update call accordingly. Handle a constant-sized + subreg of a variable-length CONST_VECTOR. + 2018-01-13 Richard Sandiford Alan Hayward David Sherwood diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index b052fbbe949..b0a01783101 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -5924,13 +5924,16 @@ simplify_ternary_operation (enum rtx_code code, machine_mode mode, or CONST_FIXED or CONST_VECTOR, returning another CONST_INT or CONST_WIDE_INT or CONST_DOUBLE or CONST_FIXED or CONST_VECTOR. - Works by unpacking OP into a collection of 8-bit values + Works by unpacking INNER_BYTES bytes of OP into a collection of 8-bit values represented as a little-endian array of 'unsigned char', selecting by BYTE, - and then repacking them again for OUTERMODE. */ + and then repacking them again for OUTERMODE. If OP is a CONST_VECTOR, + FIRST_ELEM is the number of the first element to extract, otherwise + FIRST_ELEM is ignored. */ static rtx simplify_immed_subreg (fixed_size_mode outermode, rtx op, - fixed_size_mode innermode, unsigned int byte) + machine_mode innermode, unsigned int byte, + unsigned int first_elem, unsigned int inner_bytes) { enum { value_bit = 8, @@ -5960,13 +5963,13 @@ simplify_immed_subreg (fixed_size_mode outermode, rtx op, /* We support any size mode. */ max_bitsize = MAX (GET_MODE_BITSIZE (outermode), - GET_MODE_BITSIZE (innermode)); + inner_bytes * BITS_PER_UNIT); /* Unpack the value. */ if (GET_CODE (op) == CONST_VECTOR) { - num_elem = GET_MODE_NUNITS (innermode); + num_elem = CEIL (inner_bytes, GET_MODE_UNIT_SIZE (innermode)); elem_bitsize = GET_MODE_UNIT_BITSIZE (innermode); } else @@ -5983,7 +5986,7 @@ simplify_immed_subreg (fixed_size_mode outermode, rtx op, { unsigned char * vp; rtx el = (GET_CODE (op) == CONST_VECTOR - ? CONST_VECTOR_ELT (op, elem) + ? CONST_VECTOR_ELT (op, first_elem + elem) : op); /* Vectors are kept in target memory order. (This is probably @@ -6110,10 +6113,9 @@ simplify_immed_subreg (fixed_size_mode outermode, rtx op, /* Renumber BYTE so that the least-significant byte is byte 0. A special case is paradoxical SUBREGs, which shouldn't be adjusted since they will already have offset 0. */ - if (GET_MODE_SIZE (innermode) >= GET_MODE_SIZE (outermode)) + if (inner_bytes >= GET_MODE_SIZE (outermode)) { - unsigned ibyte = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode) - - byte); + unsigned ibyte = inner_bytes - GET_MODE_SIZE (outermode) - byte; unsigned word_byte = WORDS_BIG_ENDIAN ? ibyte : byte; unsigned subword_byte = BYTES_BIG_ENDIAN ? ibyte : byte; byte = (subword_byte % UNITS_PER_WORD @@ -6122,7 +6124,7 @@ simplify_immed_subreg (fixed_size_mode outermode, rtx op, /* BYTE should still be inside OP. (Note that BYTE is unsigned, so if it's become negative it will instead be very large.) */ - gcc_assert (byte < GET_MODE_SIZE (innermode)); + gcc_assert (byte < inner_bytes); /* Convert from bytes to chunks of size value_bit. */ value_start = byte * (BITS_PER_UNIT / value_bit); @@ -6311,7 +6313,18 @@ simplify_subreg (machine_mode outermode, rtx op, if (is_a (outermode, &fs_outermode) && is_a (innermode, &fs_innermode) && byte.is_constant (&cbyte)) - return simplify_immed_subreg (fs_outermode, op, fs_innermode, cbyte); + return simplify_immed_subreg (fs_outermode, op, fs_innermode, cbyte, + 0, GET_MODE_SIZE (fs_innermode)); + + /* Handle constant-sized outer modes and variable-sized inner modes. */ + unsigned HOST_WIDE_INT first_elem; + if (GET_CODE (op) == CONST_VECTOR + && is_a (outermode, &fs_outermode) + && constant_multiple_p (byte, GET_MODE_UNIT_SIZE (innermode), + &first_elem)) + return simplify_immed_subreg (fs_outermode, op, innermode, 0, + first_elem, + GET_MODE_SIZE (fs_outermode)); return NULL_RTX; }