re PR tree-optimization/51721 (-Warray-bounds false positives and inconsistencies)
[gcc.git] / gcc / tree-vrp.c
index 4a018f73c17555b69ba1e1430d32b2483e39d461..d3922db038a84d0e161a729ec96bd56c754d8b86 100644 (file)
@@ -1,5 +1,5 @@
 /* Support routines for Value Range Propagation (VRP).
-   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
+   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
    Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>.
 
@@ -4462,6 +4462,93 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
        }
     }
 
+  /* Similarly add asserts for NAME == CST and NAME being defined as
+     NAME = NAME2 >> CST2.  */
+  if (TREE_CODE_CLASS (comp_code) == tcc_comparison
+      && TREE_CODE (val) == INTEGER_CST)
+    {
+      gimple def_stmt = SSA_NAME_DEF_STMT (name);
+      tree name2 = NULL_TREE, cst2 = NULL_TREE;
+      tree val2 = NULL_TREE;
+      unsigned HOST_WIDE_INT mask[2] = { 0, 0 };
+
+      /* Extract CST2 from the right shift.  */
+      if (is_gimple_assign (def_stmt)
+         && gimple_assign_rhs_code (def_stmt) == RSHIFT_EXPR)
+       {
+         name2 = gimple_assign_rhs1 (def_stmt);
+         cst2 = gimple_assign_rhs2 (def_stmt);
+         if (TREE_CODE (name2) == SSA_NAME
+             && host_integerp (cst2, 1)
+             && (unsigned HOST_WIDE_INT) tree_low_cst (cst2, 1)
+                < 2 * HOST_BITS_PER_WIDE_INT
+             && INTEGRAL_TYPE_P (TREE_TYPE (name2))
+             && live_on_edge (e, name2)
+             && !has_single_use (name2))
+           {
+             if ((unsigned HOST_WIDE_INT) tree_low_cst (cst2, 1)
+                 < HOST_BITS_PER_WIDE_INT)
+               mask[0] = ((unsigned HOST_WIDE_INT) 1
+                          << tree_low_cst (cst2, 1)) - 1;
+             else
+               {
+                 mask[1] = ((unsigned HOST_WIDE_INT) 1
+                            << (tree_low_cst (cst2, 1)
+                                - HOST_BITS_PER_WIDE_INT)) - 1;
+                 mask[0] = -1;
+               }
+             val2 = fold_binary (LSHIFT_EXPR, TREE_TYPE (val), val, cst2);
+           }
+       }
+
+      if (val2 != NULL_TREE
+         && TREE_CODE (val2) == INTEGER_CST
+         && simple_cst_equal (fold_build2 (RSHIFT_EXPR,
+                                           TREE_TYPE (val),
+                                           val2, cst2), val))
+       {
+         enum tree_code new_comp_code = comp_code;
+         tree tmp, new_val;
+
+         tmp = name2;
+         if (comp_code == EQ_EXPR || comp_code == NE_EXPR)
+           {
+             if (!TYPE_UNSIGNED (TREE_TYPE (val)))
+               {
+                 unsigned int prec = TYPE_PRECISION (TREE_TYPE (val));
+                 tree type = build_nonstandard_integer_type (prec, 1);
+                 tmp = build1 (NOP_EXPR, type, name2);
+                 val2 = fold_convert (type, val2);
+               }
+             tmp = fold_build2 (MINUS_EXPR, TREE_TYPE (tmp), tmp, val2);
+             new_val = build_int_cst_wide (TREE_TYPE (tmp), mask[0], mask[1]);
+             new_comp_code = comp_code == EQ_EXPR ? LE_EXPR : GT_EXPR;
+           }
+         else if (comp_code == LT_EXPR || comp_code == GE_EXPR)
+           new_val = val2;
+         else
+           {
+             new_val = build_int_cst_wide (TREE_TYPE (val2),
+                                           mask[0], mask[1]);
+             new_val = fold_binary (BIT_IOR_EXPR, TREE_TYPE (val2),
+                                    val2, new_val);
+           }
+
+         if (dump_file)
+           {
+             fprintf (dump_file, "Adding assert for ");
+             print_generic_expr (dump_file, name2, 0);
+             fprintf (dump_file, " from ");
+             print_generic_expr (dump_file, tmp, 0);
+             fprintf (dump_file, "\n");
+           }
+
+         register_new_assert_for (name2, tmp, new_comp_code, new_val,
+                                  NULL, e, bsi);
+         retval = true;
+       }
+    }
+
   return retval;
 }