===================================================================
@@ -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. */