diff mbox

Robustify get_ref_base_and_extent and friend

Message ID 201205301914.02814.ebotcazou@adacore.com
State New
Headers show

Commit Message

Eric Botcazou May 30, 2012, 5:14 p.m. UTC
Hi,

we're having issues with get_ref_base_and_extent overflowing the offset and 
thus returning bogus big negative values on 32-bit hosts.  The attached patch 
converts it to double ints like get_inner_reference.  It also contains a small 
fix for build_user_friendly_ref_for_offset that can stop if a field has again 
too big an offset.

Tested on x86_64-suse-linux and i586-suse-linux, OK for mainline?


2012-05-30  Eric Botcazou  <ebotcazou@adacore.com>

	* tree-dfa.c (get_ref_base_and_extent): Compute the offset using
	double ints throughout.
	* tree-sra.c (build_user_friendly_ref_for_offset) <RECORD_TYPE>:
	Check that the position of the field is representable as an integer.

Comments

Richard Biener May 31, 2012, 9 a.m. UTC | #1
On Wed, May 30, 2012 at 7:14 PM, Eric Botcazou <ebotcazou@adacore.com> wrote:
> Hi,
>
> we're having issues with get_ref_base_and_extent overflowing the offset and
> thus returning bogus big negative values on 32-bit hosts.  The attached patch
> converts it to double ints like get_inner_reference.  It also contains a small
> fix for build_user_friendly_ref_for_offset that can stop if a field has again
> too big an offset.
>
> Tested on x86_64-suse-linux and i586-suse-linux, OK for mainline?

Heh, I think I have a similar patch for the get_ref_base_and_extent issue
in my dev tree for almost three years ...

Ok!

Thanks,
Richard.

>
> 2012-05-30  Eric Botcazou  <ebotcazou@adacore.com>
>
>        * tree-dfa.c (get_ref_base_and_extent): Compute the offset using
>        double ints throughout.
>        * tree-sra.c (build_user_friendly_ref_for_offset) <RECORD_TYPE>:
>        Check that the position of the field is representable as an integer.
>
>
> --
> Eric Botcazou
diff mbox

Patch

