This extends VRP to handle BIT_NOT_EXPR by composing ~X as
-X - 1 (which should give us anti-range handling for free).

It requires factoring a value-range taking worker from
extract_range_from_unary_expr like I already did for
extract_range_from_binary_expr, thus that is included in this patch.

Bootstrap and regtest running on x86_64-unknown-linux-gnu.

Richard.

2011-08-05  Richard Guenther  <rguent...@suse.de>

        * tree-vrp.c (extract_range_from_unary_expr_1): New function,
        split out from ...
        (extract_range_from_unary_expr): ... here.  Handle BIT_NOT_EXPR
        by composition.

Index: gcc/tree-vrp.c
===================================================================
*** gcc/tree-vrp.c      (revision 177425)
--- gcc/tree-vrp.c      (working copy)
*************** extract_range_from_binary_expr (value_ra
*** 2805,2864 ****
    extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &vr1);
  }
  
! /* Extract range information from a unary expression EXPR based on
!    the range of its operand and the expression code.  */
  
  static void
! extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
!                              tree type, tree op0)
  {
    tree min, max;
    int cmp;
!   value_range_t vr0 = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
  
    /* Refuse to operate on certain unary expressions for which we
       cannot easily determine a resulting range.  */
    if (code == FIX_TRUNC_EXPR
        || code == FLOAT_EXPR
-       || code == BIT_NOT_EXPR
        || code == CONJ_EXPR)
      {
-       /* We can still do constant propagation here.  */
-       if ((op0 = op_with_constant_singleton_value_range (op0)) != NULL_TREE)
-       {
-         tree tem = fold_unary (code, type, op0);
-         if (tem
-             && is_gimple_min_invariant (tem)
-             && !is_overflow_infinity (tem))
-           {
-             set_value_range (vr, VR_RANGE, tem, tem, NULL);
-             return;
-           }
-       }
        set_value_range_to_varying (vr);
        return;
      }
  
-   /* Get value ranges for the operand.  For constant operands, create
-      a new value range with the operand to simplify processing.  */
-   if (TREE_CODE (op0) == SSA_NAME)
-     vr0 = *(get_value_range (op0));
-   else if (is_gimple_min_invariant (op0))
-     set_value_range_to_value (&vr0, op0, NULL);
-   else
-     set_value_range_to_varying (&vr0);
- 
-   /* If VR0 is UNDEFINED, so is the result.  */
-   if (vr0.type == VR_UNDEFINED)
-     {
-       set_value_range_to_undefined (vr);
-       return;
-     }
- 
    /* 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)))
      {
--- 2815,2854 ----
    extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &vr1);
  }
  
! /* Extract range information from a unary operation CODE based on
!    the range of its operand *VR0 with type OP0_TYPE with resulting type TYPE.
!    The The resulting range is stored in *VR.  */
  
  static void
! extract_range_from_unary_expr_1 (value_range_t *vr,
!                                enum tree_code code, tree type,
!                                value_range_t *vr0_, tree op0_type)
  {
+   value_range_t vr0 = *vr0_;
    tree min, max;
    int cmp;
! 
!   /* If VR0 is UNDEFINED, so is the result.  */
!   if (vr0.type == VR_UNDEFINED)
!     {
!       set_value_range_to_undefined (vr);
!       return;
!     }
  
    /* Refuse to operate on certain unary expressions for which we
       cannot easily determine a resulting range.  */
    if (code == FIX_TRUNC_EXPR
        || code == FLOAT_EXPR
        || code == CONJ_EXPR)
      {
        set_value_range_to_varying (vr);
        return;
      }
  
    /* Refuse to operate on symbolic ranges, or if neither operand is
       a pointer or integral type.  */
!   if ((!INTEGRAL_TYPE_P (op0_type)
!        && !POINTER_TYPE_P (op0_type))
        || (vr0.type != VR_VARYING
          && symbolic_range_p (&vr0)))
      {
*************** extract_range_from_unary_expr (value_ran
*** 2868,2896 ****
  
    /* If the expression involves pointers, we are only interested in
       determining if it evaluates to NULL [0, 0] or non-NULL (~[0, 0]).  */
!   if (POINTER_TYPE_P (type) || POINTER_TYPE_P (TREE_TYPE (op0)))
      {
!       bool sop;
! 
!       sop = false;
!       if (range_is_nonnull (&vr0)
!         || (tree_unary_nonzero_warnv_p (code, type, op0, &sop)
!             && !sop))
        set_value_range_to_nonnull (vr, type);
        else if (range_is_null (&vr0))
        set_value_range_to_null (vr, type);
        else
        set_value_range_to_varying (vr);
- 
        return;
      }
  
    /* Handle unary expressions on integer ranges.  */
    if (CONVERT_EXPR_CODE_P (code)
        && INTEGRAL_TYPE_P (type)
!       && INTEGRAL_TYPE_P (TREE_TYPE (op0)))
      {
!       tree inner_type = TREE_TYPE (op0);
        tree outer_type = type;
  
        /* If VR0 is varying and we increase the type precision, assume
--- 2858,2880 ----
  
    /* If the expression involves pointers, we are only interested in
       determining if it evaluates to NULL [0, 0] or non-NULL (~[0, 0]).  */
!   if (POINTER_TYPE_P (type) || POINTER_TYPE_P (op0_type))
      {
!       if (range_is_nonnull (&vr0))
        set_value_range_to_nonnull (vr, type);
        else if (range_is_null (&vr0))
        set_value_range_to_null (vr, type);
        else
        set_value_range_to_varying (vr);
        return;
      }
  
    /* Handle unary expressions on integer ranges.  */
    if (CONVERT_EXPR_CODE_P (code)
        && INTEGRAL_TYPE_P (type)
!       && INTEGRAL_TYPE_P (op0_type))
      {
!       tree inner_type = op0_type;
        tree outer_type = type;
  
        /* If VR0 is varying and we increase the type precision, assume
*************** extract_range_from_unary_expr (value_ran
*** 3146,3151 ****
--- 3130,3156 ----
            }
        }
      }
+   else if (code == BIT_NOT_EXPR)
+     {
+       /* ~X is simply -X - 1, so re-use existing code that also handles
+          anti-ranges fine.  */
+       value_range_t one = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
+       value_range_t tem = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
+       /* Make sure no signed overflow will occur.  */
+       if (!TYPE_UNSIGNED (type)
+         && vr0.type == VR_RANGE
+         && vrp_val_is_min (vr0.min))
+       {
+         set_value_range_to_varying (vr);
+         return;
+       }
+       set_value_range_to_value (&one, build_int_cst (type, 1), NULL);
+       extract_range_from_unary_expr_1 (&tem, NEGATE_EXPR,
+                                      type, vr0_, op0_type);
+       extract_range_from_binary_expr_1 (vr, MINUS_EXPR,
+                                       type, &tem, &one);
+       return;
+     }
    else
      {
        /* Otherwise, operate on each end of the range.  */
*************** extract_range_from_unary_expr (value_ran
*** 3212,3217 ****
--- 3217,3245 ----
  }
  
  
+ /* Extract range information from a unary expression CODE OP0 based on
+    the range of its operand with resulting type TYPE.
+    The resulting range is stored in *VR.  */
+ 
+ static void
+ extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
+                              tree type, tree op0)
+ {
+   value_range_t vr0 = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
+ 
+   /* Get value ranges for the operand.  For constant operands, create
+      a new value range with the operand to simplify processing.  */
+   if (TREE_CODE (op0) == SSA_NAME)
+     vr0 = *(get_value_range (op0));
+   else if (is_gimple_min_invariant (op0))
+     set_value_range_to_value (&vr0, op0, NULL);
+   else
+     set_value_range_to_varying (&vr0);
+ 
+   extract_range_from_unary_expr_1 (vr, code, type, &vr0, TREE_TYPE (op0));
+ }
+ 
+ 
  /* Extract range information from a conditional expression EXPR based on
     the ranges of each of its operands and the expression code.  */
  

Reply via email to