A couple days ago I wrote:
While I was grovelling around trying to swap in more state on the
bitfield store/extract code for the patch rewrite being discussed here:
http://gcc.gnu.org/ml/gcc-patches/2012-08/msg01546.html
I found a reference to PR23623 and found that it is broken again, but in
a different way. On ARM EABI, the attached test case correctly does
32-bit reads for the volatile int bit-field with
-fstrict-volatile-bitfields, but incorrectly does 8-bit writes. I
thought I should try to track this down and fix it first, as part of
making the bit-field read/extract code more consistent with each other,
before trying to figure out a new place to hook in the packedp attribute
stuff. The patch I previously submitted does not fix the behavior of
this test case for writing, nor does reverting the older patch that
added the packedp attribute for reading break that case.
After I tweaked a couple other places in store_bit_field_1 to handle
-fstrict-volatile-bitfields consistently with extract_bit_field_1, I've
gotten it into store_fixed_bit_field, to parallel the read case where it
is getting into extract_fixed_bit_field. But there it's failing to reach
the special case for using the declared mode of the field with
-fstrict-volatile-bitfields because it's been passed bitregion_start = 0
and bitregion_end = 7 so it thinks it must not write more than 8 bits no
matter what. Those values are coming in from expand_assignment, which is
in turn getting them from get_bit_range.
To be more specific, here is a work-in-progress patch that takes a
brute-force approach by making store_fixed_bit_field ignore the provided
bit region in the strict volatile bitfield case; it also has the other
fixes to make the bitfield store control flow match that for extract.
This fixes the previously-failing test case and regression tests OK on
arm-none-eabi, but I haven't tried it on any other target yet. Is this
a reasonable way to resolve this conflict, or should something farther
up the call chain take care of it?
-Sandra
2012-08-26 Sandra Loosemore <san...@codesourcery.com>
gcc/
* expmed.c (store_bit_field_1): Make handling of strict
volatile bitfields parallel that for extraction.
(store_fixed_bit_field): Ignore bitregion for strict volatile
bitfields.
(extract_bit_field_1): Make test for strict volatile bitfields
explicit.
Index: gcc/expmed.c
===================================================================
--- gcc/expmed.c (revision 190623)
+++ gcc/expmed.c (working copy)
@@ -475,6 +475,19 @@ store_bit_field_1 (rtx str_rtx, unsigned
return true;
}
+ offset = bitnum / unit;
+ bitpos = bitnum % unit;
+ byte_offset = (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
+ + (offset * UNITS_PER_WORD);
+
+ /* If the bitfield is volatile, we need to make sure the access
+ remains on a type-aligned boundary. */
+ if (GET_CODE (op0) == MEM
+ && MEM_VOLATILE_P (op0)
+ && GET_MODE_BITSIZE (GET_MODE (op0)) > 0
+ && flag_strict_volatile_bitfields > 0)
+ goto no_subreg_mode_swap;
+
/* 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.
@@ -482,11 +495,6 @@ store_bit_field_1 (rtx str_rtx, unsigned
done with a simple store. For targets that support fast unaligned
memory, any naturally sized, unit aligned field can be done directly. */
- offset = bitnum / unit;
- bitpos = bitnum % unit;
- byte_offset = (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
- + (offset * UNITS_PER_WORD);
-
if (bitpos == 0
&& bitsize == GET_MODE_BITSIZE (fieldmode)
&& (!MEM_P (op0)
@@ -581,6 +589,7 @@ store_bit_field_1 (rtx str_rtx, unsigned
return true;
}
}
+ no_subreg_mode_swap:
/* Handle fields bigger than a word. */
@@ -809,8 +818,11 @@ store_bit_field_1 (rtx str_rtx, unsigned
}
/* If OP0 is a memory, try copying it to a register and seeing if a
- cheap register alternative is available. */
- if (HAVE_insv && MEM_P (op0))
+ cheap register alternative is available.
+ Do not try this optimization for volatile bitfields if
+ -fstrict-volatile-bitfields is in effect. */
+ if (HAVE_insv && MEM_P (op0)
+ && !(MEM_VOLATILE_P (op0) && flag_strict_volatile_bitfields > 0))
{
enum machine_mode bestmode;
unsigned HOST_WIDE_INT maxbits = MAX_FIXED_MODE_SIZE;
@@ -988,8 +1000,6 @@ store_fixed_bit_field (rtx op0, unsigned
mode = word_mode;
if (MEM_VOLATILE_P (op0)
- && GET_MODE_BITSIZE (GET_MODE (op0)) > 0
- && GET_MODE_BITSIZE (GET_MODE (op0)) <= maxbits
&& flag_strict_volatile_bitfields > 0)
mode = GET_MODE (op0);
else
@@ -1683,8 +1693,11 @@ extract_bit_field_1 (rtx str_rtx, unsign
}
/* If OP0 is a memory, try copying it to a register and seeing if a
- cheap register alternative is available. */
- if (ext_mode != MAX_MACHINE_MODE && MEM_P (op0))
+ cheap register alternative is available.
+ Do not try this optimization for volatile bitfields if
+ -fstrict-volatile-bitfields is in effect. */
+ if (ext_mode != MAX_MACHINE_MODE && MEM_P (op0)
+ && !(MEM_VOLATILE_P (op0) && flag_strict_volatile_bitfields > 0))
{
enum machine_mode bestmode;