OSDN Git Service

* java-tree.def (THIS_EXPR): Now a tcc_expression.
[pf3gnuchains/gcc-fork.git] / gcc / tree-vrp.c
index d8ff9fd..d487df6 100644 (file)
@@ -432,37 +432,6 @@ compare_values (tree val1, tree val2)
   gcc_assert (POINTER_TYPE_P (TREE_TYPE (val1))
              == POINTER_TYPE_P (TREE_TYPE (val2)));
 
-  /* Do some limited symbolic comparisons.  */
-  if (!POINTER_TYPE_P (TREE_TYPE (val1)))
-    {
-      /* We can determine some comparisons against +INF and -INF even
-        if the other value is an expression.  */
-      if (val1 == TYPE_MAX_VALUE (TREE_TYPE (val1))
-         && TREE_CODE (val2) == MINUS_EXPR)
-       {
-         /* +INF > NAME - CST.  */
-         return 1;
-       }
-      else if (val1 == TYPE_MIN_VALUE (TREE_TYPE (val1))
-              && TREE_CODE (val2) == PLUS_EXPR)
-       {
-         /* -INF < NAME + CST.  */
-         return -1;
-       }
-      else if (TREE_CODE (val1) == MINUS_EXPR
-              && val2 == TYPE_MAX_VALUE (TREE_TYPE (val2)))
-       {
-         /* NAME - CST < +INF.  */
-         return -1;
-       }
-      else if (TREE_CODE (val1) == PLUS_EXPR
-              && val2 == TYPE_MIN_VALUE (TREE_TYPE (val2)))
-       {
-         /* NAME + CST > -INF.  */
-         return 1;
-       }
-    }
-
   if ((TREE_CODE (val1) == SSA_NAME
        || TREE_CODE (val1) == PLUS_EXPR
        || TREE_CODE (val1) == MINUS_EXPR)
@@ -471,69 +440,95 @@ compare_values (tree val1, tree val2)
          || TREE_CODE (val2) == MINUS_EXPR))
     {
       tree n1, c1, n2, c2;
+      enum tree_code code1, code2;
   
       /* If VAL1 and VAL2 are of the form 'NAME [+-] CST' or 'NAME',
         return -1 or +1 accordingly.  If VAL1 and VAL2 don't use the
         same name, return -2.  */
       if (TREE_CODE (val1) == SSA_NAME)
        {
+         code1 = SSA_NAME;
          n1 = val1;
          c1 = NULL_TREE;
        }
       else
        {
+         code1 = TREE_CODE (val1);
          n1 = TREE_OPERAND (val1, 0);
          c1 = TREE_OPERAND (val1, 1);
+         if (tree_int_cst_sgn (c1) == -1)
+           {
+             c1 = fold_unary_to_constant (NEGATE_EXPR, TREE_TYPE (c1), c1);
+             if (!c1)
+               return -2;
+             code1 = code1 == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR;
+           }
        }
 
       if (TREE_CODE (val2) == SSA_NAME)
        {
+         code2 = SSA_NAME;
          n2 = val2;
          c2 = NULL_TREE;
        }
       else
        {
+         code2 = TREE_CODE (val2);
          n2 = TREE_OPERAND (val2, 0);
          c2 = TREE_OPERAND (val2, 1);
+         if (tree_int_cst_sgn (c2) == -1)
+           {
+             c2 = fold_unary_to_constant (NEGATE_EXPR, TREE_TYPE (c2), c2);
+             if (!c2)
+               return -2;
+             code2 = code2 == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR;
+           }
        }
 
       /* Both values must use the same name.  */
       if (n1 != n2)
        return -2;
 
-      if (TREE_CODE (val1) == SSA_NAME)
+      if (code1 == SSA_NAME
+         && code2 == SSA_NAME)
+       /* NAME == NAME  */
+       return 0;
+
+      /* If overflow is defined we cannot simplify more.  */
+      if (TYPE_UNSIGNED (TREE_TYPE (val1))
+         || flag_wrapv)
+       return -2;
+
+      if (code1 == SSA_NAME)
        {
-         if (TREE_CODE (val2) == SSA_NAME)
-           /* NAME == NAME  */
-           return 0;
-         else if (TREE_CODE (val2) == PLUS_EXPR)
+         if (code2 == PLUS_EXPR)
            /* NAME < NAME + CST  */
            return -1;
-         else if (TREE_CODE (val2) == MINUS_EXPR)
+         else if (code2 == MINUS_EXPR)
            /* NAME > NAME - CST  */
            return 1;
        }
-      else if (TREE_CODE (val1) == PLUS_EXPR)
+      else if (code1 == PLUS_EXPR)
        {
-         if (TREE_CODE (val2) == SSA_NAME)
+         if (code2 == SSA_NAME)
            /* NAME + CST > NAME  */
            return 1;
-         else if (TREE_CODE (val2) == PLUS_EXPR)
+         else if (code2 == PLUS_EXPR)
            /* NAME + CST1 > NAME + CST2, if CST1 > CST2  */
            return compare_values (c1, c2);
-         else if (TREE_CODE (val2) == MINUS_EXPR)
+         else if (code2 == MINUS_EXPR)
            /* NAME + CST1 > NAME - CST2  */
            return 1;
        }
-      else if (TREE_CODE (val1) == MINUS_EXPR)
+      else if (code1 == MINUS_EXPR)
        {
-         if (TREE_CODE (val2) == SSA_NAME)
+         if (code2 == SSA_NAME)
            /* NAME - CST < NAME  */
            return -1;
-         else if (TREE_CODE (val2) == PLUS_EXPR)
+         else if (code2 == PLUS_EXPR)
            /* NAME - CST1 < NAME + CST2  */
            return -1;
-         else if (TREE_CODE (val2) == MINUS_EXPR)
+         else if (code2 == MINUS_EXPR)
            /* NAME - CST1 > NAME - CST2, if CST1 < CST2.  Notice that
               C1 and C2 are swapped in the call to compare_values.  */
            return compare_values (c2, c1);
@@ -605,17 +600,17 @@ compare_values (tree val1, tree val2)
 static inline int
 value_inside_range (tree val, value_range_t *vr)
 {
-  int cmp1, cmp2;
+  tree cmp1, cmp2;
 
-  cmp1 = compare_values (val, vr->min);
-  if (cmp1 == -2 || cmp1 == 2)
+  cmp1 = fold_binary_to_constant (GE_EXPR, boolean_type_node, val, vr->min);
+  if (!cmp1)
     return -2;
 
-  cmp2 = compare_values (val, vr->max);
-  if (cmp2 == -2 || cmp2 == 2)
+  cmp2 = fold_binary_to_constant (LE_EXPR, boolean_type_node, val, vr->max);
+  if (!cmp2)
     return -2;
 
-  return (cmp1 == 0 || cmp1 == 1) && (cmp2 == -1 || cmp2 == 0);
+  return cmp1 == boolean_true_node && cmp2 == boolean_true_node;
 }
 
 
@@ -1058,7 +1053,7 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
             there are three cases to consider.
 
 
-            1. The VR_ANTI_RANGE range is competely within the 
+            1. The VR_ANTI_RANGE range is completely within the 
                VR_RANGE and the endpoints of the ranges are
                different.  In that case the resulting range
                should be whichever range is more precise.
@@ -1116,7 +1111,7 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
            }
          /* Case 3a, the anti-range extends into the low
             part of the real range.  Thus creating a new
-            low for the real reange.  */
+            low for the real range.  */
          else if ((compare_values (anti_max, real_min) == 1
                    || compare_values (anti_max, real_min) == 0)
                   && compare_values (anti_max, real_max) == -1)
@@ -1129,7 +1124,7 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
            }
          /* Case 3b, the anti-range extends into the high
             part of the real range.  Thus creating a new
-            higher for the real reange.  */
+            higher for the real range.  */
          else if (compare_values (anti_min, real_min) == 1
                   && (compare_values (anti_min, real_max) == -1
                       || compare_values (anti_min, real_max) == 0))
