re PR tree-optimization/31715 (Array calculation done incorrectly)
authorRichard Guenther <rguenther@suse.de>
Fri, 27 Apr 2007 11:42:43 +0000 (11:42 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Fri, 27 Apr 2007 11:42:43 +0000 (11:42 +0000)
2007-04-27  Richard Guenther  <rguenther@suse.de>

PR tree-optimization/31715
* tree-ssa-ccp.c (maybe_fold_offset_to_array_ref): Make
sure to do computation on the offset in an appropriate
signed type.

* gcc.dg/Warray-bounds-4.c: New testcase.

From-SVN: r124216

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/Warray-bounds-4.c [new file with mode: 0644]
gcc/tree-ssa-ccp.c

index d56233977f6dda76728580387aad30fea9a648b7..0e4f987319076c767004e80f1fa31deb858696f9 100644 (file)
@@ -1,3 +1,10 @@
+2007-04-27  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/31715
+       * tree-ssa-ccp.c (maybe_fold_offset_to_array_ref): Make
+       sure to do computation on the offset in an appropriate
+       signed type.
+
 2007-04-27  Richard Sandiford  <richard@codesourcery.com>
 
        * reload.h (elimination_target_reg_p): Declare.
index 40c811bb7aa4b62a71f01ee077700834d0e73fe8..c9e601eb57d9bcd0522f96c930e1f29bae47de76 100644 (file)
@@ -1,3 +1,8 @@
+2007-04-27  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/31715
+       * gcc.dg/Warray-bounds-4.c: New testcase.
+
 2007-04-26  Ian Lance Taylor  <iant@google.com>
 
        PR target/28675
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-4.c b/gcc/testsuite/gcc.dg/Warray-bounds-4.c
new file mode 100644 (file)
index 0000000..71526f2
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wall" } */
+
+typedef unsigned int DWORD;
+
+static void g(DWORD * p, int n)
+{
+        int i;
+
+        for (i = 0; i < n && !p[n - 1]; i++);  /* { dg-bogus "subscript is above array bounds" } */
+}
+
+void f() {
+        DWORD arr[8];
+
+        g(arr, 4);
+}
index 530dee01a094db4d69d3af0f47647b90f328dcc4..9c9d847eed6f1b79c4675f54ecf092eaf9d22be8 100644 (file)
@@ -1550,7 +1550,7 @@ widen_bitfield (tree val, tree field, tree var)
 static tree
 maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type)
 {
-  tree min_idx, idx, elt_offset = integer_zero_node;
+  tree min_idx, idx, idx_type, elt_offset = integer_zero_node;
   tree array_type, elt_type, elt_size;
 
   /* If BASE is an ARRAY_REF, we can pick up another offset (this time
@@ -1578,7 +1578,10 @@ maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type)
   elt_type = TREE_TYPE (array_type);
   if (!lang_hooks.types_compatible_p (orig_type, elt_type))
     return NULL_TREE;
-       
+
+  /* Use signed size type for intermediate computation on the index.  */
+  idx_type = signed_type_for (size_type_node);
+
   /* If OFFSET and ELT_OFFSET are zero, we don't care about the size of the
      element type (so we can use the alignment if it's not constant).
      Otherwise, compute the offset as an index by using a division.  If the
@@ -1589,42 +1592,47 @@ maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type)
       if (TREE_CODE (elt_size) != INTEGER_CST)
        elt_size = size_int (TYPE_ALIGN (elt_type));
 
-      idx = integer_zero_node;
+      idx = build_int_cst (idx_type, 0);
     }
   else
     {
       unsigned HOST_WIDE_INT lquo, lrem;
       HOST_WIDE_INT hquo, hrem;
+      double_int soffset;
 
+      /* The final array offset should be signed, so we need
+        to sign-extend the (possibly pointer) offset here
+        and use signed division.  */
+      soffset = double_int_sext (tree_to_double_int (offset),
+                                TYPE_PRECISION (TREE_TYPE (offset)));
       if (TREE_CODE (elt_size) != INTEGER_CST
-         || div_and_round_double (TRUNC_DIV_EXPR, 1,
-                                  TREE_INT_CST_LOW (offset),
-                                  TREE_INT_CST_HIGH (offset),
+         || div_and_round_double (TRUNC_DIV_EXPR, 0,
+                                  soffset.low, soffset.high,
                                   TREE_INT_CST_LOW (elt_size),
                                   TREE_INT_CST_HIGH (elt_size),
                                   &lquo, &hquo, &lrem, &hrem)
          || lrem || hrem)
        return NULL_TREE;
 
-      idx = build_int_cst_wide (TREE_TYPE (offset), lquo, hquo);
+      idx = build_int_cst_wide (idx_type, lquo, hquo);
     }
 
   /* Assume the low bound is zero.  If there is a domain type, get the
      low bound, if any, convert the index into that type, and add the
      low bound.  */
-  min_idx = integer_zero_node;
+  min_idx = build_int_cst (idx_type, 0);
   if (TYPE_DOMAIN (array_type))
     {
-      if (TYPE_MIN_VALUE (TYPE_DOMAIN (array_type)))
-       min_idx = TYPE_MIN_VALUE (TYPE_DOMAIN (array_type));
+      idx_type = TYPE_DOMAIN (array_type);
+      if (TYPE_MIN_VALUE (idx_type))
+       min_idx = TYPE_MIN_VALUE (idx_type);
       else
-       min_idx = fold_convert (TYPE_DOMAIN (array_type), min_idx);
+       min_idx = fold_convert (idx_type, min_idx);
 
       if (TREE_CODE (min_idx) != INTEGER_CST)
        return NULL_TREE;
 
-      idx = fold_convert (TYPE_DOMAIN (array_type), idx);
-      elt_offset = fold_convert (TYPE_DOMAIN (array_type), elt_offset);
+      elt_offset = fold_convert (idx_type, elt_offset);
     }
 
   if (!integer_zerop (min_idx))
@@ -1632,6 +1640,9 @@ maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type)
   if (!integer_zerop (elt_offset))
     idx = int_const_binop (PLUS_EXPR, idx, elt_offset, 0);
 
+  /* Make sure to possibly truncate late after offsetting.  */
+  idx = fold_convert (idx_type, idx);
+
   return build4 (ARRAY_REF, orig_type, base, idx, NULL_TREE, NULL_TREE);
 }