After a certain point, extract_bit_field and store_bit_field ensure that they're dealing with integer modes or BLKmode MEMs. This patch uses scalar_int_mode and opt_scalar_int_mode for those parts.
2017-07-13 Richard Sandiford <richard.sandif...@linaro.org> Alan Hayward <alan.hayw...@arm.com> David Sherwood <david.sherw...@arm.com> gcc/ * expmed.c (store_bit_field_using_insv): Add op0_mode and value_mode arguments. Use scalar_int_mode internally. (store_bit_field_1): Rename the new integer mode from imode to op0_mode and use it instead of GET_MODE (op0). Update calls to store_split_bit_field, store_bit_field_using_insv and store_fixed_bit_field. (store_fixed_bit_field): Add op0_mode and value_mode arguments. Use scalar_int_mode internally. Use a bit count rather than a mode when calculating the largest bit size for get_best_mode. Update calls to store_split_bit_field and store_fixed_bit_field_1. (store_fixed_bit_field_1): Add mode and value_mode arguments. Remove assertion that OP0 has a scalar integer mode. (store_split_bit_field): Add op0_mode and value_mode arguments. Update calls to extract_fixed_bit_field. (extract_bit_field_using_extv): Add an op0_mode argument. Use scalar_int_mode internally. (extract_bit_field_1): Rename the new integer mode from imode to op0_mode and use it instead of GET_MODE (op0). Update calls to extract_split_bit_field, extract_bit_field_using_extv and extract_fixed_bit_field. (extract_fixed_bit_field): Add an op0_mode argument. Update calls to extract_split_bit_field and extract_fixed_bit_field_1. (extract_fixed_bit_field_1): Add a mode argument. Remove assertion that OP0 has a scalar integer mode. Use as_a <scalar_int_mode> on the target mode. (extract_split_bit_field): Add an op0_mode argument. Update call to extract_fixed_bit_field. Index: gcc/expmed.c =================================================================== --- gcc/expmed.c 2017-07-13 09:18:46.700153153 +0100 +++ gcc/expmed.c 2017-07-13 09:18:47.197114027 +0100 @@ -45,27 +45,31 @@ struct target_expmed default_target_expm struct target_expmed *this_target_expmed = &default_target_expmed; #endif -static void store_fixed_bit_field (rtx, unsigned HOST_WIDE_INT, +static void store_fixed_bit_field (rtx, opt_scalar_int_mode, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, - rtx, bool); -static void store_fixed_bit_field_1 (rtx, unsigned HOST_WIDE_INT, + unsigned HOST_WIDE_INT, + rtx, scalar_int_mode, bool); +static void store_fixed_bit_field_1 (rtx, scalar_int_mode, + unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, - rtx, bool); -static void store_split_bit_field (rtx, unsigned HOST_WIDE_INT, + rtx, scalar_int_mode, bool); +static void store_split_bit_field (rtx, opt_scalar_int_mode, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, - rtx, bool); -static rtx extract_fixed_bit_field (machine_mode, rtx, + unsigned HOST_WIDE_INT, + rtx, scalar_int_mode, bool); +static rtx extract_fixed_bit_field (machine_mode, rtx, opt_scalar_int_mode, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, rtx, int, bool); -static rtx extract_fixed_bit_field_1 (machine_mode, rtx, +static rtx extract_fixed_bit_field_1 (machine_mode, rtx, scalar_int_mode, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, rtx, int, bool); static rtx lshift_value (machine_mode, unsigned HOST_WIDE_INT, int); -static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT, +static rtx extract_split_bit_field (rtx, opt_scalar_int_mode, + unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, int, bool); static void do_cmp_and_jump (rtx, rtx, enum rtx_code, machine_mode, rtx_code_label *); static rtx expand_smod_pow2 (machine_mode, rtx, HOST_WIDE_INT); @@ -568,13 +572,16 @@ simple_mem_bitfield_p (rtx op0, unsigned } /* Try to use instruction INSV to store VALUE into a field of OP0. - BITSIZE and BITNUM are as for store_bit_field. */ + If OP0_MODE is defined, it is the mode of OP0, otherwise OP0 is a + BLKmode MEM. VALUE_MODE is the mode of VALUE. BITSIZE and BITNUM + are as for store_bit_field. */ static bool store_bit_field_using_insv (const extraction_insn *insv, rtx op0, + opt_scalar_int_mode op0_mode, unsigned HOST_WIDE_INT bitsize, unsigned HOST_WIDE_INT bitnum, - rtx value) + rtx value, scalar_int_mode value_mode) { struct expand_operand ops[4]; rtx value1; @@ -582,7 +589,7 @@ store_bit_field_using_insv (const extrac rtx_insn *last = get_last_insn (); bool copy_back = false; - machine_mode op_mode = insv->field_mode; + scalar_int_mode op_mode = insv->field_mode; unsigned int unit = GET_MODE_BITSIZE (op_mode); if (bitsize == 0 || bitsize > unit) return false; @@ -595,7 +602,7 @@ store_bit_field_using_insv (const extrac { /* Convert from counting within OP0 to counting in OP_MODE. */ if (BYTES_BIG_ENDIAN) - bitnum += unit - GET_MODE_BITSIZE (GET_MODE (op0)); + bitnum += unit - GET_MODE_BITSIZE (*op0_mode); /* If xop0 is a register, we need it in OP_MODE to make it acceptable to the format of insv. */ @@ -648,30 +655,28 @@ store_bit_field_using_insv (const extrac /* Convert VALUE to op_mode (which insv insn wants) in VALUE1. */ value1 = value; - if (GET_MODE (value) != op_mode) + if (value_mode != op_mode) { - if (GET_MODE_BITSIZE (GET_MODE (value)) >= bitsize) + if (GET_MODE_BITSIZE (value_mode) >= bitsize) { rtx tmp; /* Optimization: Don't bother really extending VALUE if it has all the bits we will actually use. However, if we must narrow it, be sure we do it correctly. */ - if (GET_MODE_SIZE (GET_MODE (value)) < GET_MODE_SIZE (op_mode)) + if (GET_MODE_SIZE (value_mode) < GET_MODE_SIZE (op_mode)) { - tmp = simplify_subreg (op_mode, value1, GET_MODE (value), 0); + tmp = simplify_subreg (op_mode, value1, value_mode, 0); if (! tmp) tmp = simplify_gen_subreg (op_mode, - force_reg (GET_MODE (value), - value1), - GET_MODE (value), 0); + force_reg (value_mode, value1), + value_mode, 0); } else { tmp = gen_lowpart_if_possible (op_mode, value1); if (! tmp) - tmp = gen_lowpart (op_mode, force_reg (GET_MODE (value), - value1)); + tmp = gen_lowpart (op_mode, force_reg (value_mode, value1)); } value1 = tmp; } @@ -826,14 +831,14 @@ store_bit_field_1 (rtx str_rtx, unsigned if we aren't. This must come after the entire register case above, since that case is valid for any mode. The following cases are only valid for integral modes. */ - opt_scalar_int_mode imode = int_mode_for_mode (GET_MODE (op0)); - if (!imode.exists () || *imode != GET_MODE (op0)) + opt_scalar_int_mode op0_mode = int_mode_for_mode (GET_MODE (op0)); + if (!op0_mode.exists () || *op0_mode != GET_MODE (op0)) { if (MEM_P (op0)) - op0 = adjust_bitfield_address_size (op0, imode.else_blk (), + op0 = adjust_bitfield_address_size (op0, op0_mode.else_blk (), 0, MEM_SIZE (op0)); else - op0 = gen_lowpart (*imode, op0); + op0 = gen_lowpart (*op0_mode, op0); } /* Storing an lsb-aligned field in a register @@ -945,11 +950,15 @@ store_bit_field_1 (rtx str_rtx, unsigned with 64 bit registers that uses SFmode for float. It can also occur for unaligned float or complex fields. */ orig_value = value; - if (GET_MODE (value) != VOIDmode - && GET_MODE_CLASS (GET_MODE (value)) != MODE_INT - && GET_MODE_CLASS (GET_MODE (value)) != MODE_PARTIAL_INT) + scalar_int_mode value_mode; + if (GET_MODE (value) == VOIDmode) + /* By this point we've dealt with values that are bigger than a word, + so word_mode is a conservatively correct choice. */ + value_mode = word_mode; + else if (!is_a <scalar_int_mode> (GET_MODE (value), &value_mode)) { - value = gen_reg_rtx (*int_mode_for_mode (GET_MODE (value))); + value_mode = *int_mode_for_mode (GET_MODE (value)); + value = gen_reg_rtx (value_mode); emit_move_insn (gen_lowpart (GET_MODE (orig_value), value), orig_value); } @@ -958,23 +967,25 @@ store_bit_field_1 (rtx str_rtx, unsigned Don't do this if op0 is a single hard register wider than word such as a float or vector register. */ if (!MEM_P (op0) - && GET_MODE_SIZE (GET_MODE (op0)) > UNITS_PER_WORD + && GET_MODE_SIZE (*op0_mode) > UNITS_PER_WORD && (!REG_P (op0) || !HARD_REGISTER_P (op0) - || HARD_REGNO_NREGS (REGNO (op0), GET_MODE (op0)) != 1)) + || HARD_REGNO_NREGS (REGNO (op0), *op0_mode) != 1)) { if (bitnum % BITS_PER_WORD + bitsize > BITS_PER_WORD) { if (!fallback_p) return false; - store_split_bit_field (op0, bitsize, bitnum, bitregion_start, - bitregion_end, value, reverse); + store_split_bit_field (op0, op0_mode, bitsize, bitnum, + bitregion_start, bitregion_end, + value, value_mode, reverse); return true; } - op0 = simplify_gen_subreg (word_mode, op0, GET_MODE (op0), + op0 = simplify_gen_subreg (word_mode, op0, *op0_mode, bitnum / BITS_PER_WORD * UNITS_PER_WORD); gcc_assert (op0); + op0_mode = word_mode; bitnum %= BITS_PER_WORD; } @@ -986,9 +997,10 @@ store_bit_field_1 (rtx str_rtx, unsigned if (!MEM_P (op0) && !reverse && get_best_reg_extraction_insn (&insv, EP_insv, - GET_MODE_BITSIZE (GET_MODE (op0)), + GET_MODE_BITSIZE (*op0_mode), fieldmode) - && store_bit_field_using_insv (&insv, op0, bitsize, bitnum, value)) + && store_bit_field_using_insv (&insv, op0, op0_mode, + bitsize, bitnum, value, value_mode)) return true; /* If OP0 is a memory, try copying it to a register and seeing if a @@ -997,7 +1009,8 @@ store_bit_field_1 (rtx str_rtx, unsigned { if (get_best_mem_extraction_insn (&insv, EP_insv, bitsize, bitnum, fieldmode) - && store_bit_field_using_insv (&insv, op0, bitsize, bitnum, value)) + && store_bit_field_using_insv (&insv, op0, op0_mode, + bitsize, bitnum, value, value_mode)) return true; rtx_insn *last = get_last_insn (); @@ -1025,8 +1038,8 @@ store_bit_field_1 (rtx str_rtx, unsigned if (!fallback_p) return false; - store_fixed_bit_field (op0, bitsize, bitnum, bitregion_start, - bitregion_end, value, reverse); + store_fixed_bit_field (op0, op0_mode, bitsize, bitnum, bitregion_start, + bitregion_end, value, value_mode, reverse); return true; } @@ -1120,16 +1133,19 @@ store_bit_field (rtx str_rtx, unsigned H } /* Use shifts and boolean operations to store VALUE into a bit field of - width BITSIZE in OP0, starting at bit BITNUM. + width BITSIZE in OP0, starting at bit BITNUM. If OP0_MODE is defined, + it is the mode of OP0, otherwise OP0 is a BLKmode MEM. VALUE_MODE is + the mode of VALUE. If REVERSE is true, the store is to be done in reverse order. */ static void -store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize, +store_fixed_bit_field (rtx op0, opt_scalar_int_mode op0_mode, + unsigned HOST_WIDE_INT bitsize, unsigned HOST_WIDE_INT bitnum, unsigned HOST_WIDE_INT bitregion_start, unsigned HOST_WIDE_INT bitregion_end, - rtx value, bool reverse) + rtx value, scalar_int_mode value_mode, bool reverse) { /* There is a case not handled here: a structure with a known alignment of just a halfword @@ -1138,46 +1154,48 @@ store_fixed_bit_field (rtx op0, unsigned and a field split across two bytes. Such cases are not supposed to be able to occur. */ + scalar_int_mode best_mode; if (MEM_P (op0)) { - machine_mode mode = GET_MODE (op0); - if (GET_MODE_BITSIZE (mode) == 0 - || GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (word_mode)) - mode = word_mode; - scalar_int_mode best_mode; + unsigned int max_bitsize = BITS_PER_WORD; + if (op0_mode.exists () && GET_MODE_BITSIZE (*op0_mode) < max_bitsize) + max_bitsize = GET_MODE_BITSIZE (*op0_mode); + if (!get_best_mode (bitsize, bitnum, bitregion_start, bitregion_end, - MEM_ALIGN (op0), GET_MODE_BITSIZE (mode), - MEM_VOLATILE_P (op0), &best_mode)) + MEM_ALIGN (op0), max_bitsize, MEM_VOLATILE_P (op0), + &best_mode)) { /* The only way this should occur is if the field spans word boundaries. */ - store_split_bit_field (op0, bitsize, bitnum, bitregion_start, - bitregion_end, value, reverse); + store_split_bit_field (op0, op0_mode, bitsize, bitnum, + bitregion_start, bitregion_end, + value, value_mode, reverse); return; } op0 = narrow_bit_field_mem (op0, best_mode, bitsize, bitnum, &bitnum); } + else + best_mode = *op0_mode; - store_fixed_bit_field_1 (op0, bitsize, bitnum, value, reverse); + store_fixed_bit_field_1 (op0, best_mode, bitsize, bitnum, + value, value_mode, reverse); } /* Helper function for store_fixed_bit_field, stores - the bit field always using the MODE of OP0. */ + the bit field always using MODE, which is the mode of OP0. The other + arguments are as for store_fixed_bit_field. */ static void -store_fixed_bit_field_1 (rtx op0, unsigned HOST_WIDE_INT bitsize, +store_fixed_bit_field_1 (rtx op0, scalar_int_mode mode, + unsigned HOST_WIDE_INT bitsize, unsigned HOST_WIDE_INT bitnum, - rtx value, bool reverse) + rtx value, scalar_int_mode value_mode, bool reverse) { - machine_mode mode; rtx temp; int all_zero = 0; int all_one = 0; - mode = GET_MODE (op0); - gcc_assert (SCALAR_INT_MODE_P (mode)); - /* Note that bitsize + bitnum can be greater than GET_MODE_BITSIZE (mode) for invalid input, such as f5 from gcc.dg/pr48335-2.c. */ @@ -1212,10 +1230,10 @@ store_fixed_bit_field_1 (rtx op0, unsign } else { - int must_and = (GET_MODE_BITSIZE (GET_MODE (value)) != bitsize + int must_and = (GET_MODE_BITSIZE (value_mode) != bitsize && bitnum + bitsize != GET_MODE_BITSIZE (mode)); - if (GET_MODE (value) != mode) + if (value_mode != mode) value = convert_to_mode (mode, value, 1); if (must_and) @@ -1268,18 +1286,21 @@ store_fixed_bit_field_1 (rtx op0, unsign OP0 is the REG, SUBREG or MEM rtx for the first of the objects. BITSIZE is the field width; BITPOS the position of its first bit (within the word). - VALUE is the value to store. + VALUE is the value to store, which has mode VALUE_MODE. + If OP0_MODE is defined, it is the mode of OP0, otherwise OP0 is + a BLKmode MEM. If REVERSE is true, the store is to be done in reverse order. This does not yet handle fields wider than BITS_PER_WORD. */ static void -store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize, +store_split_bit_field (rtx op0, opt_scalar_int_mode op0_mode, + unsigned HOST_WIDE_INT bitsize, unsigned HOST_WIDE_INT bitpos, unsigned HOST_WIDE_INT bitregion_start, unsigned HOST_WIDE_INT bitregion_end, - rtx value, bool reverse) + rtx value, scalar_int_mode value_mode, bool reverse) { unsigned int unit, total_bits, bitsdone = 0; @@ -1293,8 +1314,8 @@ store_split_bit_field (rtx op0, unsigned /* If OP0 is a memory with a mode, then UNIT must not be larger than OP0's mode as well. Otherwise, store_fixed_bit_field will call us again, and we will mutually recurse forever. */ - if (MEM_P (op0) && GET_MODE_BITSIZE (GET_MODE (op0)) > 0) - unit = MIN (unit, GET_MODE_BITSIZE (GET_MODE (op0))); + if (MEM_P (op0) && op0_mode.exists ()) + unit = MIN (unit, GET_MODE_BITSIZE (*op0_mode)); /* If VALUE is a constant other than a CONST_INT, get it into a register in WORD_MODE. If we can do this using gen_lowpart_common, do so. Note @@ -1306,20 +1327,18 @@ store_split_bit_field (rtx op0, unsigned if (word && (value != word)) value = word; else - value = gen_lowpart_common (word_mode, - force_reg (GET_MODE (value) != VOIDmode - ? GET_MODE (value) - : word_mode, value)); + value = gen_lowpart_common (word_mode, force_reg (value_mode, value)); + value_mode = word_mode; } - total_bits = GET_MODE_BITSIZE (GET_MODE (value)); + total_bits = GET_MODE_BITSIZE (value_mode); while (bitsdone < bitsize) { unsigned HOST_WIDE_INT thissize; unsigned HOST_WIDE_INT thispos; unsigned HOST_WIDE_INT offset; - rtx part, word; + rtx part; offset = (bitpos + bitsdone) / unit; thispos = (bitpos + bitsdone) % unit; @@ -1353,19 +1372,18 @@ store_split_bit_field (rtx op0, unsigned & ((HOST_WIDE_INT_1 << thissize) - 1)); /* Likewise, but the source is little-endian. */ else if (reverse) - part = extract_fixed_bit_field (word_mode, value, thissize, + part = extract_fixed_bit_field (word_mode, value, value_mode, + thissize, bitsize - bitsdone - thissize, NULL_RTX, 1, false); else - { - int total_bits = GET_MODE_BITSIZE (GET_MODE (value)); - /* The args are chosen so that the last part includes the - lsb. Give extract_bit_field the value it needs (with - endianness compensation) to fetch the piece we want. */ - part = extract_fixed_bit_field (word_mode, value, thissize, - total_bits - bitsize + bitsdone, - NULL_RTX, 1, false); - } + /* The args are chosen so that the last part includes the + lsb. Give extract_bit_field the value it needs (with + endianness compensation) to fetch the piece we want. */ + part = extract_fixed_bit_field (word_mode, value, value_mode, + thissize, + total_bits - bitsize + bitsdone, + NULL_RTX, 1, false); } else { @@ -1376,34 +1394,42 @@ store_split_bit_field (rtx op0, unsigned & ((HOST_WIDE_INT_1 << thissize) - 1)); /* Likewise, but the source is big-endian. */ else if (reverse) - part = extract_fixed_bit_field (word_mode, value, thissize, + part = extract_fixed_bit_field (word_mode, value, value_mode, + thissize, total_bits - bitsdone - thissize, NULL_RTX, 1, false); else - part = extract_fixed_bit_field (word_mode, value, thissize, - bitsdone, NULL_RTX, 1, false); + part = extract_fixed_bit_field (word_mode, value, value_mode, + thissize, bitsdone, NULL_RTX, + 1, false); } /* If OP0 is a register, then handle OFFSET here. */ + rtx op0_piece = op0; + opt_scalar_int_mode op0_piece_mode = op0_mode; if (SUBREG_P (op0) || REG_P (op0)) { - machine_mode op0_mode = GET_MODE (op0); - if (op0_mode != BLKmode && GET_MODE_SIZE (op0_mode) < UNITS_PER_WORD) - word = offset ? const0_rtx : op0; + if (op0_mode.exists () && GET_MODE_SIZE (*op0_mode) < UNITS_PER_WORD) + { + if (offset) + op0_piece = const0_rtx; + } else - word = operand_subword_force (op0, offset * unit / BITS_PER_WORD, - GET_MODE (op0)); + { + op0_piece = operand_subword_force (op0, + offset * unit / BITS_PER_WORD, + GET_MODE (op0)); + op0_piece_mode = word_mode; + } offset &= BITS_PER_WORD / unit - 1; } - else - word = op0; /* OFFSET is in UNITs, and UNIT is in bits. If WORD is const0_rtx, it is just an out-of-bounds access. Ignore it. */ - if (word != const0_rtx) - store_fixed_bit_field (word, thissize, offset * unit + thispos, - bitregion_start, bitregion_end, part, - reverse); + if (op0_piece != const0_rtx) + store_fixed_bit_field (op0_piece, op0_piece_mode, thissize, + offset * unit + thispos, bitregion_start, + bitregion_end, part, word_mode, reverse); bitsdone += thissize; } } @@ -1435,11 +1461,13 @@ convert_extracted_bit_field (rtx x, mach /* Try to use an ext(z)v pattern to extract a field from OP0. Return the extracted value on success, otherwise return null. - EXT_MODE is the mode of the extraction and the other arguments - are as for extract_bit_field. */ + EXTV describes the extraction instruction to use. If OP0_MODE + is defined, it is the mode of OP0, otherwise OP0 is a BLKmode MEM. + The other arguments are as for extract_bit_field. */ static rtx extract_bit_field_using_extv (const extraction_insn *extv, rtx op0, + opt_scalar_int_mode op0_mode, unsigned HOST_WIDE_INT bitsize, unsigned HOST_WIDE_INT bitnum, int unsignedp, rtx target, @@ -1448,7 +1476,7 @@ extract_bit_field_using_extv (const extr struct expand_operand ops[4]; rtx spec_target = target; rtx spec_target_subreg = 0; - machine_mode ext_mode = extv->field_mode; + scalar_int_mode ext_mode = extv->field_mode; unsigned unit = GET_MODE_BITSIZE (ext_mode); if (bitsize == 0 || unit < bitsize) @@ -1462,13 +1490,13 @@ extract_bit_field_using_extv (const extr { /* Convert from counting within OP0 to counting in EXT_MODE. */ if (BYTES_BIG_ENDIAN) - bitnum += unit - GET_MODE_BITSIZE (GET_MODE (op0)); + bitnum += unit - GET_MODE_BITSIZE (*op0_mode); /* If op0 is a register, we need it in EXT_MODE to make it acceptable to the format of ext(z)v. */ - if (GET_CODE (op0) == SUBREG && GET_MODE (op0) != ext_mode) + if (GET_CODE (op0) == SUBREG && *op0_mode != ext_mode) return NULL_RTX; - if (REG_P (op0) && GET_MODE (op0) != ext_mode) + if (REG_P (op0) && *op0_mode != ext_mode) op0 = gen_lowpart_SUBREG (ext_mode, op0); } @@ -1617,20 +1645,20 @@ extract_bit_field_1 (rtx str_rtx, unsign /* Make sure we are playing with integral modes. Pun with subregs if we aren't. */ - opt_scalar_int_mode imode = int_mode_for_mode (GET_MODE (op0)); - if (!imode.exists () || *imode != GET_MODE (op0)) + opt_scalar_int_mode op0_mode = int_mode_for_mode (GET_MODE (op0)); + if (!op0_mode.exists () || *op0_mode != GET_MODE (op0)) { if (MEM_P (op0)) - op0 = adjust_bitfield_address_size (op0, imode.else_blk (), + op0 = adjust_bitfield_address_size (op0, op0_mode.else_blk (), 0, MEM_SIZE (op0)); - else if (imode.exists ()) + else if (op0_mode.exists ()) { - op0 = gen_lowpart (*imode, op0); + op0 = gen_lowpart (*op0_mode, op0); /* If we got a SUBREG, force it into a register since we aren't going to be able to do another SUBREG on it. */ if (GET_CODE (op0) == SUBREG) - op0 = force_reg (*imode, op0); + op0 = force_reg (*op0_mode, op0); } else { @@ -1662,11 +1690,11 @@ extract_bit_field_1 (rtx str_rtx, unsign bit of either OP0 or a word of OP0. */ if (!MEM_P (op0) && !reverse - && lowpart_bit_field_p (bitnum, bitsize, GET_MODE (op0)) + && lowpart_bit_field_p (bitnum, bitsize, *op0_mode) && bitsize == GET_MODE_BITSIZE (mode1) - && TRULY_NOOP_TRUNCATION_MODES_P (mode1, GET_MODE (op0))) + && TRULY_NOOP_TRUNCATION_MODES_P (mode1, *op0_mode)) { - rtx sub = simplify_gen_subreg (mode1, op0, GET_MODE (op0), + rtx sub = simplify_gen_subreg (mode1, op0, *op0_mode, bitnum / BITS_PER_UNIT); if (sub) return convert_extracted_bit_field (sub, mode, tmode, unsignedp); @@ -1769,18 +1797,19 @@ extract_bit_field_1 (rtx str_rtx, unsign /* If OP0 is a multi-word register, narrow it to the affected word. If the region spans two words, defer to extract_split_bit_field. */ - if (!MEM_P (op0) && GET_MODE_SIZE (GET_MODE (op0)) > UNITS_PER_WORD) + if (!MEM_P (op0) && GET_MODE_SIZE (*op0_mode) > UNITS_PER_WORD) { if (bitnum % BITS_PER_WORD + bitsize > BITS_PER_WORD) { if (!fallback_p) return NULL_RTX; - target = extract_split_bit_field (op0, bitsize, bitnum, unsignedp, - reverse); + target = extract_split_bit_field (op0, op0_mode, bitsize, bitnum, + unsignedp, reverse); return convert_extracted_bit_field (target, mode, tmode, unsignedp); } - op0 = simplify_gen_subreg (word_mode, op0, GET_MODE (op0), + op0 = simplify_gen_subreg (word_mode, op0, *op0_mode, bitnum / BITS_PER_WORD * UNITS_PER_WORD); + op0_mode = word_mode; bitnum %= BITS_PER_WORD; } @@ -1794,10 +1823,10 @@ extract_bit_field_1 (rtx str_rtx, unsign contains the field, with appropriate checks for endianness and TRULY_NOOP_TRUNCATION. */ && get_best_reg_extraction_insn (&extv, pattern, - GET_MODE_BITSIZE (GET_MODE (op0)), - tmode)) + GET_MODE_BITSIZE (*op0_mode), tmode)) { - rtx result = extract_bit_field_using_extv (&extv, op0, bitsize, bitnum, + rtx result = extract_bit_field_using_extv (&extv, op0, op0_mode, + bitsize, bitnum, unsignedp, target, mode, tmode); if (result) @@ -1811,9 +1840,9 @@ extract_bit_field_1 (rtx str_rtx, unsign if (get_best_mem_extraction_insn (&extv, pattern, bitsize, bitnum, tmode)) { - rtx result = extract_bit_field_using_extv (&extv, op0, bitsize, - bitnum, unsignedp, - target, mode, + rtx result = extract_bit_field_using_extv (&extv, op0, op0_mode, + bitsize, bitnum, + unsignedp, target, mode, tmode); if (result) return result; @@ -1849,8 +1878,8 @@ extract_bit_field_1 (rtx str_rtx, unsign do a load. */ int_mode = *int_mode_for_mode (mode); - target = extract_fixed_bit_field (int_mode, op0, bitsize, bitnum, target, - unsignedp, reverse); + target = extract_fixed_bit_field (int_mode, op0, op0_mode, bitsize, + bitnum, target, unsignedp, reverse); /* Complex values must be reversed piecewise, so we need to undo the global reversal, convert to the complex mode and reverse again. */ @@ -1929,7 +1958,8 @@ extract_bit_field (rtx str_rtx, unsigned } /* Use shifts and boolean operations to extract a field of BITSIZE bits - from bit BITNUM of OP0. + from bit BITNUM of OP0. If OP0_MODE is defined, it is the mode of OP0, + otherwise OP0 is a BLKmode MEM. UNSIGNEDP is nonzero for an unsigned bit field (don't sign-extend value). If REVERSE is true, the extraction is to be done in reverse order. @@ -1940,39 +1970,40 @@ extract_bit_field (rtx str_rtx, unsigned static rtx extract_fixed_bit_field (machine_mode tmode, rtx op0, + opt_scalar_int_mode op0_mode, unsigned HOST_WIDE_INT bitsize, unsigned HOST_WIDE_INT bitnum, rtx target, int unsignedp, bool reverse) { + scalar_int_mode mode; if (MEM_P (op0)) { - scalar_int_mode mode; if (!get_best_mode (bitsize, bitnum, 0, 0, MEM_ALIGN (op0), BITS_PER_WORD, MEM_VOLATILE_P (op0), &mode)) /* The only way this should occur is if the field spans word boundaries. */ - return extract_split_bit_field (op0, bitsize, bitnum, unsignedp, - reverse); + return extract_split_bit_field (op0, op0_mode, bitsize, bitnum, + unsignedp, reverse); op0 = narrow_bit_field_mem (op0, mode, bitsize, bitnum, &bitnum); } + else + mode = *op0_mode; - return extract_fixed_bit_field_1 (tmode, op0, bitsize, bitnum, + return extract_fixed_bit_field_1 (tmode, op0, mode, bitsize, bitnum, target, unsignedp, reverse); } /* Helper function for extract_fixed_bit_field, extracts - the bit field always using the MODE of OP0. */ + the bit field always using MODE, which is the mode of OP0. + The other arguments are as for extract_fixed_bit_field. */ static rtx -extract_fixed_bit_field_1 (machine_mode tmode, rtx op0, +extract_fixed_bit_field_1 (machine_mode tmode, rtx op0, scalar_int_mode mode, unsigned HOST_WIDE_INT bitsize, unsigned HOST_WIDE_INT bitnum, rtx target, int unsignedp, bool reverse) { - machine_mode mode = GET_MODE (op0); - gcc_assert (SCALAR_INT_MODE_P (mode)); - /* Note that bitsize + bitnum can be greater than GET_MODE_BITSIZE (mode) for invalid input, such as extract equivalent of f5 from gcc.dg/pr48335-2.c. */ @@ -1999,16 +2030,19 @@ extract_fixed_bit_field_1 (machine_mode subtarget = 0; op0 = expand_shift (RSHIFT_EXPR, mode, op0, bitnum, subtarget, 1); } - /* Convert the value to the desired mode. */ - if (mode != tmode) - op0 = convert_to_mode (tmode, op0, 1); + /* Convert the value to the desired mode. TMODE must also be a + scalar integer for this conversion to make sense, since we + shouldn't reinterpret the bits. */ + scalar_int_mode new_mode = as_a <scalar_int_mode> (tmode); + if (mode != new_mode) + op0 = convert_to_mode (new_mode, op0, 1); /* Unless the msb of the field used to be the msb when we shifted, mask out the upper bits. */ if (GET_MODE_BITSIZE (mode) != bitnum + bitsize) - return expand_binop (GET_MODE (op0), and_optab, op0, - mask_rtx (GET_MODE (op0), 0, bitsize, 0), + return expand_binop (new_mode, and_optab, op0, + mask_rtx (new_mode, 0, bitsize, 0), target, 1, OPTAB_LIB_WIDEN); return op0; } @@ -2058,11 +2092,14 @@ lshift_value (machine_mode mode, unsigne OP0 is the REG, SUBREG or MEM rtx for the first of the two words. BITSIZE is the field width; BITPOS, position of its first bit, in the word. UNSIGNEDP is 1 if should zero-extend the contents; else sign-extend. + If OP0_MODE is defined, it is the mode of OP0, otherwise OP0 is + a BLKmode MEM. If REVERSE is true, the extraction is to be done in reverse order. */ static rtx -extract_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize, +extract_split_bit_field (rtx op0, opt_scalar_int_mode op0_mode, + unsigned HOST_WIDE_INT bitsize, unsigned HOST_WIDE_INT bitpos, int unsignedp, bool reverse) { @@ -2081,7 +2118,7 @@ extract_split_bit_field (rtx op0, unsign while (bitsdone < bitsize) { unsigned HOST_WIDE_INT thissize; - rtx part, word; + rtx part; unsigned HOST_WIDE_INT thispos; unsigned HOST_WIDE_INT offset; @@ -2095,19 +2132,21 @@ extract_split_bit_field (rtx op0, unsign thissize = MIN (thissize, unit - thispos); /* If OP0 is a register, then handle OFFSET here. */ + rtx op0_piece = op0; + opt_scalar_int_mode op0_piece_mode = op0_mode; if (SUBREG_P (op0) || REG_P (op0)) { - word = operand_subword_force (op0, offset, GET_MODE (op0)); + op0_piece = operand_subword_force (op0, offset, *op0_mode); + op0_piece_mode = word_mode; offset = 0; } - else - word = op0; /* Extract the parts in bit-counting order, whose meaning is determined by BYTES_PER_UNIT. OFFSET is in UNITs, and UNIT is in bits. */ - part = extract_fixed_bit_field (word_mode, word, thissize, - offset * unit + thispos, 0, 1, reverse); + part = extract_fixed_bit_field (word_mode, op0_piece, op0_piece_mode, + thissize, offset * unit + thispos, + 0, 1, reverse); bitsdone += thissize; /* Shift this part into place for the result. */