===================================================================
@@ -4705,6 +4705,17 @@ expand_assignment (tree to, tree from, b
to_rtx = adjust_address (to_rtx, mode1, 0);
else if (GET_MODE (to_rtx) == VOIDmode)
to_rtx = adjust_address (to_rtx, BLKmode, 0);
+ else if (mode1 == VOIDmode
+ && MEM_SIZE_KNOWN_P (to_rtx))
+ {
+ mode1 = mode_for_size ((MEM_SIZE (to_rtx) & -MEM_SIZE (to_rtx))
+ * BITS_PER_UNIT, MODE_INT, 0);
+ if (mode1 == BLKmode
+ || GET_MODE_SIZE (mode1) > GET_MODE_SIZE (word_mode)
+ || (GET_MODE_SIZE (mode1)
+ < GET_MODE_SIZE (DECL_MODE (TREE_OPERAND (to, 1)))))
+ mode1 = VOIDmode;
+ }
}
if (offset != 0)
===================================================================
@@ -50,7 +50,7 @@ static void store_fixed_bit_field (rtx,
unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT,
- rtx);
+ rtx, enum machine_mode);
static void store_split_bit_field (rtx, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT,
@@ -632,6 +632,8 @@ store_bit_field_1 (rtx str_rtx, unsigned
&& GET_MODE (value) != BLKmode
&& bitsize > 0
&& GET_MODE_BITSIZE (op_mode) >= bitsize
+ && (fieldmode == VOIDmode
+ || GET_MODE_BITSIZE (fieldmode) >= GET_MODE_BITSIZE (op_mode))
/* Do not use insv for volatile bitfields when
-fstrict-volatile-bitfields is in effect. */
&& !(MEM_P (op0) && MEM_VOLATILE_P (op0)
@@ -761,7 +763,10 @@ store_bit_field_1 (rtx str_rtx, unsigned
bitregion_start, bitregion_end,
MEM_ALIGN (op0),
(op_mode == MAX_MACHINE_MODE
- ? VOIDmode : op_mode),
+ || (fieldmode != VOIDmode
+ && (GET_MODE_SIZE (fieldmode)
+ > GET_MODE_SIZE (op_mode))))
+ ? fieldmode : op_mode,
MEM_VOLATILE_P (op0));
else
bestmode = GET_MODE (op0);
@@ -802,7 +807,8 @@ store_bit_field_1 (rtx str_rtx, unsigned
return false;
store_fixed_bit_field (op0, offset, bitsize, bitpos,
- bitregion_start, bitregion_end, value);
+ bitregion_start, bitregion_end, value,
+ fieldmode);
return true;
}
@@ -872,7 +878,7 @@ store_fixed_bit_field (rtx op0, unsigned
unsigned HOST_WIDE_INT bitpos,
unsigned HOST_WIDE_INT bitregion_start,
unsigned HOST_WIDE_INT bitregion_end,
- rtx value)
+ rtx value, enum machine_mode wmode)
{
enum machine_mode mode;
unsigned int total_bits = BITS_PER_WORD;
@@ -911,10 +917,13 @@ store_fixed_bit_field (rtx op0, unsigned
a word, we won't be doing the extraction the normal way.
We don't want a mode bigger than the destination. */
+ if (wmode == VOIDmode)
+ wmode = word_mode;
+
mode = GET_MODE (op0);
if (GET_MODE_BITSIZE (mode) == 0
- || GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (word_mode))
- mode = word_mode;
+ || GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (wmode))
+ mode = wmode;
if (MEM_VOLATILE_P (op0)
&& GET_MODE_BITSIZE (GET_MODE (op0)) > 0
@@ -1169,7 +1178,8 @@ store_split_bit_field (rtx op0, unsigned
it is just an out-of-bounds access. Ignore it. */
if (word != const0_rtx)
store_fixed_bit_field (word, offset * unit / BITS_PER_UNIT, thissize,
- thispos, bitregion_start, bitregion_end, part);
+ thispos, bitregion_start, bitregion_end, part,
+ word_mode);
bitsdone += thissize;
}
}
===================================================================
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-options "-fno-toplevel-reorder" } */
+
+extern void abort (void);
+
+struct S
+{
+ signed a : 26;
+ signed b : 16;
+ signed c : 10;
+ volatile signed d : 14;
+};
+
+static struct S e = { 0, 0, 0, 1 };
+static int f = 1;
+
+void __attribute__((noinline))
+foo (void)
+{
+ e.d = 0;
+ f = 2;
+}
+
+int
+main ()
+{
+ if (e.a || e.b || e.c || e.d != 1 || f != 1)
+ abort ();
+ foo ();
+ if (e.a || e.b || e.c || e.d || f != 2)
+ abort ();
+ return 0;
+}
===================================================================
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+
+extern void abort (void);
+
+static volatile struct S0 {
+ short f3[9];
+ unsigned f8 : 15;
+} s = {1};
+static unsigned short sh = 0x1234;
+
+struct S0 a, b;
+int vi = 0;
+
+void func_4()
+{
+ s.f8 |= 1;
+ sh = 15;
+ if (vi) a = b;
+}
+
+int main()
+{
+ func_4();
+ if (sh != 15)
+ abort ();
+ return 0;
+}
===================================================================
@@ -0,0 +1,32 @@
+/* { dg-do run } */
+
+extern void abort (void);
+struct S1
+{
+ int f0;
+ int:1;
+ int f3;
+ int:1;
+ int:0;
+ int f6:1;
+};
+int g_13 = 1;
+volatile struct S1 g_118 = {
+ 1
+};
+
+void __attribute__((noinline))
+func_46 ()
+{
+ for (g_13 = 0; g_13 >= 0; g_13 -= 1)
+ g_118.f6 = 0;
+}
+
+int
+main ()
+{
+ func_46 ();
+ if (g_13 != -1)
+ abort ();
+ return 0;
+}
===================================================================
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+
+extern void abort (void);
+struct S1 {
+ unsigned f0, f1;
+ unsigned short f2, f3;
+ unsigned f4 : 16;
+ unsigned f5, f6;
+ volatile unsigned f7 : 28;
+};
+static struct S1 g_76;
+static struct S1 g_245 = {0,0,0,0,0,0,0,1};
+static signed char g_323 = 0x80;
+static void func_1(void)
+{
+ g_245.f7 &= 1;
+ for (g_323 = 0; g_323 <= -1; g_323 -= 2) {
+ g_76 = g_76;
+ g_76.f4 ^= 11;
+ }
+}
+int main()
+{
+ func_1();
+ if (g_323 != 0 || g_245.f7 != 1)
+ abort ();
+ return 0;
+}