diff mbox

Fix get_bit_range and expand_assignment for negative bitpos (PR middle-end/58970)

Message ID 20131105080148.GE27813@tucnak.zalov.cz
State New
Headers show

Commit Message

Jakub Jelinek Nov. 5, 2013, 8:01 a.m. UTC
Hi!

This is an updated version of the get_bit_range fix, this time it
ensures that bitpos is not negative already right after the
get_inner_reference call, because various parts of the expansion might be
confused by the negative values.  As the second testcase shows, even with
non-negative bitpos we can still end up with bitoffset > *bitpos when *offset
is NULL, so get_bit_range handles that too.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk (and
after a while 4.8)?

2013-11-05  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/58970
	* expr.c (get_bit_range): Handle *offset == NULL_TREE.
	(expand_assignment): If *bitpos is negative, set *offset
	and adjust *bitpos, so that it is not negative.

	* gcc.c-torture/compile/pr58970-1.c: New test.
	* gcc.c-torture/compile/pr58970-2.c: New test.


	Jakub

Comments

Jeff Law Nov. 5, 2013, 7:55 p.m. UTC | #1
On 11/05/13 01:01, Jakub Jelinek wrote:
> Hi!
>
> This is an updated version of the get_bit_range fix, this time it
> ensures that bitpos is not negative already right after the
> get_inner_reference call, because various parts of the expansion might be
> confused by the negative values.  As the second testcase shows, even with
> non-negative bitpos we can still end up with bitoffset > *bitpos when *offset
> is NULL, so get_bit_range handles that too.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk (and
> after a while 4.8)?
>
> 2013-11-05  Jakub Jelinek  <jakub@redhat.com>
>
> 	PR middle-end/58970
> 	* expr.c (get_bit_range): Handle *offset == NULL_TREE.
> 	(expand_assignment): If *bitpos is negative, set *offset
> 	and adjust *bitpos, so that it is not negative.
>
> 	* gcc.c-torture/compile/pr58970-1.c: New test.
> 	* gcc.c-torture/compile/pr58970-2.c: New test.
OK for the trunk.  Your call if/when for the 4.8 branch.

jeff
diff mbox

Patch

--- gcc/expr.c.jj	2013-11-04 11:27:35.769278058 +0100
+++ gcc/expr.c	2013-11-04 21:40:54.283437813 +0100
@@ -4574,19 +4574,19 @@  get_bit_range (unsigned HOST_WIDE_INT *b
 		- tree_low_cst (DECL_FIELD_BIT_OFFSET (repr), 1));
 
   /* If the adjustment is larger than bitpos, we would have a negative bit
-     position for the lower bound and this may wreak havoc later.  This can
-     occur only if we have a non-null offset, so adjust offset and bitpos
-     to make the lower bound non-negative.  */
+     position for the lower bound and this may wreak havoc later.  Adjust
+     offset and bitpos to make the lower bound non-negative in that case.  */
   if (bitoffset > *bitpos)
     {
       HOST_WIDE_INT adjust = bitoffset - *bitpos;
-
       gcc_assert ((adjust % BITS_PER_UNIT) == 0);
-      gcc_assert (*offset != NULL_TREE);
 
       *bitpos += adjust;
-      *offset
-	= size_binop (MINUS_EXPR, *offset, size_int (adjust / BITS_PER_UNIT));
+      if (*offset == NULL_TREE)
+	*offset = size_int (-adjust / BITS_PER_UNIT);
+      else
+	*offset
+	  = size_binop (MINUS_EXPR, *offset, size_int (adjust / BITS_PER_UNIT));
       *bitstart = 0;
     }
   else
@@ -4719,6 +4719,15 @@  expand_assignment (tree to, tree from, b
       tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
 				 &unsignedp, &volatilep, true);
 
+      /* Make sure bitpos is not negative, it can wreak havoc later.  */
+      if (bitpos < 0)
+	{
+	  gcc_assert (offset == NULL_TREE);
+	  offset = size_int (bitpos >> (BITS_PER_UNIT == 8
+					? 3 : exact_log2 (BITS_PER_UNIT)));
+	  bitpos &= BITS_PER_UNIT - 1;
+	}
+
       if (TREE_CODE (to) == COMPONENT_REF
 	  && DECL_BIT_FIELD_TYPE (TREE_OPERAND (to, 1)))
 	get_bit_range (&bitregion_start, &bitregion_end, to, &bitpos, &offset);
--- gcc/testsuite/gcc.c-torture/compile/pr58970-1.c.jj	2013-11-04 21:27:47.531590559 +0100
+++ gcc/testsuite/gcc.c-torture/compile/pr58970-1.c	2013-11-04 21:27:47.531590559 +0100
@@ -0,0 +1,11 @@ 
+/* PR middle-end/58970 */
+
+struct T { int b : 1; };
+struct S { struct T t[1]; };
+
+void
+foo (int x, struct S *s)
+{
+  if (x == -1)
+    s->t[x].b = 0;
+}
--- gcc/testsuite/gcc.c-torture/compile/pr58970-2.c.jj	2013-08-25 18:20:55.717911035 +0200
+++ gcc/testsuite/gcc.c-torture/compile/pr58970-2.c	2013-11-04 21:45:41.997935365 +0100
@@ -0,0 +1,11 @@ 
+/* PR middle-end/58970 */
+
+struct T { char a : 8; char b : 1; };
+struct S { char x; struct T t[1]; };
+
+void
+foo (int x, struct S *s)
+{
+  if (x == -1)
+    s->t[x].b = 0;
+}