Index: tree-dfa.c
===================================================================
--- tree-dfa.c	(revision 187922)
+++ tree-dfa.c	(working copy)
@@ -614,7 +614,8 @@  get_ref_base_and_extent (tree exp, HOST_
   HOST_WIDE_INT bitsize = -1;
   HOST_WIDE_INT maxsize = -1;
   tree size_tree = NULL_TREE;
-  HOST_WIDE_INT bit_offset = 0;
+  double_int bit_offset = double_int_zero;
+  HOST_WIDE_INT hbit_offset;
   bool seen_variable_array_ref = false;
   tree base_type;
 
@@ -652,7 +653,9 @@  get_ref_base_and_extent (tree exp, HOST_
       switch (TREE_CODE (exp))
 	{
 	case BIT_FIELD_REF:
-	  bit_offset += TREE_INT_CST_LOW (TREE_OPERAND (exp, 2));
+	  bit_offset
+	    = double_int_add (bit_offset,
+			      tree_to_double_int (TREE_OPERAND (exp, 2)));
 	  break;
 
 	case COMPONENT_REF:
@@ -660,22 +663,23 @@  get_ref_base_and_extent (tree exp, HOST_
 	    tree field = TREE_OPERAND (exp, 1);
 	    tree this_offset = component_ref_field_offset (exp);
 
-	    if (this_offset
-		&& TREE_CODE (this_offset) == INTEGER_CST
-		&& host_integerp (this_offset, 0))
+	    if (this_offset && TREE_CODE (this_offset) == INTEGER_CST)
 	      {
-		HOST_WIDE_INT hthis_offset = TREE_INT_CST_LOW (this_offset);
-		hthis_offset *= BITS_PER_UNIT;
-		hthis_offset
-		  += TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field));
-		bit_offset += hthis_offset;
+		double_int doffset = tree_to_double_int (this_offset);
+		doffset = double_int_lshift (doffset,
+					     BITS_PER_UNIT == 8
+					     ? 3 : exact_log2 (BITS_PER_UNIT),
+					     HOST_BITS_PER_DOUBLE_INT, true);
+		doffset = double_int_add (doffset,
+					  tree_to_double_int
+					  (DECL_FIELD_BIT_OFFSET (field)));
+		bit_offset = double_int_add (bit_offset, doffset);
 
 		/* If we had seen a variable array ref already and we just
 		   referenced the last field of a struct or a union member
 		   then we have to adjust maxsize by the padding at the end
 		   of our field.  */
-		if (seen_variable_array_ref
-		    && maxsize != -1)
+		if (seen_variable_array_ref && maxsize != -1)
 		  {
 		    tree stype = TREE_TYPE (TREE_OPERAND (exp, 0));
 		    tree next = DECL_CHAIN (field);
@@ -687,10 +691,12 @@  get_ref_base_and_extent (tree exp, HOST_
 			tree fsize = DECL_SIZE_UNIT (field);
 			tree ssize = TYPE_SIZE_UNIT (stype);
 			if (host_integerp (fsize, 0)
-			    && host_integerp (ssize, 0))
+			    && host_integerp (ssize, 0)
+			    && double_int_fits_in_shwi_p (doffset))
 			  maxsize += ((TREE_INT_CST_LOW (ssize)
 				       - TREE_INT_CST_LOW (fsize))
-				      * BITS_PER_UNIT - hthis_offset);
+				      * BITS_PER_UNIT
+					- double_int_to_shwi (doffset));
 			else
 			  maxsize = -1;
 		      }
@@ -702,8 +708,12 @@  get_ref_base_and_extent (tree exp, HOST_
 		/* We need to adjust maxsize to the whole structure bitsize.
 		   But we can subtract any constant offset seen so far,
 		   because that would get us out of the structure otherwise.  */
-		if (maxsize != -1 && csize && host_integerp (csize, 1))
-		  maxsize = TREE_INT_CST_LOW (csize) - bit_offset;
+		if (maxsize != -1
+		    && csize
+		    && host_integerp (csize, 1)
+		    && double_int_fits_in_shwi_p (bit_offset))
+		  maxsize = TREE_INT_CST_LOW (csize)
+			    - double_int_to_shwi (bit_offset);
 		else
 		  maxsize = -1;
 	      }
@@ -715,24 +725,26 @@  get_ref_base_and_extent (tree exp, HOST_
 	  {
 	    tree index = TREE_OPERAND (exp, 1);
 	    tree low_bound, unit_size;
-	    double_int doffset;
 
 	    /* If the resulting bit-offset is constant, track it.  */
 	    if (TREE_CODE (index) == INTEGER_CST
 		&& (low_bound = array_ref_low_bound (exp),
  		    TREE_CODE (low_bound) == INTEGER_CST)
 		&& (unit_size = array_ref_element_size (exp),
-		    host_integerp (unit_size, 1))
-		&& (doffset = double_int_sext
-			      (double_int_sub (TREE_INT_CST (index),
-					       TREE_INT_CST (low_bound)),
-			       TYPE_PRECISION (TREE_TYPE (index))),
-		    double_int_fits_in_shwi_p (doffset)))
+		    TREE_CODE (unit_size) == INTEGER_CST))
 	      {
-		HOST_WIDE_INT hoffset = double_int_to_shwi (doffset);
-		hoffset *= TREE_INT_CST_LOW (unit_size);
-		hoffset *= BITS_PER_UNIT;
-		bit_offset += hoffset;
+		double_int doffset
+		  = double_int_sext
+		    (double_int_sub (TREE_INT_CST (index),
+				     TREE_INT_CST (low_bound)),
+		     TYPE_PRECISION (TREE_TYPE (index)));
+		doffset = double_int_mul (doffset,
+					  tree_to_double_int (unit_size));
+		doffset = double_int_lshift (doffset,
+					     BITS_PER_UNIT == 8
+					     ? 3 : exact_log2 (BITS_PER_UNIT),
+					     HOST_BITS_PER_DOUBLE_INT, true);
+		bit_offset = double_int_add (bit_offset, doffset);
 
 		/* An array ref with a constant index up in the structure
 		   hierarchy will constrain the size of any variable array ref
@@ -745,8 +757,12 @@  get_ref_base_and_extent (tree exp, HOST_
 		/* We need to adjust maxsize to the whole array bitsize.
 		   But we can subtract any constant offset seen so far,
 		   because that would get us outside of the array otherwise.  */
-		if (maxsize != -1 && asize && host_integerp (asize, 1))
-		  maxsize = TREE_INT_CST_LOW (asize) - bit_offset;
+		if (maxsize != -1
+		    && asize
+		    && host_integerp (asize, 1)
+		    && double_int_fits_in_shwi_p (bit_offset))
+		  maxsize = TREE_INT_CST_LOW (asize)
+			    - double_int_to_shwi (bit_offset);
 		else
 		  maxsize = -1;
 
@@ -761,7 +777,8 @@  get_ref_base_and_extent (tree exp, HOST_
 	  break;
 
 	case IMAGPART_EXPR:
-	  bit_offset += bitsize;
+	  bit_offset
+	    = double_int_add (bit_offset, uhwi_to_double_int (bitsize));
 	  break;
 
 	case VIEW_CONVERT_EXPR:
@@ -780,10 +797,10 @@  get_ref_base_and_extent (tree exp, HOST_
 					   BITS_PER_UNIT == 8
 					   ? 3 : exact_log2 (BITS_PER_UNIT),
 					   HOST_BITS_PER_DOUBLE_INT, true);
-		  off = double_int_add (off, shwi_to_double_int (bit_offset));
+		  off = double_int_add (off, bit_offset);
 		  if (double_int_fits_in_shwi_p (off))
 		    {
-		      bit_offset = double_int_to_shwi (off);
+		      bit_offset = off;
 		      exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
 		    }
 		}
@@ -799,7 +816,7 @@  get_ref_base_and_extent (tree exp, HOST_
 	      if (TMR_INDEX (exp) || TMR_INDEX2 (exp))
 		{
 		  exp = TREE_OPERAND (TMR_BASE (exp), 0);
-		  bit_offset = 0;
+		  bit_offset = double_int_zero;
 		  maxsize = -1;
 		  goto done;
 		}
@@ -812,10 +829,10 @@  get_ref_base_and_extent (tree exp, HOST_
 					   BITS_PER_UNIT == 8
 					   ? 3 : exact_log2 (BITS_PER_UNIT),
 					   HOST_BITS_PER_DOUBLE_INT, true);
-		  off = double_int_add (off, shwi_to_double_int (bit_offset));
+		  off = double_int_add (off, bit_offset);
 		  if (double_int_fits_in_shwi_p (off))
 		    {
-		      bit_offset = double_int_to_shwi (off);
+		      bit_offset = off;
 		      exp = TREE_OPERAND (TMR_BASE (exp), 0);
 		    }
 		}
@@ -830,6 +847,17 @@  get_ref_base_and_extent (tree exp, HOST_
     }
  done:
 
+  if (!double_int_fits_in_shwi_p (bit_offset))
+    {
+      *poffset = 0;
+      *psize = bitsize;
+      *pmax_size = -1;
+
+      return exp;
+    }
+
+  hbit_offset = double_int_to_shwi (bit_offset);
+
   /* We need to deal with variable arrays ending structures such as
        struct { int length; int a[1]; } x;           x.a[d]
        struct { struct { int a; int b; } a[1]; } x;  x.a[d].a
@@ -844,7 +872,7 @@  get_ref_base_and_extent (tree exp, HOST_
   if (seen_variable_array_ref
       && maxsize != -1
       && (!host_integerp (TYPE_SIZE (base_type), 1)
-	  || (bit_offset + maxsize
+	  || (hbit_offset + maxsize
 	      == (signed) TREE_INT_CST_LOW (TYPE_SIZE (base_type)))))
     maxsize = -1;
 
@@ -856,7 +884,7 @@  get_ref_base_and_extent (tree exp, HOST_
          base decl.  */
       if (maxsize == -1
 	  && host_integerp (DECL_SIZE (exp), 1))
-	maxsize = TREE_INT_CST_LOW (DECL_SIZE (exp)) - bit_offset;
+	maxsize = TREE_INT_CST_LOW (DECL_SIZE (exp)) - hbit_offset;
     }
   else if (CONSTANT_CLASS_P (exp))
     {
@@ -864,13 +892,13 @@  get_ref_base_and_extent (tree exp, HOST_
          base type constant.  */
       if (maxsize == -1
 	  && host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1))
-	maxsize = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp))) - bit_offset;
+	maxsize = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp))) - hbit_offset;
     }
 
   /* ???  Due to negative offsets in ARRAY_REF we can end up with
      negative bit_offset here.  We might want to store a zero offset
      in this case.  */
-  *poffset = bit_offset;
+  *poffset = hbit_offset;
   *psize = bitsize;
   *pmax_size = maxsize;
 
Index: tree-sra.c
===================================================================
--- tree-sra.c	(revision 187922)
+++ tree-sra.c	(working copy)
@@ -1549,17 +1549,20 @@  build_user_friendly_ref_for_offset (tree
 	  for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
 	    {
 	      HOST_WIDE_INT pos, size;
-	      tree expr, *expr_ptr;
+	      tree tr_pos, expr, *expr_ptr;
 
 	      if (TREE_CODE (fld) != FIELD_DECL)
 		continue;
 
-	      pos = int_bit_position (fld);
+	      tr_pos = bit_position (fld);
+	      if (!tr_pos || !host_integerp (tr_pos, 1))
+		continue;
+	      pos = TREE_INT_CST_LOW (tr_pos);
 	      gcc_assert (TREE_CODE (type) == RECORD_TYPE || pos == 0);
 	      tr_size = DECL_SIZE (fld);
 	      if (!tr_size || !host_integerp (tr_size, 1))
 		continue;
-	      size = tree_low_cst (tr_size, 1);
+	      size = TREE_INT_CST_LOW (tr_size);
 	      if (size == 0)
 		{
 		  if (pos != offset)