Commit bebf0797 by Richard Sandiford Committed by Richard Sandiford

expmed.c (lowpart_bit_field_p): New function.

gcc/
	* expmed.c (lowpart_bit_field_p): New function.
	(store_bit_field_1): Remove unit, offset, bitpos and byte_offset
	from the outermost scope.  Express conditions in terms of bitnum
	rather than offset, bitpos and byte_offset.  Split the plain move
	cases into two, one for memory accesses and one for register accesses.
	Allow simplify_gen_subreg to fail rather than calling validate_subreg.
	Move the handling of multiword OP0s after the code that coerces VALUE
	to an integer mode.  Use simplify_gen_subreg for this case and assert
	that it succeeds.  If the field still spans several words, pass it
	directly to store_split_bit_field.  Assume after that point that
	both sources and register targets fit within a word.  Replace
	x-prefixed variables with non-prefixed forms.  Compute the bitpos
	for insv register operands directly in the chosen unit size, rather
	than going through an intermediate BITS_PER_WORD unit size.
	Update the call to store_fixed_bit_field.
	(store_fixed_bit_field): Replace the bitpos and offset parameters
	with a single bitnum parameter, of the same form as store_bit_field.
	Assume that OP0 contains the full field.  Simplify the memory offset
	calculation.  Assert that the processed OP0 has an integral mode.
	(store_split_bit_field): Update the call to store_fixed_bit_field.