@@ -1196,17 +1191,39 @@ vrp_int_const_binop (enum tree_code code, tree val1, tree val2)
   if (TYPE_UNSIGNED (TREE_TYPE (val1)))
     {
       int checkz = compare_values (res, val1);
+      bool overflow = false;
 
       /* Ensure that res = val1 [+*] val2 >= val1
          or that res = val1 - val2 <= val1.  */
-      if (((code == PLUS_EXPR || code == MULT_EXPR)
+      if ((code == PLUS_EXPR
           && !(checkz == 1 || checkz == 0))
           || (code == MINUS_EXPR
              && !(checkz == 0 || checkz == -1)))
        {
+         overflow = true;
+       }
+      /* Checking for multiplication overflow is done by dividing the
+        output of the multiplication by the first input of the
+        multiplication.  If the result of that division operation is
+        not equal to the second input of the multiplication, then the
+        multiplication overflowed.  */
+      else if (code == MULT_EXPR && !integer_zerop (val1))
+       {
+         tree tmp = int_const_binop (TRUNC_DIV_EXPR,
+                                     TYPE_MAX_VALUE (TREE_TYPE (val1)),
+                                     val1, 0);
+         int check = compare_values (tmp, val2);
+
+         if (check != 0)
+           overflow = true;
+       }
+
+      if (overflow)
+       {
          res = copy_node (res);
          TREE_OVERFLOW (res) = 1;
        }
+
     }
   else if (TREE_OVERFLOW (res)
           && !TREE_OVERFLOW (val1)
@@ -1641,14 +1658,12 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
       return;
     }
 
-  /* Refuse to operate on varying and symbolic ranges.  Also, if the
-     operand is neither a pointer nor an integral type, set the
-     resulting range to VARYING.  TODO, in some cases we may be able
-     to derive anti-ranges (like nonzero values).  */
-  if (vr0.type == VR_VARYING
-      || (!INTEGRAL_TYPE_P (TREE_TYPE (op0))
-         && !POINTER_TYPE_P (TREE_TYPE (op0)))
-      || symbolic_range_p (&vr0))
+  /* Refuse to operate on symbolic ranges, or if neither operand is
+     a pointer or integral type.  */
+  if ((!INTEGRAL_TYPE_P (TREE_TYPE (op0))
+       && !POINTER_TYPE_P (TREE_TYPE (op0)))
+      || (vr0.type != VR_VARYING
+         && symbolic_range_p (&vr0)))
     {
       set_value_range_to_varying (vr);
       return;
@@ -1681,20 +1696,36 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
         or equal to the new max, then we can safely use the newly
         computed range for EXPR.  This allows us to compute
         accurate ranges through many casts.  */
-      if (vr0.type == VR_RANGE)
+      if (vr0.type == VR_RANGE
+         || (vr0.type == VR_VARYING
+             && TYPE_PRECISION (outer_type) > TYPE_PRECISION (inner_type)))
        {
-         tree new_min, new_max;
+         tree new_min, new_max, orig_min, orig_max;
 
-         /* Convert VR0's min/max to OUTER_TYPE.  */
-         new_min = fold_convert (outer_type, vr0.min);
-         new_max = fold_convert (outer_type, vr0.max);
+         /* Convert the input operand min/max to OUTER_TYPE.   If
+            the input has no range information, then use the min/max
+            for the input's type.  */
+         if (vr0.type == VR_RANGE)
+           {
+             orig_min = vr0.min;
+             orig_max = vr0.max;
+           }
+         else
+           {
+             orig_min = TYPE_MIN_VALUE (inner_type);
+             orig_max = TYPE_MAX_VALUE (inner_type);
+           }
+
+         new_min = fold_convert (outer_type, orig_min);
+         new_max = fold_convert (outer_type, orig_max);
 
          /* Verify the new min/max values are gimple values and
-            that they compare equal to VR0's min/max values.  */
+            that they compare equal to the original input's
+            min/max values.  */
          if (is_gimple_val (new_min)
              && is_gimple_val (new_max)
-             && tree_int_cst_equal (new_min, vr0.min)
-             && tree_int_cst_equal (new_max, vr0.max)
+             && tree_int_cst_equal (new_min, orig_min)
+             && tree_int_cst_equal (new_max, orig_max)
              && compare_values (new_min, new_max) <= 0
              && compare_values (new_min, new_max) >= -1)
            {
@@ -1717,6 +1748,16 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
        }
     }
 
+  /* Conversion of a VR_VARYING value to a wider type can result
+     in a usable range.  So wait until after we've handled conversions
+     before dropping the result to VR_VARYING if we had a source
+     operand that is VR_VARYING.  */
+  if (vr0.type == VR_VARYING)
+    {
+      set_value_range_to_varying (vr);
+      return;
+    }
+
   /* Apply the operation to each end of the range and see what we end
      up with.  */
   if (code == NEGATE_EXPR
@@ -2440,16 +2481,16 @@ infer_value_range (tree stmt, tree op, enum tree_code *comp_code_p, tree *val_p)
   if (stmt_ends_bb_p (stmt) && EDGE_COUNT (bb_for_stmt (stmt)->succs) == 0)
     return false;
 
-  if (POINTER_TYPE_P (TREE_TYPE (op)))
+  /* We can only assume that a pointer dereference will yield
+     non-NULL if -fdelete-null-pointer-checks is enabled.  */
+  if (flag_delete_null_pointer_checks && POINTER_TYPE_P (TREE_TYPE (op)))
     {
       bool is_store;
       unsigned num_uses, num_derefs;
 
       count_uses_and_derefs (op, stmt, &num_uses, &num_derefs, &is_store);
-      if (num_derefs > 0 && flag_delete_null_pointer_checks)
+      if (num_derefs > 0)
        {
-         /* We can only assume that a pointer dereference will yield
-            non-NULL if -fdelete-null-pointer-checks is enabled.  */
          *val_p = build_int_cst (TREE_TYPE (op), 0);
          *comp_code_p = NE_EXPR;
          return true;
@@ -2952,21 +2993,50 @@ find_assert_locations (basic_block bb)
             operands it was looking for was present in the sub-graph.  */
          SET_BIT (found_in_subgraph, SSA_NAME_VERSION (op));
 
-         /* If OP is used only once, namely in this STMT, don't
-            bother creating an ASSERT_EXPR for it.  Such an
-            ASSERT_EXPR would do nothing but increase compile time.
-            Experiments show that with this simple check, we can save
-            more than 20% of ASSERT_EXPRs.  */
-         if (has_single_use (op))
-           continue;
-
          /* If OP is used in such a way that we can infer a value
             range for it, and we don't find a previous assertion for
             it, create a new assertion location node for OP.  */
          if (infer_value_range (stmt, op, &comp_code, &value))
            {
-             register_new_assert_for (op, comp_code, value, bb, NULL, si);
-             need_assert = true;
+             /* If we are able to infer a nonzero value range for OP,
+                then walk backwards through the use-def chain to see if OP
+                was set via a typecast.
+
+                If so, then we can also infer a nonzero value range
+                for the operand of the NOP_EXPR.  */
+             if (comp_code == NE_EXPR && integer_zerop (value))
+               {
+                 tree t = op;
+                 tree def_stmt = SSA_NAME_DEF_STMT (t);
+       
+                 while (TREE_CODE (def_stmt) == MODIFY_EXPR
+                        && TREE_CODE (TREE_OPERAND (def_stmt, 1)) == NOP_EXPR
+                        && TREE_CODE (TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 0)) == SSA_NAME
+                        && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 0))))
+                   {
+                     t = TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 0);
+                     def_stmt = SSA_NAME_DEF_STMT (t);
+
+                     /* Note we want to register the assert for the
+                        operand of the NOP_EXPR after SI, not after the
+                        conversion.  */
+                     if (! has_single_use (t))
+                       {
+                         register_new_assert_for (t, comp_code, value,
+                                                  bb, NULL, si);
+                         need_assert = true;
+                       }
+                   }
+               }
+
+             /* If OP is used only once, namely in this STMT, don't
+                bother creating an ASSERT_EXPR for it.  Such an
+                ASSERT_EXPR would do nothing but increase compile time.  */
+             if (!has_single_use (op))
+               {
+                 register_new_assert_for (op, comp_code, value, bb, NULL, si);
+                 need_assert = true;
+               }
            }
        }
 
@@ -3194,26 +3264,26 @@ remove_range_assertions (void)
     for (si = bsi_start (bb); !bsi_end_p (si);)
       {
        tree stmt = bsi_stmt (si);
+       tree use_stmt;
 
        if (TREE_CODE (stmt) == MODIFY_EXPR
            && TREE_CODE (TREE_OPERAND (stmt, 1)) == ASSERT_EXPR)
          {
-           tree rhs = TREE_OPERAND (stmt, 1);
+           tree rhs = TREE_OPERAND (stmt, 1), var;
            tree cond = fold (ASSERT_EXPR_COND (rhs));
            use_operand_p use_p;
            imm_use_iterator iter;
 
            gcc_assert (cond != boolean_false_node);
-           TREE_OPERAND (stmt, 1) = ASSERT_EXPR_VAR (rhs);
-           update_stmt (stmt);
 
-           /* The statement is now a copy.  Propagate the RHS into
-              every use of the LHS.  */
-           FOR_EACH_IMM_USE_SAFE (use_p, iter, TREE_OPERAND (stmt, 0))
-             {
-               SET_USE (use_p, ASSERT_EXPR_VAR (rhs));
-               update_stmt (USE_STMT (use_p));
-             }
+           /* Propagate the RHS into every use of the LHS.  */
+           var = ASSERT_EXPR_VAR (rhs);
+           FOR_EACH_IMM_USE_STMT (use_stmt, iter, TREE_OPERAND (stmt, 0))
+             FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
+               {
+                 SET_USE (use_p, var);
+                 gcc_assert (TREE_CODE (var) == SSA_NAME);
+               }
 
            /* And finally, remove the copy, it is not needed.  */
            bsi_remove (&si, true);
@@ -3239,11 +3309,19 @@ stmt_interesting_for_vrp (tree stmt)
   else if (TREE_CODE (stmt) == MODIFY_EXPR)
     {
       tree lhs = TREE_OPERAND (stmt, 0);
+      tree rhs = TREE_OPERAND (stmt, 1);
 
+      /* In general, assignments with virtual operands are not useful
+        for deriving ranges, with the obvious exception of calls to
+        builtin functions.  */
       if (TREE_CODE (lhs) == SSA_NAME
          && (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
              || POINTER_TYPE_P (TREE_TYPE (lhs)))
-         && ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
+         && ((TREE_CODE (rhs) == CALL_EXPR
+              && TREE_CODE (TREE_OPERAND (rhs, 0)) == ADDR_EXPR
+              && DECL_P (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0))
+              && DECL_IS_BUILTIN (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0)))
+             || ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS)))
        return true;
     }
   else if (TREE_CODE (stmt) == COND_EXPR || TREE_CODE (stmt) == SWITCH_EXPR)
@@ -3712,9 +3790,20 @@ vrp_visit_stmt (tree stmt, edge *taken_edge_p, tree *output_p)
     }
 
   ann = stmt_ann (stmt);
-  if (TREE_CODE (stmt) == MODIFY_EXPR
-      && ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
-    return vrp_visit_assignment (stmt, output_p);
+  if (TREE_CODE (stmt) == MODIFY_EXPR)
+    {
+      tree rhs = TREE_OPERAND (stmt, 1);
+
+      /* In general, assignments with virtual operands are not useful
+        for deriving ranges, with the obvious exception of calls to
+        builtin functions.  */
+      if ((TREE_CODE (rhs) == CALL_EXPR
+          && TREE_CODE (TREE_OPERAND (rhs, 0)) == ADDR_EXPR
+          && DECL_P (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0))
+          && DECL_IS_BUILTIN (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0)))
+         || ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
+       return vrp_visit_assignment (stmt, output_p);
+    }
   else if (TREE_CODE (stmt) == COND_EXPR || TREE_CODE (stmt) == SWITCH_EXPR)
     return vrp_visit_cond_stmt (stmt, taken_edge_p);