expr.c (get_inner_reference): Do computation of bitoffset from offset in a way we...
authorRichard Guenther <rguenther@suse.de>
Fri, 24 Aug 2007 09:41:17 +0000 (09:41 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Fri, 24 Aug 2007 09:41:17 +0000 (09:41 +0000)
2007-08-23  Richard Guenther  <rguenther@suse.de>

* expr.c (get_inner_reference): Do computation of bitoffset
from offset in a way we can detect overflow reliably.

From-SVN: r127762

gcc/ChangeLog
gcc/expr.c

index f10d68b2527fe826b94e1f520d6afbadc12ddaa1..adca8881442c2c763dcdd25dba6e1a4b83ddc8af 100644 (file)
@@ -1,3 +1,8 @@
+2007-08-24  Richard Guenther  <rguenther@suse.de>
+
+       * expr.c (get_inner_reference): Do computation of bitoffset
+       from offset in a way we can detect overflow reliably.
+
 2007-08-24  Jie Zhang  <jie.zhang@analog.com>
 
        * crtstuff.c (USE_PT_GNU_EH_FRAME): Don't define for uClibc.
index dc6615abac09d47700ea43c6dca731e2bd76c9ca..a3b8132709f1f47dbf73c567c42ba11fcd49fd98 100644 (file)
@@ -5782,7 +5782,6 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
   enum machine_mode mode = VOIDmode;
   tree offset = size_zero_node;
   tree bit_offset = bitsize_zero_node;
-  tree tem;
 
   /* First get the mode, signedness, and size.  We do this from just the
      outermost expression.  */
@@ -5825,6 +5824,8 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
        *pbitsize = tree_low_cst (size_tree, 1);
     }
 
+  *pmode = mode;
+
   /* Compute cumulative bit-offset for nested component-refs and array-refs,
      and find the ultimate containing object.  */
   while (1)
@@ -5909,18 +5910,25 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
  done:
 
   /* If OFFSET is constant, see if we can return the whole thing as a
-     constant bit position.  Otherwise, split it up.  */
-  if (host_integerp (offset, 0)
-      && 0 != (tem = size_binop (MULT_EXPR,
-                                fold_convert (bitsizetype, offset),
-                                bitsize_unit_node))
-      && 0 != (tem = size_binop (PLUS_EXPR, tem, bit_offset))
-      && host_integerp (tem, 0))
-    *pbitpos = tree_low_cst (tem, 0), *poffset = 0;
-  else
-    *pbitpos = tree_low_cst (bit_offset, 0), *poffset = offset;
+     constant bit position.  Make sure to handle overflow during
+     this conversion.  */
+  if (host_integerp (offset, 0))
+    {
+      double_int tem = double_int_mul (tree_to_double_int (offset),
+                                      uhwi_to_double_int (BITS_PER_UNIT));
+      tem = double_int_add (tem, tree_to_double_int (bit_offset));
+      if (double_int_fits_in_shwi_p (tem))
+       {
+         *pbitpos = double_int_to_shwi (tem);
+         *poffset = NULL_TREE;
+         return exp;
+       }
+    }
+
+  /* Otherwise, split it up.  */
+  *pbitpos = tree_low_cst (bit_offset, 0);
+  *poffset = offset;
 
-  *pmode = mode;
   return exp;
 }