summaryrefslogtreecommitdiff
path: root/gcc/expmed.c
diff options
context:
space:
mode:
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>2012-10-23 19:17:35 +0000
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>2012-10-23 19:17:35 +0000
commitebf8dd0669c37177396d1956259c34d14bc23cd3 (patch)
treec8c8d433853cf42b50b757be0c2e322949cf4672 /gcc/expmed.c
parent5e81ea649bd660dd51144aec16c2720aa94135ac (diff)
downloadgcc-ebf8dd0669c37177396d1956259c34d14bc23cd3.tar.gz
gcc/
* expmed.c (store_split_bit_field): Update the calls to extract_fixed_bit_field. In the big-endian case, always use the mode of OP0 to count the number of significant bits. (extract_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. Move the computation of MODE1 to the block that needs it. Use MODE unless the TMODE-based mode_for_size calculation succeeds. Split the plain move cases into two, one for memory accesses and one for register accesses. Generalize the memory case, freeing it from the old register-based endian checks. Move the INT_MODE calculation above the code that needs it. Use simplify_gen_subreg to handle multiword OP0s. If the field still spans several words, pass it directly to extract_split_bit_field. Assume after that point that both targets and register sources fit within a word. Replace x-prefixed variables with non-prefixed forms. Compute the bitpos for ext(z)v register operands directly in the chosen unit size, rather than going through an intermediate BITS_PER_WORD unit size. Simplify the containment check used when forcing OP0 into a register. Update the call to extract_fixed_bit_field. (extract_fixed_bit_field): Replace the bitpos and offset parameters with a single bitnum parameter, of the same form as extract_bit_field. Assume that OP0 contains the full field. Simplify the memory offset calculation and containment check for volatile bitfields. Make the offset explicit when volatile bitfields force a misaligned access. Remove WARNED and fix long lines. Assert that the processed OP0 has an integral mode. (store_split_bit_field): Update the call to store_fixed_bit_field. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@192741 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/expmed.c')
-rw-r--r--gcc/expmed.c365
1 files changed, 151 insertions, 214 deletions
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 3ea3e83d8d3..1708f57f0be 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -57,7 +57,6 @@ static void store_split_bit_field (rtx, unsigned HOST_WIDE_INT,
rtx);
static rtx extract_fixed_bit_field (enum machine_mode, rtx,
unsigned HOST_WIDE_INT,
- unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, rtx, int, bool);
static rtx mask_rtx (enum machine_mode, int, int, int);
static rtx lshift_value (enum machine_mode, rtx, int, int);
@@ -1128,28 +1127,21 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
if (BYTES_BIG_ENDIAN)
{
- int total_bits;
-
- /* We must do an endian conversion exactly the same way as it is
- done in extract_bit_field, so that the two calls to
- extract_fixed_bit_field will have comparable arguments. */
- if (!MEM_P (value) || GET_MODE (value) == BLKmode)
- total_bits = BITS_PER_WORD;
- else
- total_bits = GET_MODE_BITSIZE (GET_MODE (value));
-
/* Fetch successively less significant portions. */
if (CONST_INT_P (value))
part = GEN_INT (((unsigned HOST_WIDE_INT) (INTVAL (value))
>> (bitsize - bitsdone - thissize))
& (((HOST_WIDE_INT) 1 << thissize) - 1));
else
- /* 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, 0, thissize,
- total_bits - bitsize + bitsdone,
- NULL_RTX, 1, false);
+ {
+ 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);
+ }
}
else
{
@@ -1159,7 +1151,7 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
>> bitsdone)
& (((HOST_WIDE_INT) 1 << thissize) - 1));
else
- part = extract_fixed_bit_field (word_mode, value, 0, thissize,
+ part = extract_fixed_bit_field (word_mode, value, thissize,
bitsdone, NULL_RTX, 1, false);
}
@@ -1240,14 +1232,10 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
enum machine_mode mode, enum machine_mode tmode,
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;
enum machine_mode int_mode;
enum machine_mode ext_mode;
enum machine_mode mode1;
- int byte_offset;
if (tmode == VOIDmode)
tmode = mode;
@@ -1365,37 +1353,10 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
}
}
- /* Extraction of a full-word or multi-word value from a structure
- in a register or aligned memory can be done with just a SUBREG.
- A subword value in the least significant part of a register
- can also be extracted with a SUBREG. For this, we need the
- byte offset of the value in op0. */
-
- bitpos = bitnum % unit;
- offset = bitnum / unit;
- byte_offset = bitpos / BITS_PER_UNIT + offset * UNITS_PER_WORD;
-
- /* 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));
-
/* ??? We currently assume TARGET is at least as big as BITSIZE.
If that's wrong, the solution is to test for it and set TARGET to 0
if needed. */
- /* Only scalar integer modes can be converted via subregs. There is an
- additional problem for FP modes here in that they can have a precision
- which is different from the size. mode_for_size uses precision, but
- we want a mode based on the size, so we must avoid calling it for FP
- modes. */
- mode1 = (SCALAR_INT_MODE_P (tmode)
- ? mode_for_size (bitsize, GET_MODE_CLASS (tmode), 0)
- : mode);
-
/* If the bitfield is volatile, we need to make sure the access
remains on a type-aligned boundary. */
if (GET_CODE (op0) == MEM
@@ -1404,39 +1365,48 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
&& flag_strict_volatile_bitfields > 0)
goto no_subreg_mode_swap;
- if (((bitsize >= BITS_PER_WORD && bitsize == GET_MODE_BITSIZE (mode)
- && bitpos % BITS_PER_WORD == 0)
- || (mode1 != BLKmode
- /* ??? The big endian test here is wrong. This is correct
- if the value is in a register, and if mode_for_size is not
- the same mode as op0. This causes us to get unnecessarily
- inefficient code from the Thumb port when -mbig-endian. */
- && (BYTES_BIG_ENDIAN
- ? bitpos + bitsize == BITS_PER_WORD
- : bitpos == 0)))
- && ((!MEM_P (op0)
- && TRULY_NOOP_TRUNCATION_MODES_P (mode1, GET_MODE (op0))
- && GET_MODE_SIZE (mode1) != 0
- && byte_offset % GET_MODE_SIZE (mode1) == 0)
- || (MEM_P (op0)
- && (! SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (op0))
- || (offset * BITS_PER_UNIT % bitsize == 0
- && MEM_ALIGN (op0) % bitsize == 0)))))
+ /* Only scalar integer modes can be converted via subregs. There is an
+ additional problem for FP modes here in that they can have a precision
+ which is different from the size. mode_for_size uses precision, but
+ we want a mode based on the size, so we must avoid calling it for FP
+ modes. */
+ mode1 = mode;
+ if (SCALAR_INT_MODE_P (tmode))
{
- if (MEM_P (op0))
- op0 = adjust_bitfield_address (op0, mode1, offset);
- else if (mode1 != GET_MODE (op0))
- {
- rtx sub = simplify_gen_subreg (mode1, op0, GET_MODE (op0),
- byte_offset);
- if (sub == NULL)
- goto no_subreg_mode_swap;
- op0 = sub;
- }
- if (mode1 != mode)
- return convert_to_mode (tmode, op0, unsignedp);
- return op0;
+ enum machine_mode try_mode = mode_for_size (bitsize,
+ GET_MODE_CLASS (tmode), 0);
+ if (try_mode != BLKmode)
+ mode1 = try_mode;
+ }
+ gcc_assert (mode1 != BLKmode);
+
+ /* Extraction of a full MODE1 value can be done with a subreg as long
+ as the least significant bit of the value is the least significant
+ bit of either OP0 or a word of OP0. */
+ if (!MEM_P (op0)
+ && lowpart_bit_field_p (bitnum, bitsize, GET_MODE (op0))
+ && bitsize == GET_MODE_BITSIZE (mode1)
+ && TRULY_NOOP_TRUNCATION_MODES_P (mode1, GET_MODE (op0)))
+ {
+ rtx sub = simplify_gen_subreg (mode1, op0, GET_MODE (op0),
+ bitnum / BITS_PER_UNIT);
+ if (sub)
+ return convert_extracted_bit_field (sub, mode, tmode, unsignedp);
+ }
+
+ /* Extraction of a full MODE1 value can be done with a load as long as
+ the field is on a byte boundary and is sufficiently aligned. */
+ if (MEM_P (op0)
+ && bitnum % BITS_PER_UNIT == 0
+ && bitsize == GET_MODE_BITSIZE (mode1)
+ && (!SLOW_UNALIGNED_ACCESS (mode1, MEM_ALIGN (op0))
+ || (bitnum % bitsize == 0
+ && MEM_ALIGN (op0) % bitsize == 0)))
+ {
+ op0 = adjust_bitfield_address (op0, mode1, bitnum / BITS_PER_UNIT);
+ return convert_extracted_bit_field (op0, mode, tmode, unsignedp);
}
+
no_subreg_mode_swap:
/* Handle fields bigger than a word. */
@@ -1517,35 +1487,25 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
GET_MODE_BITSIZE (mode) - bitsize, NULL_RTX, 0);
}
- /* From here on we know the desired field is smaller than a word. */
-
- /* Check if there is a correspondingly-sized integer field, so we can
- safely extract it as one size of integer, if necessary; then
- truncate or extend to the size that is wanted; then use SUBREGs or
- convert_to_mode to get one of the modes we really wanted. */
-
- int_mode = int_mode_for_mode (tmode);
- if (int_mode == BLKmode)
- int_mode = int_mode_for_mode (mode);
- /* Should probably push op0 out to memory and then do a load. */
- gcc_assert (int_mode != BLKmode);
-
- /* 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 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 (offset != 0
- || 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);
+ bitnum %= BITS_PER_WORD;
+ if (bitnum + bitsize > BITS_PER_WORD)
{
- if (!REG_P (op0))
- op0 = copy_to_reg (op0);
- op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0),
- op0, (offset * UNITS_PER_WORD));
+ if (!fallback_p)
+ return NULL_RTX;
+ target = extract_split_bit_field (op0, bitsize, bitnum, unsignedp);
+ return convert_extracted_bit_field (target, mode, tmode, unsignedp);
}
- offset = 0;
}
- /* Now OFFSET is nonzero only for memory operands. */
+ /* From here on we know the desired field is smaller than a word.
+ If OP0 is a register, it too fits within a word. */
+
ext_mode = mode_for_extraction (unsignedp ? EP_extzv : EP_extv, 0);
if (ext_mode != MAX_MACHINE_MODE
&& bitsize > 0
@@ -1556,30 +1516,34 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
&& flag_strict_volatile_bitfields > 0)
/* If op0 is a register, we need it in EXT_MODE to make it
acceptable to the format of ext(z)v. */
- && !(GET_CODE (op0) == SUBREG && GET_MODE (op0) != ext_mode)
- && !((REG_P (op0) || GET_CODE (op0) == SUBREG)
- && (bitsize + bitpos > GET_MODE_BITSIZE (ext_mode))))
+ && !(GET_CODE (op0) == SUBREG && GET_MODE (op0) != ext_mode))
{
struct expand_operand ops[4];
- unsigned HOST_WIDE_INT xbitpos = bitpos, xoffset = offset;
+ unsigned HOST_WIDE_INT bitpos = bitnum;
rtx xop0 = op0;
rtx xtarget = target;
rtx xspec_target = target;
rtx xspec_target_subreg = 0;
+ unsigned unit = GET_MODE_BITSIZE (ext_mode);
/* If op0 is a register, we need it in EXT_MODE to make it
acceptable to the format of ext(z)v. */
if (REG_P (xop0) && GET_MODE (xop0) != ext_mode)
xop0 = gen_lowpart_SUBREG (ext_mode, xop0);
- if (MEM_P (xop0))
- /* Get ref to first byte containing part of the field. */
- xop0 = adjust_bitfield_address (xop0, byte_mode, xoffset);
- /* Now convert from counting within UNIT to counting in EXT_MODE. */
- if (BYTES_BIG_ENDIAN && !MEM_P (xop0))
- xbitpos += GET_MODE_BITSIZE (ext_mode) - unit;
-
- unit = GET_MODE_BITSIZE (ext_mode);
+ if (MEM_P (xop0))
+ {
+ /* 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 EXT_MODE. */
+ if (BYTES_BIG_ENDIAN)
+ bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0));
+ }
/* If BITS_BIG_ENDIAN is zero on a BYTES_BIG_ENDIAN machine, we count
"backwards" from the size of the unit we are extracting from.
@@ -1587,7 +1551,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
BYTES/BITS_BIG_ENDIAN machine. */
if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
- xbitpos = unit - bitsize - xbitpos;
+ bitpos = unit - bitsize - bitpos;
if (xtarget == 0)
xtarget = xspec_target = gen_reg_rtx (tmode);
@@ -1613,7 +1577,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
create_output_operand (&ops[0], xtarget, ext_mode);
create_fixed_operand (&ops[1], xop0);
create_integer_operand (&ops[2], bitsize);
- create_integer_operand (&ops[3], xbitpos);
+ create_integer_operand (&ops[3], bitpos);
if (maybe_expand_insn (unsignedp ? CODE_FOR_extzv : CODE_FOR_extv,
4, ops))
{
@@ -1652,26 +1616,25 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
&& !(SLOW_UNALIGNED_ACCESS (bestmode, MEM_ALIGN (op0))
&& GET_MODE_BITSIZE (bestmode) > MEM_ALIGN (op0)))
{
- unsigned HOST_WIDE_INT xoffset, xbitpos;
+ unsigned HOST_WIDE_INT offset, bitpos;
/* Compute the offset as a multiple of this unit,
counting in bytes. */
- unit = GET_MODE_BITSIZE (bestmode);
- xoffset = (bitnum / unit) * GET_MODE_SIZE (bestmode);
- xbitpos = bitnum % unit;
+ unsigned int unit = GET_MODE_BITSIZE (bestmode);
+ offset = (bitnum / unit) * GET_MODE_SIZE (bestmode);
+ bitpos = bitnum % unit;
/* Make sure the register is big enough for the whole field. */
- if (xoffset * BITS_PER_UNIT + unit
- >= offset * BITS_PER_UNIT + bitsize)
+ if (bitpos + bitsize <= unit)
{
rtx last, result, xop0;
last = get_last_insn ();
/* Fetch it to a register in that size. */
- xop0 = adjust_bitfield_address (op0, bestmode, xoffset);
+ xop0 = adjust_bitfield_address (op0, bestmode, offset);
xop0 = force_reg (bestmode, xop0);
- result = extract_bit_field_1 (xop0, bitsize, xbitpos,
+ result = extract_bit_field_1 (xop0, bitsize, bitpos,
unsignedp, packedp, target,
mode, tmode, false);
if (result)
@@ -1685,8 +1648,16 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
if (!fallback_p)
return NULL;
- target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
- bitpos, target, unsignedp, packedp);
+ /* Find a correspondingly-sized integer field, so we can apply
+ shifts and masks to it. */
+ int_mode = int_mode_for_mode (tmode);
+ if (int_mode == BLKmode)
+ int_mode = int_mode_for_mode (mode);
+ /* Should probably push op0 out to memory and then do a load. */
+ gcc_assert (int_mode != BLKmode);
+
+ target = extract_fixed_bit_field (int_mode, op0, bitsize, bitnum,
+ target, unsignedp, packedp);
return convert_extracted_bit_field (target, mode, tmode, unsignedp);
}
@@ -1716,16 +1687,8 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
target, mode, tmode, true);
}
-/* Extract a bit field using shifts and boolean operations
- Returns an rtx to represent the value.
- OP0 addresses a register (word) or memory (byte).
- BITPOS says which bit within the word or byte the bit field starts in.
- OFFSET says how many bytes farther the bit field starts;
- it is 0 if OP0 is a register.
- BITSIZE says how many bits long the bit field is.
- (If OP0 is a register, it may be narrower than a full word,
- but BITPOS still counts within a full word,
- which is significant on bigendian machines.)
+/* Use shifts and boolean operations to extract a field of BITSIZE bits
+ from bit BITNUM of OP0.
UNSIGNEDP is nonzero for an unsigned bit field (don't sign-extend value).
PACKEDP is true if the field has the packed attribute.
@@ -1736,21 +1699,13 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
static rtx
extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
- unsigned HOST_WIDE_INT offset,
unsigned HOST_WIDE_INT bitsize,
- unsigned HOST_WIDE_INT bitpos, rtx target,
+ unsigned HOST_WIDE_INT bitnum, rtx target,
int unsignedp, bool packedp)
{
- unsigned int total_bits = BITS_PER_WORD;
enum machine_mode mode;
- if (GET_CODE (op0) == SUBREG || REG_P (op0))
- {
- /* Special treatment for a bit field split across two registers. */
- if (bitsize + bitpos > BITS_PER_WORD)
- return extract_split_bit_field (op0, bitsize, bitpos, unsignedp);
- }
- else
+ if (MEM_P (op0))
{
/* Get the proper mode to use for this field. We want a mode that
includes the entire field. If such a mode would be larger than
@@ -1767,105 +1722,89 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
mode = tmode;
}
else
- mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT, 0, 0,
+ mode = get_best_mode (bitsize, bitnum, 0, 0,
MEM_ALIGN (op0), word_mode, MEM_VOLATILE_P (op0));
if (mode == VOIDmode)
/* The only way this should occur is if the field spans word
boundaries. */
- return extract_split_bit_field (op0, bitsize,
- bitpos + offset * BITS_PER_UNIT,
- unsignedp);
-
- total_bits = GET_MODE_BITSIZE (mode);
+ return extract_split_bit_field (op0, bitsize, bitnum, unsignedp);
- /* Make sure bitpos is valid for the chosen mode. Adjust BITPOS to
- 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);
- }
+ unsigned int total_bits = GET_MODE_BITSIZE (mode);
+ HOST_WIDE_INT bit_offset = bitnum - bitnum % total_bits;
- /* If we're accessing a volatile MEM, we can't do the next
- alignment step if it results in a multi-word access where we
- otherwise wouldn't have one. So, check for that case
- here. */
+ /* If we're accessing a volatile MEM, we can't apply BIT_OFFSET
+ if it results in a multi-word access where we otherwise wouldn't
+ have one. So, check for that case here. */
if (MEM_P (op0)
&& MEM_VOLATILE_P (op0)
&& flag_strict_volatile_bitfields > 0
- && bitpos + bitsize <= total_bits
- && bitpos + bitsize + (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT > total_bits)
+ && bitnum % BITS_PER_UNIT + bitsize <= total_bits
+ && bitnum % GET_MODE_BITSIZE (mode) + bitsize > total_bits)
{
if (STRICT_ALIGNMENT)
{
static bool informed_about_misalignment = false;
- bool warned;
if (packedp)
{
if (bitsize == total_bits)
- warned = warning_at (input_location, OPT_fstrict_volatile_bitfields,
- "multiple accesses to volatile structure member"
- " because of packed attribute");
+ warning_at (input_location, OPT_fstrict_volatile_bitfields,
+ "multiple accesses to volatile structure"
+ " member because of packed attribute");
else
- warned = warning_at (input_location, OPT_fstrict_volatile_bitfields,
- "multiple accesses to volatile structure bitfield"
- " because of packed attribute");
+ warning_at (input_location, OPT_fstrict_volatile_bitfields,
+ "multiple accesses to volatile structure"
+ " bitfield because of packed attribute");
- return extract_split_bit_field (op0, bitsize,
- bitpos + offset * BITS_PER_UNIT,
+ return extract_split_bit_field (op0, bitsize, bitnum,
unsignedp);
}
if (bitsize == total_bits)
- warned = warning_at (input_location, OPT_fstrict_volatile_bitfields,
- "mis-aligned access used for structure member");
+ warning_at (input_location, OPT_fstrict_volatile_bitfields,
+ "mis-aligned access used for structure member");
else
- warned = warning_at (input_location, OPT_fstrict_volatile_bitfields,
- "mis-aligned access used for structure bitfield");
+ warning_at (input_location, OPT_fstrict_volatile_bitfields,
+ "mis-aligned access used for structure bitfield");
- if (! informed_about_misalignment && warned)
+ if (! informed_about_misalignment)
{
informed_about_misalignment = true;
inform (input_location,
- "when a volatile object spans multiple type-sized locations,"
- " the compiler must choose between using a single mis-aligned access to"
- " preserve the volatility, or using multiple aligned accesses to avoid"
- " runtime faults; this code may fail at runtime if the hardware does"
- " not allow this access");
+ "when a volatile object spans multiple type-sized"
+ " locations, the compiler must choose between using"
+ " a single mis-aligned access to preserve the"
+ " volatility, or using multiple aligned accesses"
+ " to avoid runtime faults; this code may fail at"
+ " runtime if the hardware does not allow this"
+ " access");
}
}
+ bit_offset = bitnum - bitnum % BITS_PER_UNIT;
}
- else
- {
-
- /* 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);
+ op0 = adjust_bitfield_address (op0, mode, bit_offset / BITS_PER_UNIT);
+ bitnum -= bit_offset;
}
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. */
if (BYTES_BIG_ENDIAN)
- /* BITPOS is the distance between our msb and that of OP0.
+ /* BITNUM is the distance between our msb and that of OP0.
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 the field's lsb and that of OP0.
+ /* Now BITNUM is always the distance between the field's lsb and that of OP0.
We have reduced the big-endian case to the little-endian case. */
if (unsignedp)
{
- if (bitpos)
+ if (bitnum)
{
/* If the field does not already start at the lsb,
shift it so it does. */
@@ -1873,7 +1812,7 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
rtx subtarget = (target != 0 && REG_P (target) ? target : 0);
if (tmode != mode)
subtarget = 0;
- op0 = expand_shift (RSHIFT_EXPR, mode, op0, bitpos, subtarget, 1);
+ op0 = expand_shift (RSHIFT_EXPR, mode, op0, bitnum, subtarget, 1);
}
/* Convert the value to the desired mode. */
if (mode != tmode)
@@ -1882,7 +1821,7 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
/* Unless the msb of the field used to be the msb when we shifted,
mask out the upper bits. */
- if (GET_MODE_BITSIZE (mode) != bitpos + bitsize)
+ if (GET_MODE_BITSIZE (mode) != bitnum + bitsize)
return expand_binop (GET_MODE (op0), and_optab, op0,
mask_rtx (GET_MODE (op0), 0, bitsize, 0),
target, 1, OPTAB_LIB_WIDEN);
@@ -1897,7 +1836,7 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
- if (GET_MODE_BITSIZE (mode) >= bitsize + bitpos)
+ if (GET_MODE_BITSIZE (mode) >= bitsize + bitnum)
{
op0 = convert_to_mode (mode, op0, 0);
break;
@@ -1906,9 +1845,9 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
if (mode != tmode)
target = 0;
- if (GET_MODE_BITSIZE (mode) != (bitsize + bitpos))
+ if (GET_MODE_BITSIZE (mode) != (bitsize + bitnum))
{
- int amount = GET_MODE_BITSIZE (mode) - (bitsize + bitpos);
+ int amount = GET_MODE_BITSIZE (mode) - (bitsize + bitnum);
/* Maybe propagate the target for the shift. */
rtx subtarget = (target != 0 && REG_P (target) ? target : 0);
op0 = expand_shift (LSHIFT_EXPR, mode, op0, amount, subtarget, 1);
@@ -2014,11 +1953,9 @@ extract_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
/* Extract the parts in bit-counting order,
whose meaning is determined by BYTES_PER_UNIT.
- OFFSET is in UNITs, and UNIT is in bits.
- extract_fixed_bit_field wants offset in bytes. */
- part = extract_fixed_bit_field (word_mode, word,
- offset * unit / BITS_PER_UNIT,
- thissize, thispos, 0, 1, false);
+ OFFSET is in UNITs, and UNIT is in bits. */
+ part = extract_fixed_bit_field (word_mode, word, thissize,
+ offset * unit + thispos, 0, 1, false);
bitsdone += thissize;
/* Shift this part into place for the result. */