aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2012-04-25 16:27:08 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2012-04-25 16:27:08 +0200
commitf1cc958978c4b3a76ccf96571972f95963c9f0ea (patch)
tree81ecc613d94b359b676a0ac3492e351643109575
parent948e73b3d6a3d10ada7c0240bfbfa4aef147f59d (diff)
downloadgcc-f1cc958978c4b3a76ccf96571972f95963c9f0ea.zip
gcc-f1cc958978c4b3a76ccf96571972f95963c9f0ea.tar.gz
gcc-f1cc958978c4b3a76ccf96571972f95963c9f0ea.tar.bz2
re PR tree-optimization/52979 (likely wrong code bug w/packed bitfields)
PR middle-end/52979 * stor-layout.c (get_best_mode): Don't return mode with bitsize larger than maxbits. Don't compute maxbits modulo align. Also check that unit bytes long store at bitpos / unit * unit doesn't affect bits beyond bitregion_end. * expmed.c (store_bit_field_1): Avoid trying insv if OP_MODE MEM would not fit into bitregion_start ... bitregion_end + 1 bit region. (store_split_bit_field): Decrease unit close to end of bitregion_end if access is restricted in order to avoid mutual recursion. * gcc.c-torture/compile/pr52979-1.c: New test. * gcc.c-torture/execute/pr52979-1.c: New test. * gcc.c-torture/execute/pr52979-2.c: New test. From-SVN: r186819
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/expmed.c20
-rw-r--r--gcc/stor-layout.c11
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/pr52979-1.c15
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr52979-1.c40
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr52979-2.c40
7 files changed, 139 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 9edaf93..d5154ec 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,16 @@
2012-04-25 Jakub Jelinek <jakub@redhat.com>
+ PR middle-end/52979
+ * stor-layout.c (get_best_mode): Don't return mode with bitsize
+ larger than maxbits. Don't compute maxbits modulo align.
+ Also check that unit bytes long store at bitpos / unit * unit
+ doesn't affect bits beyond bitregion_end.
+ * expmed.c (store_bit_field_1): Avoid trying insv if OP_MODE MEM
+ would not fit into bitregion_start ... bitregion_end + 1 bit
+ region.
+ (store_split_bit_field): Decrease unit close to end of bitregion_end
+ if access is restricted in order to avoid mutual recursion.
+
PR tree-optimization/53058
* double-int.h (double_int_max_value, double_int_min_value): New
prototypes.
diff --git a/gcc/expmed.c b/gcc/expmed.c
index aa24fbf..a0a0960 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -640,7 +640,13 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
&& !(MEM_P (op0) && MEM_VOLATILE_P (op0)
&& flag_strict_volatile_bitfields > 0)
&& ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
- && (bitsize + bitpos > GET_MODE_BITSIZE (op_mode))))
+ && (bitsize + bitpos > GET_MODE_BITSIZE (op_mode)))
+ /* Do not use insv if the bit region is restricted and
+ op_mode integer at offset doesn't fit into the
+ restricted region. */
+ && !(MEM_P (op0) && bitregion_end
+ && bitnum - bitpos + GET_MODE_BITSIZE (op_mode)
+ > bitregion_end + 1))
{
struct expand_operand ops[4];
int xbitpos = bitpos;
@@ -760,7 +766,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
|| GET_MODE_BITSIZE (GET_MODE (op0)) > maxbits
|| (op_mode != MAX_MACHINE_MODE
&& GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (op_mode)))
- bestmode = get_best_mode (bitsize, bitnum,
+ bestmode = get_best_mode (bitsize, bitnum,
bitregion_start, bitregion_end,
MEM_ALIGN (op0),
(op_mode == MAX_MACHINE_MODE
@@ -1096,6 +1102,16 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
offset = (bitpos + bitsdone) / unit;
thispos = (bitpos + bitsdone) % unit;
+ /* When region of bytes we can touch is restricted, decrease
+ UNIT close to the end of the region as needed. */
+ if (bitregion_end
+ && unit > BITS_PER_UNIT
+ && bitpos + bitsdone - thispos + unit > bitregion_end + 1)
+ {
+ unit = unit / 2;
+ continue;
+ }
+
/* THISSIZE must not overrun a word boundary. Otherwise,
store_fixed_bit_field will call us again, and we will mutually
recurse forever. */
diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
index d79be14..e72e7f3 100644
--- a/gcc/stor-layout.c
+++ b/gcc/stor-layout.c
@@ -2624,7 +2624,7 @@ get_best_mode (int bitsize, int bitpos,
if (!bitregion_end)
maxbits = MAX_FIXED_MODE_SIZE;
else
- maxbits = (bitregion_end - bitregion_start) % align + 1;
+ maxbits = bitregion_end - bitregion_start + 1;
/* Find the narrowest integer mode that contains the bit field. */
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
@@ -2645,7 +2645,10 @@ get_best_mode (int bitsize, int bitpos,
(Though at least one Unix compiler ignores this problem:
that on the Sequent 386 machine. */
|| MIN (unit, BIGGEST_ALIGNMENT) > align
- || (largest_mode != VOIDmode && unit > GET_MODE_BITSIZE (largest_mode)))
+ || (largest_mode != VOIDmode && unit > GET_MODE_BITSIZE (largest_mode))
+ || unit > maxbits
+ || (bitregion_end
+ && bitpos - (bitpos % unit) + unit > bitregion_end + 1))
return VOIDmode;
if ((SLOW_BYTE_ACCESS && ! volatilep)
@@ -2663,7 +2666,9 @@ get_best_mode (int bitsize, int bitpos,
&& unit <= MIN (align, BIGGEST_ALIGNMENT)
&& unit <= maxbits
&& (largest_mode == VOIDmode
- || unit <= GET_MODE_BITSIZE (largest_mode)))
+ || unit <= GET_MODE_BITSIZE (largest_mode))
+ && (bitregion_end == 0
+ || bitpos - (bitpos % unit) + unit <= bitregion_end + 1))
wide_mode = tmode;
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d479cd6..b7fe632 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2012-04-25 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/52979
+ * gcc.c-torture/compile/pr52979-1.c: New test.
+ * gcc.c-torture/execute/pr52979-1.c: New test.
+ * gcc.c-torture/execute/pr52979-2.c: New test.
+
2012-04-25 Richard Guenther <rguenther@suse.de>
* gcc.target/i386/l_fma_float_5.c: Adjust.
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr52979-1.c b/gcc/testsuite/gcc.c-torture/compile/pr52979-1.c
new file mode 100644
index 0000000..c703073
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr52979-1.c
@@ -0,0 +1,15 @@
+/* PR middle-end/52979 */
+
+struct S
+{
+ unsigned int a : 16, b : 16, c : 16, d : 16, e : 14;
+ unsigned int f : 4, g : 14, h : 8;
+ char i;
+ int j;
+};
+
+void
+foo (struct S *s)
+{
+ s->f = 1;
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr52979-1.c b/gcc/testsuite/gcc.c-torture/execute/pr52979-1.c
new file mode 100644
index 0000000..246b1fd
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr52979-1.c
@@ -0,0 +1,40 @@
+/* PR middle-end/52979 */
+
+extern void abort (void);
+int c, d, e;
+
+void
+foo (void)
+{
+}
+
+struct __attribute__((packed)) S { int g : 31; int h : 6; };
+struct S a = { 1 };
+static struct S b = { 1 };
+
+void
+bar (void)
+{
+ a.h = 1;
+ struct S f = { };
+ b = f;
+ e = 0;
+ if (d)
+ c = a.g;
+}
+
+void
+baz (void)
+{
+ bar ();
+ a = b;
+}
+
+int
+main ()
+{
+ baz ();
+ if (a.g)
+ abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr52979-2.c b/gcc/testsuite/gcc.c-torture/execute/pr52979-2.c
new file mode 100644
index 0000000..52f5bb8
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr52979-2.c
@@ -0,0 +1,40 @@
+/* PR middle-end/52979 */
+
+extern void abort (void);
+int c, d, e;
+
+void
+foo (void)
+{
+}
+
+struct __attribute__((packed)) S { int g : 31; int h : 6; };
+static struct S b = { 1 };
+struct S a = { 1 };
+
+void
+bar (void)
+{
+ a.h = 1;
+ struct S f = { };
+ b = f;
+ e = 0;
+ if (d)
+ c = a.g;
+}
+
+void
+baz (void)
+{
+ bar ();
+ a = b;
+}
+
+int
+main ()
+{
+ baz ();
+ if (a.g)
+ abort ();
+ return 0;
+}