From-SVN: r192740
parent a17d5a98
2012-10-23 Richard Sandiford <rdsandiford@googlemail.com>
* expmed.c (lowpart_bit_field_p): New function.
(store_bit_field_1): Remove unit, offset, bitpos and byte_offset
from the outermost scope. Express conditions in terms of bitnum
rather than offset, bitpos and byte_offset. Split the plain move
cases into two, one for memory accesses and one for register accesses.
Allow simplify_gen_subreg to fail rather than calling validate_subreg.
Move the handling of multiword OP0s after the code that coerces VALUE
to an integer mode. Use simplify_gen_subreg for this case and assert
that it succeeds. If the field still spans several words, pass it
directly to store_split_bit_field. Assume after that point that
both sources and register targets fit within a word. Replace
x-prefixed variables with non-prefixed forms. Compute the bitpos
for insv register operands directly in the chosen unit size, rather
than going through an intermediate BITS_PER_WORD unit size.
Update the call to store_fixed_bit_field.
(store_fixed_bit_field): Replace the bitpos and offset parameters
with a single bitnum parameter, of the same form as store_bit_field.
Assume that OP0 contains the full field. Simplify the memory offset
calculation. Assert that the processed OP0 has an integral mode.
(store_split_bit_field): Update the call to store_fixed_bit_field.
2012-10-23 Paul Koning <ni1d@arrl.net> 2012-10-23 Paul Koning <ni1d@arrl.net>
PR debug/54508 PR debug/54508
...@@ -49,7 +49,6 @@ static void store_fixed_bit_field (rtx, unsigned HOST_WIDE_INT, ...@@ -49,7 +49,6 @@ static void store_fixed_bit_field (rtx, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT,
rtx); rtx);
static void store_split_bit_field (rtx, unsigned HOST_WIDE_INT, static void store_split_bit_field (rtx, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
...@@ -394,6 +393,23 @@ mode_for_extraction (enum extraction_pattern pattern, int opno) ...@@ -394,6 +393,23 @@ mode_for_extraction (enum extraction_pattern pattern, int opno)
return data->operand[opno].mode; return data->operand[opno].mode;
} }
/* Return true if a bitfield of size BITSIZE at bit number BITNUM within
a structure of mode STRUCT_MODE represents a lowpart subreg. The subreg
offset is then BITNUM / BITS_PER_UNIT. */
static bool
lowpart_bit_field_p (unsigned HOST_WIDE_INT bitnum,
unsigned HOST_WIDE_INT bitsize,
enum machine_mode struct_mode)
{
if (BYTES_BIG_ENDIAN)
return (bitnum % BITS_PER_UNIT
&& (bitnum + bitsize == GET_MODE_BITSIZE (struct_mode)
|| (bitnum + bitsize) % BITS_PER_WORD == 0));
else
return bitnum % BITS_PER_WORD == 0;
}
/* A subroutine of store_bit_field, with the same arguments. Return true /* A subroutine of store_bit_field, with the same arguments. Return true
if the operation could be implemented. if the operation could be implemented.
...@@ -409,15 +425,9 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -409,15 +425,9 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
enum machine_mode fieldmode, enum machine_mode fieldmode,
rtx value, bool fallback_p) rtx value, bool fallback_p)
{ {
unsigned int unit
= (MEM_P (str_rtx)) ? BITS_PER_UNIT : BITS_PER_WORD;
unsigned HOST_WIDE_INT offset, bitpos;
rtx op0 = str_rtx; rtx op0 = str_rtx;
int byte_offset;
rtx orig_value; rtx orig_value;
enum machine_mode op_mode = mode_for_extraction (EP_insv, 3);
while (GET_CODE (op0) == SUBREG) while (GET_CODE (op0) == SUBREG)
{ {
/* The following line once was done only if WORDS_BIG_ENDIAN, /* The following line once was done only if WORDS_BIG_ENDIAN,
...@@ -427,8 +437,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -427,8 +437,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
always get higher addresses. */ always get higher addresses. */
int inner_mode_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))); int inner_mode_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)));
int outer_mode_size = GET_MODE_SIZE (GET_MODE (op0)); int outer_mode_size = GET_MODE_SIZE (GET_MODE (op0));
int byte_offset = 0;
byte_offset = 0;
/* Paradoxical subregs need special handling on big endian machines. */ /* Paradoxical subregs need special handling on big endian machines. */
if (SUBREG_BYTE (op0) == 0 && inner_mode_size < outer_mode_size) if (SUBREG_BYTE (op0) == 0 && inner_mode_size < outer_mode_size)
...@@ -476,34 +485,34 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -476,34 +485,34 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
} }
/* If the target is a register, overwriting the entire object, or storing /* If the target is a register, overwriting the entire object, or storing
a full-word or multi-word field can be done with just a SUBREG. a full-word or multi-word field can be done with just a SUBREG. */
if (!MEM_P (op0)
&& bitsize == GET_MODE_BITSIZE (fieldmode)
&& ((bitsize == GET_MODE_BITSIZE (GET_MODE (op0)) && bitnum == 0)
|| (bitsize % BITS_PER_WORD == 0 && bitnum % BITS_PER_WORD == 0)))
{
/* Use the subreg machinery either to narrow OP0 to the required
words or to cope with mode punning between equal-sized modes. */
rtx sub = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
bitnum / BITS_PER_UNIT);
if (sub)
{
emit_move_insn (sub, value);
return true;
}
}
If the target is memory, storing any naturally aligned field can be /* If the target is memory, storing any naturally aligned field can be
done with a simple store. For targets that support fast unaligned done with a simple store. For targets that support fast unaligned
memory, any naturally sized, unit aligned field can be done directly. */ memory, any naturally sized, unit aligned field can be done directly. */
if (MEM_P (op0)
offset = bitnum / unit; && bitnum % BITS_PER_UNIT == 0
bitpos = bitnum % unit;
byte_offset = (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
+ (offset * UNITS_PER_WORD);
if (bitpos == 0
&& bitsize == GET_MODE_BITSIZE (fieldmode) && bitsize == GET_MODE_BITSIZE (fieldmode)
&& (!MEM_P (op0) && (!SLOW_UNALIGNED_ACCESS (fieldmode, MEM_ALIGN (op0))
? ((GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD || (bitnum % bitsize == 0
|| GET_MODE_SIZE (GET_MODE (op0)) == GET_MODE_SIZE (fieldmode)) && MEM_ALIGN (op0) % bitsize == 0)))
&& ((GET_MODE (op0) == fieldmode && byte_offset == 0)
|| validate_subreg (fieldmode, GET_MODE (op0), op0,
byte_offset)))
: (! SLOW_UNALIGNED_ACCESS (fieldmode, MEM_ALIGN (op0))
|| (offset * BITS_PER_UNIT % bitsize == 0
&& MEM_ALIGN (op0) % GET_MODE_BITSIZE (fieldmode) == 0))))
{ {
if (MEM_P (op0)) op0 = adjust_bitfield_address (op0, fieldmode, bitnum / BITS_PER_UNIT);
op0 = adjust_bitfield_address (op0, fieldmode, offset);
else if (GET_MODE (op0) != fieldmode)
op0 = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
byte_offset);
emit_move_insn (op0, value); emit_move_insn (op0, value);
return true; return true;
} }
...@@ -526,19 +535,11 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -526,19 +535,11 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
} }
} }
/* If OP0 is a register, BITPOS must count within a word.
But as we have it, it counts within whatever size OP0 now has.
On a bigendian machine, these are not the same, so convert. */
if (BYTES_BIG_ENDIAN
&& !MEM_P (op0)
&& unit > GET_MODE_BITSIZE (GET_MODE (op0)))
bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0));
/* Storing an lsb-aligned field in a register /* Storing an lsb-aligned field in a register
can be done with a movestrict instruction. */ can be done with a movstrict instruction. */
if (!MEM_P (op0) if (!MEM_P (op0)
&& (BYTES_BIG_ENDIAN ? bitpos + bitsize == unit : bitpos == 0) && lowpart_bit_field_p (bitnum, bitsize, GET_MODE (op0))
&& bitsize == GET_MODE_BITSIZE (fieldmode) && bitsize == GET_MODE_BITSIZE (fieldmode)
&& optab_handler (movstrict_optab, fieldmode) != CODE_FOR_nothing) && optab_handler (movstrict_optab, fieldmode) != CODE_FOR_nothing)
{ {
...@@ -558,8 +559,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -558,8 +559,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
arg0 = SUBREG_REG (arg0); arg0 = SUBREG_REG (arg0);
} }
subreg_off = (bitnum % BITS_PER_WORD) / BITS_PER_UNIT subreg_off = bitnum / BITS_PER_UNIT;
+ (offset * UNITS_PER_WORD);
if (validate_subreg (fieldmode, GET_MODE (arg0), arg0, subreg_off)) if (validate_subreg (fieldmode, GET_MODE (arg0), arg0, subreg_off))
{ {
arg0 = gen_rtx_SUBREG (fieldmode, arg0, subreg_off); arg0 = gen_rtx_SUBREG (fieldmode, arg0, subreg_off);
...@@ -638,34 +638,6 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -638,34 +638,6 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
return true; return true;
} }
/* From here on we can assume that the field to be stored in is
a full-word (whatever type that is), since it is shorter than a word. */
/* OFFSET is the number of words or bytes (UNIT says which)
from STR_RTX to the first word or byte containing part of the field. */
if (!MEM_P (op0))
{
if (offset != 0
|| GET_MODE_SIZE (GET_MODE (op0)) > UNITS_PER_WORD)
{
if (!REG_P (op0))
{
/* Since this is a destination (lvalue), we can't copy
it to a pseudo. We can remove a SUBREG that does not
change the size of the operand. Such a SUBREG may
have been added above. */
gcc_assert (GET_CODE (op0) == SUBREG
&& (GET_MODE_SIZE (GET_MODE (op0))
== GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))));
op0 = SUBREG_REG (op0);
}
op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0),
op0, (offset * UNITS_PER_WORD));
}
offset = 0;
}
/* If VALUE has a floating-point or complex mode, access it as an /* If VALUE has a floating-point or complex mode, access it as an
integer of the corresponding size. This can occur on a machine integer of the corresponding size. This can occur on a machine
with 64 bit registers that uses SFmode for float. It can also with 64 bit registers that uses SFmode for float. It can also
...@@ -679,9 +651,30 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -679,9 +651,30 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
emit_move_insn (gen_lowpart (GET_MODE (orig_value), value), orig_value); emit_move_insn (gen_lowpart (GET_MODE (orig_value), value), orig_value);
} }
/* Now OFFSET is nonzero only if OP0 is memory /* If OP0 is a multi-word register, narrow it to the affected word.
and is therefore always measured in bytes. */ If the region spans two words, defer to store_split_bit_field. */
if (!MEM_P (op0) && GET_MODE_SIZE (GET_MODE (op0)) > UNITS_PER_WORD)
{
op0 = simplify_gen_subreg (word_mode, op0, GET_MODE (op0),
bitnum / BITS_PER_WORD * UNITS_PER_WORD);
gcc_assert (op0);
bitnum %= BITS_PER_WORD;
if (bitnum + bitsize > BITS_PER_WORD)
{
if (!fallback_p)
return false;
store_split_bit_field (op0, bitsize, bitnum, bitregion_start,
bitregion_end, value);
return true;
}
}
/* From here on we can assume that the field to be stored in fits
within a word. If the destination is a register, it too fits
in a word. */
enum machine_mode op_mode = mode_for_extraction (EP_insv, 3);
if (HAVE_insv if (HAVE_insv
&& GET_MODE (value) != BLKmode && GET_MODE (value) != BLKmode
&& bitsize > 0 && bitsize > 0
...@@ -690,25 +683,34 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -690,25 +683,34 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
-fstrict-volatile-bitfields is in effect. */ -fstrict-volatile-bitfields is in effect. */
&& !(MEM_P (op0) && MEM_VOLATILE_P (op0) && !(MEM_P (op0) && MEM_VOLATILE_P (op0)
&& flag_strict_volatile_bitfields > 0) && flag_strict_volatile_bitfields > 0)
&& ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
&& (bitsize + bitpos > GET_MODE_BITSIZE (op_mode)))
/* Do not use insv if the bit region is restricted and /* Do not use insv if the bit region is restricted and
op_mode integer at offset doesn't fit into the op_mode integer at offset doesn't fit into the
restricted region. */ restricted region. */
&& !(MEM_P (op0) && bitregion_end && !(MEM_P (op0) && bitregion_end
&& bitnum - bitpos + GET_MODE_BITSIZE (op_mode) && bitnum - (bitnum % BITS_PER_UNIT) + GET_MODE_BITSIZE (op_mode)
> bitregion_end + 1)) > bitregion_end + 1))
{ {
struct expand_operand ops[4]; struct expand_operand ops[4];
int xbitpos = bitpos; unsigned HOST_WIDE_INT bitpos = bitnum;
rtx value1; rtx value1;
rtx xop0 = op0; rtx xop0 = op0;
rtx last = get_last_insn (); rtx last = get_last_insn ();
bool copy_back = false; bool copy_back = false;
/* Add OFFSET into OP0's address. */ unsigned int unit = GET_MODE_BITSIZE (op_mode);
if (MEM_P (xop0)) if (MEM_P (xop0))
xop0 = adjust_bitfield_address (xop0, byte_mode, offset); {
/* Get a reference to the first byte of the field. */
xop0 = adjust_bitfield_address (xop0, byte_mode,
bitpos / BITS_PER_UNIT);
bitpos %= BITS_PER_UNIT;
}
else
{
/* Convert from counting within OP0 to counting in OP_MODE. */
if (BYTES_BIG_ENDIAN)
bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0));
}
/* If xop0 is a register, we need it in OP_MODE /* If xop0 is a register, we need it in OP_MODE
to make it acceptable to the format of insv. */ to make it acceptable to the format of insv. */
...@@ -735,20 +737,13 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -735,20 +737,13 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
copy_back = true; copy_back = true;
} }
/* We have been counting XBITPOS within UNIT.
Count instead within the size of the register. */
if (BYTES_BIG_ENDIAN && !MEM_P (xop0))
xbitpos += GET_MODE_BITSIZE (op_mode) - unit;
unit = GET_MODE_BITSIZE (op_mode);
/* If BITS_BIG_ENDIAN is zero on a BYTES_BIG_ENDIAN machine, we count /* If BITS_BIG_ENDIAN is zero on a BYTES_BIG_ENDIAN machine, we count
"backwards" from the size of the unit we are inserting into. "backwards" from the size of the unit we are inserting into.
Otherwise, we count bits from the most significant on a Otherwise, we count bits from the most significant on a
BYTES/BITS_BIG_ENDIAN machine. */ BYTES/BITS_BIG_ENDIAN machine. */
if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN) if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
xbitpos = unit - bitsize - xbitpos; bitpos = unit - bitsize - bitpos;
/* Convert VALUE to op_mode (which insv insn wants) in VALUE1. */ /* Convert VALUE to op_mode (which insv insn wants) in VALUE1. */
value1 = value; value1 = value;
...@@ -787,7 +782,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -787,7 +782,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
create_fixed_operand (&ops[0], xop0); create_fixed_operand (&ops[0], xop0);
create_integer_operand (&ops[1], bitsize); create_integer_operand (&ops[1], bitsize);
create_integer_operand (&ops[2], xbitpos); create_integer_operand (&ops[2], bitpos);
create_input_operand (&ops[3], value1, op_mode); create_input_operand (&ops[3], value1, op_mode);
if (maybe_expand_insn (CODE_FOR_insv, 4, ops)) if (maybe_expand_insn (CODE_FOR_insv, 4, ops))
{ {
...@@ -832,7 +827,8 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -832,7 +827,8 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
&& GET_MODE_BITSIZE (bestmode) > MEM_ALIGN (op0))) && GET_MODE_BITSIZE (bestmode) > MEM_ALIGN (op0)))
{ {
rtx last, tempreg, xop0; rtx last, tempreg, xop0;
unsigned HOST_WIDE_INT xoffset, xbitpos; unsigned int unit;
unsigned HOST_WIDE_INT offset, bitpos;
last = get_last_insn (); last = get_last_insn ();
...@@ -840,14 +836,14 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -840,14 +836,14 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
that mode. Compute the offset as a multiple of this unit, that mode. Compute the offset as a multiple of this unit,
counting in bytes. */ counting in bytes. */
unit = GET_MODE_BITSIZE (bestmode); unit = GET_MODE_BITSIZE (bestmode);
xoffset = (bitnum / unit) * GET_MODE_SIZE (bestmode); offset = (bitnum / unit) * GET_MODE_SIZE (bestmode);
xbitpos = bitnum % unit; bitpos = bitnum % unit;
xop0 = adjust_bitfield_address (op0, bestmode, xoffset); xop0 = adjust_bitfield_address (op0, bestmode, offset);
/* Fetch that unit, store the bitfield in it, then store /* Fetch that unit, store the bitfield in it, then store
the unit. */ the unit. */
tempreg = copy_to_reg (xop0); tempreg = copy_to_reg (xop0);
if (store_bit_field_1 (tempreg, bitsize, xbitpos, if (store_bit_field_1 (tempreg, bitsize, bitpos,
bitregion_start, bitregion_end, bitregion_start, bitregion_end,
fieldmode, orig_value, false)) fieldmode, orig_value, false))
{ {
...@@ -861,8 +857,8 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -861,8 +857,8 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
if (!fallback_p) if (!fallback_p)
return false; return false;
store_fixed_bit_field (op0, offset, bitsize, bitpos, store_fixed_bit_field (op0, bitsize, bitnum, bitregion_start,
bitregion_start, bitregion_end, value); bitregion_end, value);
return true; return true;
} }
...@@ -918,25 +914,17 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -918,25 +914,17 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
gcc_unreachable (); gcc_unreachable ();
} }
/* Use shifts and boolean operations to store VALUE /* Use shifts and boolean operations to store VALUE into a bit field of
into a bit field of width BITSIZE width BITSIZE in OP0, starting at bit BITNUM. */
in a memory location specified by OP0 except offset by OFFSET bytes.
(OFFSET must be 0 if OP0 is a register.)
The field starts at position BITPOS within the byte.
(If OP0 is a register, it may be a full word or a narrower mode,
but BITPOS still counts within a full word,
which is significant on bigendian machines.) */
static void static void
store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset, store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
unsigned HOST_WIDE_INT bitsize, unsigned HOST_WIDE_INT bitnum,
unsigned HOST_WIDE_INT bitpos,
unsigned HOST_WIDE_INT bitregion_start, unsigned HOST_WIDE_INT bitregion_start,
unsigned HOST_WIDE_INT bitregion_end, unsigned HOST_WIDE_INT bitregion_end,
rtx value) rtx value)
{ {
enum machine_mode mode; enum machine_mode mode;
unsigned int total_bits = BITS_PER_WORD;
rtx temp; rtx temp;
int all_zero = 0; int all_zero = 0;
int all_one = 0; int all_one = 0;
...@@ -948,19 +936,7 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset, ...@@ -948,19 +936,7 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
and a field split across two bytes. and a field split across two bytes.
Such cases are not supposed to be able to occur. */ Such cases are not supposed to be able to occur. */
if (REG_P (op0) || GET_CODE (op0) == SUBREG) if (MEM_P (op0))
{
gcc_assert (!offset);
/* Special treatment for a bit field split across two registers. */
if (bitsize + bitpos > BITS_PER_WORD)
{
store_split_bit_field (op0, bitsize, bitpos,
bitregion_start, bitregion_end,
value);
return;
}
}
else
{ {
unsigned HOST_WIDE_INT maxbits = MAX_FIXED_MODE_SIZE; unsigned HOST_WIDE_INT maxbits = MAX_FIXED_MODE_SIZE;
...@@ -983,58 +959,39 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset, ...@@ -983,58 +959,39 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
&& flag_strict_volatile_bitfields > 0) && flag_strict_volatile_bitfields > 0)
mode = GET_MODE (op0); mode = GET_MODE (op0);
else else
mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT, mode = get_best_mode (bitsize, bitnum, bitregion_start, bitregion_end,
bitregion_start, bitregion_end,
MEM_ALIGN (op0), mode, MEM_VOLATILE_P (op0)); MEM_ALIGN (op0), mode, MEM_VOLATILE_P (op0));
if (mode == VOIDmode) if (mode == VOIDmode)
{ {
/* The only way this should occur is if the field spans word /* The only way this should occur is if the field spans word
boundaries. */ boundaries. */
store_split_bit_field (op0, bitsize, bitpos + offset * BITS_PER_UNIT, store_split_bit_field (op0, bitsize, bitnum, bitregion_start,
bitregion_start, bitregion_end, value); bitregion_end, value);
return; return;
} }
total_bits = GET_MODE_BITSIZE (mode); HOST_WIDE_INT bit_offset = bitnum - bitnum % GET_MODE_BITSIZE (mode);
op0 = adjust_bitfield_address (op0, mode, bit_offset / BITS_PER_UNIT);
/* Make sure bitpos is valid for the chosen mode. Adjust BITPOS to bitnum -= bit_offset;
be in the range 0 to total_bits-1, and put any excess bytes in
OFFSET. */
if (bitpos >= total_bits)
{
offset += (bitpos / total_bits) * (total_bits / BITS_PER_UNIT);
bitpos -= ((bitpos / total_bits) * (total_bits / BITS_PER_UNIT)
* BITS_PER_UNIT);
}
/* Get ref to an aligned byte, halfword, or word containing the field.
Adjust BITPOS to be position within a word,
and OFFSET to be the offset of that word.
Then alter OP0 to refer to that word. */
bitpos += (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT;
offset -= (offset % (total_bits / BITS_PER_UNIT));
op0 = adjust_bitfield_address (op0, mode, offset);
} }
mode = GET_MODE (op0); mode = GET_MODE (op0);
gcc_assert (SCALAR_INT_MODE_P (mode));
/* Now MODE is either some integral mode for a MEM as OP0, /* Note that bitsize + bitnum can be greater than GET_MODE_BITSIZE (mode)
or is a full-word for a REG as OP0. TOTAL_BITS corresponds. for invalid input, such as f5 from gcc.dg/pr48335-2.c. */
The bit field is contained entirely within OP0.
BITPOS is the starting bit number within OP0.
(OP0's mode may actually be narrower than MODE.) */
if (BYTES_BIG_ENDIAN) if (BYTES_BIG_ENDIAN)
/* BITPOS is the distance between our msb /* BITNUM is the distance between our msb
and that of the containing datum. and that of the containing datum.
Convert it to the distance from the lsb. */ Convert it to the distance from the lsb. */
bitpos = total_bits - bitsize - bitpos; bitnum = GET_MODE_BITSIZE (mode) - bitsize - bitnum;
/* Now BITPOS is always the distance between our lsb /* Now BITNUM is always the distance between our lsb
and that of OP0. */ and that of OP0. */
/* Shift VALUE left by BITPOS bits. If VALUE is not constant, /* Shift VALUE left by BITNUM bits. If VALUE is not constant,
we must first convert its mode to MODE. */ we must first convert its mode to MODE. */
if (CONST_INT_P (value)) if (CONST_INT_P (value))
...@@ -1051,12 +1008,12 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset, ...@@ -1051,12 +1008,12 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
|| (bitsize == HOST_BITS_PER_WIDE_INT && v == -1)) || (bitsize == HOST_BITS_PER_WIDE_INT && v == -1))
all_one = 1; all_one = 1;
value = lshift_value (mode, value, bitpos, bitsize); value = lshift_value (mode, value, bitnum, bitsize);
} }
else else
{ {
int must_and = (GET_MODE_BITSIZE (GET_MODE (value)) != bitsize int must_and = (GET_MODE_BITSIZE (GET_MODE (value)) != bitsize
&& bitpos + bitsize != GET_MODE_BITSIZE (mode)); && bitnum + bitsize != GET_MODE_BITSIZE (mode));
if (GET_MODE (value) != mode) if (GET_MODE (value) != mode)
value = convert_to_mode (mode, value, 1); value = convert_to_mode (mode, value, 1);
...@@ -1065,9 +1022,9 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset, ...@@ -1065,9 +1022,9 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
value = expand_binop (mode, and_optab, value, value = expand_binop (mode, and_optab, value,
mask_rtx (mode, 0, bitsize, 0), mask_rtx (mode, 0, bitsize, 0),
NULL_RTX, 1, OPTAB_LIB_WIDEN); NULL_RTX, 1, OPTAB_LIB_WIDEN);
if (bitpos > 0) if (bitnum > 0)
value = expand_shift (LSHIFT_EXPR, mode, value, value = expand_shift (LSHIFT_EXPR, mode, value,
bitpos, NULL_RTX, 1); bitnum, NULL_RTX, 1);
} }
/* Now clear the chosen bits in OP0, /* Now clear the chosen bits in OP0,
...@@ -1080,7 +1037,7 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset, ...@@ -1080,7 +1037,7 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
if (! all_one) if (! all_one)
{ {
temp = expand_binop (mode, and_optab, temp, temp = expand_binop (mode, and_optab, temp,
mask_rtx (mode, bitpos, bitsize, 1), mask_rtx (mode, bitnum, bitsize, 1),
NULL_RTX, 1, OPTAB_LIB_WIDEN); NULL_RTX, 1, OPTAB_LIB_WIDEN);
temp = force_reg (mode, temp); temp = force_reg (mode, temp);
} }
...@@ -1235,12 +1192,11 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize, ...@@ -1235,12 +1192,11 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
else else
word = op0; word = op0;
/* OFFSET is in UNITs, and UNIT is in bits. /* OFFSET is in UNITs, and UNIT is in bits. If WORD is const0_rtx,
store_fixed_bit_field wants offset in bytes. If WORD is const0_rtx,
it is just an out-of-bounds access. Ignore it. */ it is just an out-of-bounds access. Ignore it. */
if (word != const0_rtx) if (word != const0_rtx)
store_fixed_bit_field (word, offset * unit / BITS_PER_UNIT, thissize, store_fixed_bit_field (word, thissize, offset * unit + thispos,
thispos, bitregion_start, bitregion_end, part); bitregion_start, bitregion_end, part);
bitsdone += thissize; bitsdone += thissize;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment