More VRP TLC, this restructures extract_range_from_binary_expr_1 a bit,
avoiding to glob unrelated tree codes to avoid some code duplication.
Instead factor out the common code.

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.

Richard.

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

        * tree-vrp.c (extract_range_from_multiplicative_op_1): New
        helper factored out from ...
        (extract_range_from_binary_expr_1): ... here.  Re-structure
        to not glob handling too different tree codes.

Index: gcc/tree-vrp.c
===================================================================
*** gcc/tree-vrp.c      (revision 177762)
--- gcc/tree-vrp.c      (working copy)
*************** zero_nonzero_bits_from_vr (value_range_t
*** 2181,2186 ****
--- 2181,2338 ----
    return true;
  }
  
+ /* Helper to extract a value-range *VR for a multiplicative operation
+    *VR0 CODE *VR1.  */
+ 
+ static void
+ extract_range_from_multiplicative_op_1 (value_range_t *vr,
+                                       enum tree_code code,
+                                       value_range_t *vr0, value_range_t *vr1)
+ {
+   enum value_range_type type;
+   tree val[4];
+   size_t i;
+   tree min, max;
+   bool sop;
+   int cmp;
+ 
+   /* Multiplications, divisions and shifts are a bit tricky to handle,
+      depending on the mix of signs we have in the two ranges, we
+      need to operate on different values to get the minimum and
+      maximum values for the new range.  One approach is to figure
+      out all the variations of range combinations and do the
+      operations.
+ 
+      However, this involves several calls to compare_values and it
+      is pretty convoluted.  It's simpler to do the 4 operations
+      (MIN0 OP MIN1, MIN0 OP MAX1, MAX0 OP MIN1 and MAX0 OP MAX0 OP
+      MAX1) and then figure the smallest and largest values to form
+      the new range.  */
+   gcc_assert (code == MULT_EXPR
+             || code == TRUNC_DIV_EXPR
+             || code == FLOOR_DIV_EXPR
+             || code == CEIL_DIV_EXPR
+             || code == EXACT_DIV_EXPR
+             || code == ROUND_DIV_EXPR
+             || code == RSHIFT_EXPR);
+   gcc_assert ((vr0->type == VR_RANGE
+              || (code == MULT_EXPR && vr0->type == VR_ANTI_RANGE))
+             && vr0->type == vr1->type);
+ 
+   type = vr0->type;
+ 
+   /* Compute the 4 cross operations.  */
+   sop = false;
+   val[0] = vrp_int_const_binop (code, vr0->min, vr1->min);
+   if (val[0] == NULL_TREE)
+     sop = true;
+ 
+   if (vr1->max == vr1->min)
+     val[1] = NULL_TREE;
+   else
+     {
+       val[1] = vrp_int_const_binop (code, vr0->min, vr1->max);
+       if (val[1] == NULL_TREE)
+       sop = true;
+     }
+ 
+   if (vr0->max == vr0->min)
+     val[2] = NULL_TREE;
+   else
+     {
+       val[2] = vrp_int_const_binop (code, vr0->max, vr1->min);
+       if (val[2] == NULL_TREE)
+       sop = true;
+     }
+ 
+   if (vr0->min == vr0->max || vr1->min == vr1->max)
+     val[3] = NULL_TREE;
+   else
+     {
+       val[3] = vrp_int_const_binop (code, vr0->max, vr1->max);
+       if (val[3] == NULL_TREE)
+       sop = true;
+     }
+ 
+   if (sop)
+     {
+       set_value_range_to_varying (vr);
+       return;
+     }
+ 
+   /* Set MIN to the minimum of VAL[i] and MAX to the maximum
+      of VAL[i].  */
+   min = val[0];
+   max = val[0];
+   for (i = 1; i < 4; i++)
+     {
+       if (!is_gimple_min_invariant (min)
+         || (TREE_OVERFLOW (min) && !is_overflow_infinity (min))
+         || !is_gimple_min_invariant (max)
+         || (TREE_OVERFLOW (max) && !is_overflow_infinity (max)))
+       break;
+ 
+       if (val[i])
+       {
+         if (!is_gimple_min_invariant (val[i])
+             || (TREE_OVERFLOW (val[i])
+                 && !is_overflow_infinity (val[i])))
+           {
+             /* If we found an overflowed value, set MIN and MAX
+                to it so that we set the resulting range to
+                VARYING.  */
+             min = max = val[i];
+             break;
+           }
+ 
+         if (compare_values (val[i], min) == -1)
+           min = val[i];
+ 
+         if (compare_values (val[i], max) == 1)
+           max = val[i];
+       }
+     }
+ 
+   /* If either MIN or MAX overflowed, then set the resulting range to
+      VARYING.  But we do accept an overflow infinity
+      representation.  */
+   if (min == NULL_TREE
+       || !is_gimple_min_invariant (min)
+       || (TREE_OVERFLOW (min) && !is_overflow_infinity (min))
+       || max == NULL_TREE
+       || !is_gimple_min_invariant (max)
+       || (TREE_OVERFLOW (max) && !is_overflow_infinity (max)))
+     {
+       set_value_range_to_varying (vr);
+       return;
+     }
+ 
+   /* We punt if:
+      1) [-INF, +INF]
+      2) [-INF, +-INF(OVF)]
+      3) [+-INF(OVF), +INF]
+      4) [+-INF(OVF), +-INF(OVF)]
+      We learn nothing when we have INF and INF(OVF) on both sides.
+      Note that we do accept [-INF, -INF] and [+INF, +INF] without
+      overflow.  */
+   if ((vrp_val_is_min (min) || is_overflow_infinity (min))
+       && (vrp_val_is_max (max) || is_overflow_infinity (max)))
+     {
+       set_value_range_to_varying (vr);
+       return;
+     }
+ 
+   cmp = compare_values (min, max);
+   if (cmp == -2 || cmp == 1)
+     {
+       /* If the new range has its limits swapped around (MIN > MAX),
+        then the operation caused one of them to wrap around, mark
+        the new range VARYING.  */
+       set_value_range_to_varying (vr);
+     }
+   else
+     set_value_range (vr, type, min, max, NULL);
+ }
  
  /* Extract range information from a binary operation CODE based on
     the ranges of each of its operands, *VR0 and *VR1 with resulting
*************** extract_range_from_binary_expr_1 (value_
*** 2193,2201 ****
  {
    value_range_t vr0 = *vr0_, vr1 = *vr1_;
    enum value_range_type type;
!   tree min, max;
    int cmp;
  
    /* Not all binary expressions can be applied to ranges in a
       meaningful way.  Handle only arithmetic operations.  */
    if (code != PLUS_EXPR
--- 2345,2360 ----
  {
    value_range_t vr0 = *vr0_, vr1 = *vr1_;
    enum value_range_type type;
!   tree min = NULL_TREE, max = NULL_TREE;
    int cmp;
  
+   if (!INTEGRAL_TYPE_P (expr_type)
+       && !POINTER_TYPE_P (expr_type))
+     {
+       set_value_range_to_varying (vr);
+       return;
+     }
+ 
    /* Not all binary expressions can be applied to ranges in a
       meaningful way.  Handle only arithmetic operations.  */
    if (code != PLUS_EXPR
*************** extract_range_from_binary_expr_1 (value_
*** 2307,2315 ****
  
    /* For integer ranges, apply the operation to each end of the
       range and see what we end up with.  */
!   if (code == PLUS_EXPR
!       || code == MIN_EXPR
!       || code == MAX_EXPR)
      {
        /* If we have a PLUS_EXPR with two VR_ANTI_RANGEs, drop to
         VR_VARYING.  It would take more effort to compute a precise
--- 2466,2472 ----
  
    /* For integer ranges, apply the operation to each end of the
       range and see what we end up with.  */
!   if (code == PLUS_EXPR)
      {
        /* If we have a PLUS_EXPR with two VR_ANTI_RANGEs, drop to
         VR_VARYING.  It would take more effort to compute a precise
*************** extract_range_from_binary_expr_1 (value_
*** 2320,2351 ****
         this point.  */
        if (vr0.type == VR_ANTI_RANGE)
        {
!         if (code == PLUS_EXPR)
!           {
!             set_value_range_to_varying (vr);
!             return;
!           }
!         /* For MIN_EXPR and MAX_EXPR with two VR_ANTI_RANGEs,
!            the resulting VR_ANTI_RANGE is the same - intersection
!            of the two ranges.  */
!         min = vrp_int_const_binop (MAX_EXPR, vr0.min, vr1.min);
!         max = vrp_int_const_binop (MIN_EXPR, vr0.max, vr1.max);
!       }
!       else
!       {
!         /* For operations that make the resulting range directly
!            proportional to the original ranges, apply the operation to
!            the same end of each range.  */
!         min = vrp_int_const_binop (code, vr0.min, vr1.min);
!         max = vrp_int_const_binop (code, vr0.max, vr1.max);
        }
  
        /* If both additions overflowed the range kind is still correct.
         This happens regularly with subtracting something in unsigned
         arithmetic.
           ???  See PR30318 for all the cases we do not handle.  */
!       if (code == PLUS_EXPR
!         && (TREE_OVERFLOW (min) && !is_overflow_infinity (min))
          && (TREE_OVERFLOW (max) && !is_overflow_infinity (max)))
        {
          min = build_int_cst_wide (TREE_TYPE (min),
--- 2477,2497 ----
         this point.  */
        if (vr0.type == VR_ANTI_RANGE)
        {
!         set_value_range_to_varying (vr);
!         return;
        }
  
+       /* For operations that make the resulting range directly
+        proportional to the original ranges, apply the operation to
+        the same end of each range.  */
+       min = vrp_int_const_binop (code, vr0.min, vr1.min);
+       max = vrp_int_const_binop (code, vr0.max, vr1.max);
+ 
        /* If both additions overflowed the range kind is still correct.
         This happens regularly with subtracting something in unsigned
         arithmetic.
           ???  See PR30318 for all the cases we do not handle.  */
!       if ((TREE_OVERFLOW (min) && !is_overflow_infinity (min))
          && (TREE_OVERFLOW (max) && !is_overflow_infinity (max)))
        {
          min = build_int_cst_wide (TREE_TYPE (min),
*************** extract_range_from_binary_expr_1 (value_
*** 2356,2373 ****
                                    TREE_INT_CST_HIGH (max));
        }
      }
!   else if (code == MULT_EXPR
!          || code == TRUNC_DIV_EXPR
!          || code == FLOOR_DIV_EXPR
!          || code == CEIL_DIV_EXPR
!          || code == EXACT_DIV_EXPR
!          || code == ROUND_DIV_EXPR
!          || code == RSHIFT_EXPR)
      {
-       tree val[4];
-       size_t i;
-       bool sop;
- 
        /* If we have an unsigned MULT_EXPR with two VR_ANTI_RANGEs,
         drop to VR_VARYING.  It would take more effort to compute a
         precise range for such a case.  For example, if we have
--- 2502,2529 ----
                                    TREE_INT_CST_HIGH (max));
        }
      }
!   else if (code == MIN_EXPR
!          || code == MAX_EXPR)
!     {
!       if (vr0.type == VR_ANTI_RANGE)
!       {
!         /* For MIN_EXPR and MAX_EXPR with two VR_ANTI_RANGEs,
!            the resulting VR_ANTI_RANGE is the same - intersection
!            of the two ranges.  */
!         min = vrp_int_const_binop (MAX_EXPR, vr0.min, vr1.min);
!         max = vrp_int_const_binop (MIN_EXPR, vr0.max, vr1.max);
!       }
!       else
!       {
!         /* For operations that make the resulting range directly
!            proportional to the original ranges, apply the operation to
!            the same end of each range.  */
!         min = vrp_int_const_binop (code, vr0.min, vr1.min);
!         max = vrp_int_const_binop (code, vr0.max, vr1.max);
!       }
!     }
!   else if (code == MULT_EXPR)
      {
        /* If we have an unsigned MULT_EXPR with two VR_ANTI_RANGEs,
         drop to VR_VARYING.  It would take more effort to compute a
         precise range for such a case.  For example, if we have
*************** extract_range_from_binary_expr_1 (value_
*** 2376,2389 ****
         we cannot claim that the product is in ~[0,0].  Note that we
         are guaranteed to have vr0.type == vr1.type at this
         point.  */
!       if (code == MULT_EXPR
!         && vr0.type == VR_ANTI_RANGE
          && !TYPE_OVERFLOW_UNDEFINED (expr_type))
        {
          set_value_range_to_varying (vr);
          return;
        }
  
        /* If we have a RSHIFT_EXPR with any shift values outside [0..prec-1],
         then drop to VR_VARYING.  Outside of this range we get undefined
         behavior from the shift operation.  We cannot even trust
--- 2532,2549 ----
         we cannot claim that the product is in ~[0,0].  Note that we
         are guaranteed to have vr0.type == vr1.type at this
         point.  */
!       if (vr0.type == VR_ANTI_RANGE
          && !TYPE_OVERFLOW_UNDEFINED (expr_type))
        {
          set_value_range_to_varying (vr);
          return;
        }
  
+       extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
+       return;
+     }
+   else if (code == RSHIFT_EXPR)
+     {
        /* If we have a RSHIFT_EXPR with any shift values outside [0..prec-1],
         then drop to VR_VARYING.  Outside of this range we get undefined
         behavior from the shift operation.  We cannot even trust
*************** extract_range_from_binary_expr_1 (value_
*** 2402,2413 ****
            }
        }
  
!       else if ((code == TRUNC_DIV_EXPR
!               || code == FLOOR_DIV_EXPR
!               || code == CEIL_DIV_EXPR
!               || code == EXACT_DIV_EXPR
!               || code == ROUND_DIV_EXPR)
!              && (vr0.type != VR_RANGE || symbolic_range_p (&vr0)))
        {
          /* For division, if op1 has VR_RANGE but op0 does not, something
             can be deduced just from that range.  Say [min, max] / [4, max]
--- 2562,2577 ----
            }
        }
  
!       extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
!       return;
!     }
!   else if (code == TRUNC_DIV_EXPR
!          || code == FLOOR_DIV_EXPR
!          || code == CEIL_DIV_EXPR
!          || code == EXACT_DIV_EXPR
!          || code == ROUND_DIV_EXPR)
!     {
!       if (vr0.type != VR_RANGE || symbolic_range_p (&vr0))
        {
          /* For division, if op1 has VR_RANGE but op0 does not, something
             can be deduced just from that range.  Say [min, max] / [4, max]
*************** extract_range_from_binary_expr_1 (value_
*** 2429,2440 ****
  
        /* For divisions, if flag_non_call_exceptions is true, we must
         not eliminate a division by zero.  */
!       if ((code == TRUNC_DIV_EXPR
!          || code == FLOOR_DIV_EXPR
!          || code == CEIL_DIV_EXPR
!          || code == EXACT_DIV_EXPR
!          || code == ROUND_DIV_EXPR)
!         && cfun->can_throw_non_call_exceptions
          && (vr1.type != VR_RANGE
              || symbolic_range_p (&vr1)
              || range_includes_zero_p (&vr1)))
--- 2593,2599 ----
  
        /* For divisions, if flag_non_call_exceptions is true, we must
         not eliminate a division by zero.  */
!       if (cfun->can_throw_non_call_exceptions
          && (vr1.type != VR_RANGE
              || symbolic_range_p (&vr1)
              || range_includes_zero_p (&vr1)))
*************** extract_range_from_binary_expr_1 (value_
*** 2446,2457 ****
        /* For divisions, if op0 is VR_RANGE, we can deduce a range
         even if op1 is VR_VARYING, VR_ANTI_RANGE, symbolic or can
         include 0.  */
!       if ((code == TRUNC_DIV_EXPR
!          || code == FLOOR_DIV_EXPR
!          || code == CEIL_DIV_EXPR
!          || code == EXACT_DIV_EXPR
!          || code == ROUND_DIV_EXPR)
!         && vr0.type == VR_RANGE
          && (vr1.type != VR_RANGE
              || symbolic_range_p (&vr1)
              || range_includes_zero_p (&vr1)))
--- 2605,2611 ----
        /* For divisions, if op0 is VR_RANGE, we can deduce a range
         even if op1 is VR_VARYING, VR_ANTI_RANGE, symbolic or can
         include 0.  */
!       if (vr0.type == VR_RANGE
          && (vr1.type != VR_RANGE
              || symbolic_range_p (&vr1)
              || range_includes_zero_p (&vr1)))
*************** extract_range_from_binary_expr_1 (value_
*** 2459,2465 ****
          tree zero = build_int_cst (TREE_TYPE (vr0.min), 0);
          int cmp;
  
-         sop = false;
          min = NULL_TREE;
          max = NULL_TREE;
          if (TYPE_UNSIGNED (expr_type)
--- 2613,2618 ----
*************** extract_range_from_binary_expr_1 (value_
*** 2498,2593 ****
              return;
            }
        }
- 
-       /* Multiplications and divisions are a bit tricky to handle,
-        depending on the mix of signs we have in the two ranges, we
-        need to operate on different values to get the minimum and
-        maximum values for the new range.  One approach is to figure
-        out all the variations of range combinations and do the
-        operations.
- 
-        However, this involves several calls to compare_values and it
-        is pretty convoluted.  It's simpler to do the 4 operations
-        (MIN0 OP MIN1, MIN0 OP MAX1, MAX0 OP MIN1 and MAX0 OP MAX0 OP
-        MAX1) and then figure the smallest and largest values to form
-        the new range.  */
        else
        {
!         gcc_assert ((vr0.type == VR_RANGE
!                      || (code == MULT_EXPR && vr0.type == VR_ANTI_RANGE))
!                     && vr0.type == vr1.type);
! 
!         /* Compute the 4 cross operations.  */
!         sop = false;
!         val[0] = vrp_int_const_binop (code, vr0.min, vr1.min);
!         if (val[0] == NULL_TREE)
!           sop = true;
! 
!         if (vr1.max == vr1.min)
!           val[1] = NULL_TREE;
!         else
!           {
!             val[1] = vrp_int_const_binop (code, vr0.min, vr1.max);
!             if (val[1] == NULL_TREE)
!               sop = true;
!           }
! 
!         if (vr0.max == vr0.min)
!           val[2] = NULL_TREE;
!         else
!           {
!             val[2] = vrp_int_const_binop (code, vr0.max, vr1.min);
!             if (val[2] == NULL_TREE)
!               sop = true;
!           }
! 
!         if (vr0.min == vr0.max || vr1.min == vr1.max)
!           val[3] = NULL_TREE;
!         else
!           {
!             val[3] = vrp_int_const_binop (code, vr0.max, vr1.max);
!             if (val[3] == NULL_TREE)
!               sop = true;
!           }
! 
!         if (sop)
!           {
!             set_value_range_to_varying (vr);
!             return;
!           }
! 
!         /* Set MIN to the minimum of VAL[i] and MAX to the maximum
!            of VAL[i].  */
!         min = val[0];
!         max = val[0];
!         for (i = 1; i < 4; i++)
!           {
!             if (!is_gimple_min_invariant (min)
!                 || (TREE_OVERFLOW (min) && !is_overflow_infinity (min))
!                 || !is_gimple_min_invariant (max)
!                 || (TREE_OVERFLOW (max) && !is_overflow_infinity (max)))
!               break;
! 
!             if (val[i])
!               {
!                 if (!is_gimple_min_invariant (val[i])
!                     || (TREE_OVERFLOW (val[i])
!                         && !is_overflow_infinity (val[i])))
!                   {
!                     /* If we found an overflowed value, set MIN and MAX
!                        to it so that we set the resulting range to
!                        VARYING.  */
!                     min = max = val[i];
!                     break;
!                   }
! 
!                 if (compare_values (val[i], min) == -1)
!                   min = val[i];
! 
!                 if (compare_values (val[i], max) == 1)
!                   max = val[i];
!               }
!           }
        }
      }
    else if (code == TRUNC_MOD_EXPR)
--- 2651,2660 ----
              return;
            }
        }
        else
        {
!         extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
!         return;
        }
      }
    else if (code == TRUNC_MOD_EXPR)
*************** extract_range_from_binary_expr_1 (value_
*** 2733,2743 ****
          else
            max = min = NULL_TREE;
        }
-       else
-       {
-         set_value_range_to_varying (vr);
-         return;
-       }
      }
    else
      gcc_unreachable ();
--- 2800,2805 ----

Reply via email to