Multi-range implementation for value_range (irange).
authorAldy Hernandez <aldyh@redhat.com>
Thu, 30 Jul 2020 09:30:18 +0000 (11:30 +0200)
committerAldy Hernandez <aldyh@redhat.com>
Mon, 3 Aug 2020 06:39:29 +0000 (08:39 +0200)
Implement class irange, a generic multi-range implementation for
value ranges.  This class is API compatible with value_range, and is meant
to seamlessly coexist with it.

gcc/ChangeLog:

* Makefile.in (GTFILES): Move value-range.h up.
* gengtype-lex.l: Set yylval to handle GTY markers on templates.
* ipa-cp.c (initialize_node_lattices): Call value_range
constructor.
(ipcp_propagate_stage): Use in-place new so value_range construct
is called.
* ipa-fnsummary.c (evaluate_conditions_for_known_args): Use std
vec instead of GCC's vec<>.
(evaluate_properties_for_edge): Adjust for std vec.
(ipa_fn_summary_t::duplicate): Same.
(estimate_ipcp_clone_size_and_time): Same.
* ipa-prop.c (ipa_get_value_range): Use in-place new for
value_range.
* ipa-prop.h (struct GTY): Remove class keyword for m_vr.
* range-op.cc (empty_range_check): Rename to...
(empty_range_varying): ...this and adjust for varying.
(undefined_shift_range_check): Adjust for irange.
(range_operator::wi_fold): Same.
(range_operator::fold_range): Adjust for irange.  Special case
single pairs for performance.
(range_operator::op1_range): Adjust for irange.
(range_operator::op2_range): Same.
(value_range_from_overflowed_bounds): Same.
(value_range_with_overflow): Same.
(create_possibly_reversed_range): Same.
(range_true): Same.
(range_false): Same.
(range_true_and_false): Same.
(get_bool_state):  Adjust for irange and tweak for performance.
(operator_equal::fold_range): Adjust for irange.
(operator_equal::op1_range): Same.
(operator_equal::op2_range): Same.
(operator_not_equal::fold_range): Same.
(operator_not_equal::op1_range): Same.
(operator_not_equal::op2_range): Same.
(build_lt): Same.
(build_le): Same.
(build_gt): Same.
(build_ge): Same.
(operator_lt::fold_range): Same.
(operator_lt::op1_range): Same.
(operator_lt::op2_range): Same.
(operator_le::fold_range): Same.
(operator_le::op1_range): Same.
(operator_le::op2_range): Same.
(operator_gt::fold_range): Same.
(operator_gt::op1_range): Same.
(operator_gt::op2_range): Same.
(operator_ge::fold_range): Same.
(operator_ge::op1_range): Same.
(operator_ge::op2_range): Same.
(operator_plus::wi_fold): Same.
(operator_plus::op1_range): Same.
(operator_plus::op2_range): Same.
(operator_minus::wi_fold): Same.
(operator_minus::op1_range): Same.
(operator_minus::op2_range): Same.
(operator_min::wi_fold): Same.
(operator_max::wi_fold): Same.
(cross_product_operator::wi_cross_product): Same.
(operator_mult::op1_range): New.
(operator_mult::op2_range): New.
(operator_mult::wi_fold): Adjust for irange.
(operator_div::wi_fold): Same.
(operator_exact_divide::op1_range): Same.
(operator_lshift::fold_range): Same.
(operator_lshift::wi_fold): Same.
(operator_lshift::op1_range): New.
(operator_rshift::op1_range): New.
(operator_rshift::fold_range): Adjust for irange.
(operator_rshift::wi_fold): Same.
(operator_cast::truncating_cast_p): Abstract out from
operator_cast::fold_range.
(operator_cast::fold_range): Adjust for irange and tweak for
performance.
(operator_cast::inside_domain_p): Abstract out from fold_range.
(operator_cast::fold_pair): Same.
(operator_cast::op1_range): Use abstracted methods above.  Adjust
for irange and tweak for performance.
(operator_logical_and::fold_range): Adjust for irange.
(operator_logical_and::op1_range): Same.
(operator_logical_and::op2_range): Same.
(unsigned_singleton_p): New.
(operator_bitwise_and::remove_impossible_ranges): New.
(operator_bitwise_and::fold_range): New.
(wi_optimize_and_or):  Adjust for irange.
(operator_bitwise_and::wi_fold): Same.
(set_nonzero_range_from_mask): New.
(operator_bitwise_and::simple_op1_range_solver): New.
(operator_bitwise_and::op1_range): Adjust for irange.
(operator_bitwise_and::op2_range): Same.
(operator_logical_or::fold_range): Same.
(operator_logical_or::op1_range): Same.
(operator_logical_or::op2_range): Same.
(operator_bitwise_or::wi_fold): Same.
(operator_bitwise_or::op1_range): Same.
(operator_bitwise_or::op2_range): Same.
(operator_bitwise_xor::wi_fold): Same.
(operator_bitwise_xor::op1_range): New.
(operator_bitwise_xor::op2_range): New.
(operator_trunc_mod::wi_fold):  Adjust for irange.
(operator_logical_not::fold_range): Same.
(operator_logical_not::op1_range): Same.
(operator_bitwise_not::fold_range): Same.
(operator_bitwise_not::op1_range): Same.
(operator_cst::fold_range): Same.
(operator_identity::fold_range): Same.
(operator_identity::op1_range): Same.
(class operator_unknown): New.
(operator_unknown::fold_range): New.
(class operator_abs): Adjust for irange.
(operator_abs::wi_fold): Same.
(operator_abs::op1_range): Same.
(operator_absu::wi_fold): Same.
(class operator_negate): Same.
(operator_negate::fold_range): Same.
(operator_negate::op1_range): Same.
(operator_addr_expr::fold_range): Same.
(operator_addr_expr::op1_range): Same.
(pointer_plus_operator::wi_fold): Same.
(pointer_min_max_operator::wi_fold): Same.
(pointer_and_operator::wi_fold): Same.
(pointer_or_operator::op1_range): New.
(pointer_or_operator::op2_range): New.
(pointer_or_operator::wi_fold):  Adjust for irange.
(integral_table::integral_table): Add entries for IMAGPART_EXPR
and POINTER_DIFF_EXPR.
(range_cast):  Adjust for irange.
(build_range3): New.
(range3_tests): New.
(widest_irange_tests): New.
(multi_precision_range_tests): New.
(operator_tests): New.
(range_tests): New.
* range-op.h (class range_operator): Adjust for irange.
(range_cast): Same.
* tree-vrp.c (range_fold_binary_symbolics_p): Adjust for irange and
tweak for performance.
(range_fold_binary_expr): Same.
(masked_increment): Change to extern.
* tree-vrp.h (masked_increment): New.
* tree.c (cache_wide_int_in_type_cache): New function abstracted
out from wide_int_to_tree_1.
(wide_int_to_tree_1): Cache 0, 1, and MAX for pointers.
* value-range-equiv.cc (value_range_equiv::deep_copy): Use kind
method.
(value_range_equiv::move): Same.
(value_range_equiv::check): Adjust for irange.
(value_range_equiv::intersect): Same.
(value_range_equiv::union_): Same.
(value_range_equiv::dump): Same.
* value-range.cc (irange::operator=): Same.
(irange::maybe_anti_range): New.
(irange::copy_legacy_range): New.
(irange::set_undefined): Adjust for irange.
(irange::swap_out_of_order_endpoints): Abstract out from set().
(irange::set_varying): Adjust for irange.
(irange::irange_set): New.
(irange::irange_set_anti_range): New.
(irange::set): Adjust for irange.
(value_range::set_nonzero): Move to header file.
(value_range::set_zero): Move to header file.
(value_range::check): Rename to...
(irange::verify_range): ...this.
(value_range::num_pairs): Rename to...
(irange::legacy_num_pairs): ...this, and adjust for irange.
(value_range::lower_bound): Rename to...
(irange::legacy_lower_bound): ...this, and adjust for irange.
(value_range::upper_bound): Rename to...
(irange::legacy_upper_bound): ...this, and adjust for irange.
(value_range::equal_p): Rename to...
(irange::legacy_equal_p): ...this.
(value_range::operator==): Move to header file.
(irange::equal_p): New.
(irange::symbolic_p): Adjust for irange.
(irange::constant_p): Same.
(irange::singleton_p): Same.
(irange::value_inside_range): Same.
(irange::may_contain_p): Same.
(irange::contains_p): Same.
(irange::normalize_addresses): Same.
(irange::normalize_symbolics): Same.
(irange::legacy_intersect): Same.
(irange::legacy_union): Same.
(irange::union_): Same.
(irange::intersect): Same.
(irange::irange_union): New.
(irange::irange_intersect): New.
(subtract_one): New.
(irange::invert): Adjust for irange.
(dump_bound_with_infinite_markers): New.
(irange::dump): Adjust for irange.
(debug): Add irange versions.
(range_has_numeric_bounds_p): Adjust for irange.
(vrp_val_max): Move to header file.
(vrp_val_min): Move to header file.
(DEFINE_INT_RANGE_GC_STUBS): New.
(DEFINE_INT_RANGE_INSTANCE): New.
* value-range.h (class irange): New.
(class int_range): New.
(class value_range): Rename to a instantiation of int_range.
(irange::legacy_mode_p): New.
(value_range::value_range): Remove.
(irange::kind): New.
(irange::num_pairs): Adjust for irange.
(irange::type): Adjust for irange.
(irange::tree_lower_bound): New.
(irange::tree_upper_bound): New.
(irange::type): Adjust for irange.
(irange::min): Same.
(irange::max): Same.
(irange::varying_p): Same.
(irange::undefined_p): Same.
(irange::zero_p): Same.
(irange::nonzero_p): Same.
(irange::supports_type_p): Same.
(range_includes_zero_p): Same.
(gt_ggc_mx): New.
(gt_pch_nx): New.
(irange::irange): New.
(int_range::int_range): New.
(int_range::operator=): New.
(irange::set): Moved from value-range.cc and adjusted for irange.
(irange::set_undefined): Same.
(irange::set_varying): Same.
(irange::operator==): Same.
(irange::lower_bound): Same.
(irange::upper_bound): Same.
(irange::union_): Same.
(irange::intersect): Same.
(irange::set_nonzero): Same.
(irange::set_zero): Same.
(irange::normalize_min_max): New.
(vrp_val_max): Move from value-range.cc.
(vrp_val_min): Same.
* vr-values.c (vr_values::get_lattice_entry): Call value_range
constructor.

15 files changed:
gcc/Makefile.in
gcc/gengtype-lex.l
gcc/ipa-cp.c
gcc/ipa-fnsummary.c
gcc/ipa-prop.c
gcc/ipa-prop.h
gcc/range-op.cc
gcc/range-op.h
gcc/tree-vrp.c
gcc/tree-vrp.h
gcc/tree.c
gcc/value-range-equiv.cc
gcc/value-range.cc
gcc/value-range.h
gcc/vr-values.c

index 4208c6285b6de485b42b44bf911324aed24cd7b6..7251c007907e1e0093152a4c025cb909ff1c6b12 100644 (file)
@@ -2628,13 +2628,13 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/tree-ssa-alias.h \
   $(srcdir)/tree-ssanames.h \
   $(srcdir)/tree-vrp.h \
+  $(srcdir)/value-range.h \
   $(srcdir)/ipa-prop.h \
   $(srcdir)/trans-mem.c \
   $(srcdir)/lto-streamer.h \
   $(srcdir)/target-globals.h \
   $(srcdir)/ipa-predicate.h \
   $(srcdir)/ipa-fnsummary.h \
-  $(srcdir)/value-range.h \
   $(srcdir)/vtable-verify.c \
   $(srcdir)/asan.c \
   $(srcdir)/ubsan.c \
index a5e9d2b1de67ced370105e997d44d1824e183a51..9bf6ffa73c4d1641686a0824f0583e79a616b6da 100644 (file)
@@ -125,7 +125,10 @@ CXX_KEYWORD inline|public:|private:|protected:|template|operator|friend|static|m
 "ptr_alias"/{EOID}             { return PTR_ALIAS; }
 "nested_ptr"/{EOID}            { return NESTED_PTR; }
 "user"/{EOID}                  { return USER_GTY; }
-[0-9]+                         { return NUM; }
+[0-9]+                         {
+  *yylval = XDUPVAR (const char, yytext, yyleng, yyleng+1);
+  return NUM;
+}
 
 {IWORD}({WS}{IWORD})*/{EOID}           |
 "ENUM_BITFIELD"{WS}?"("{WS}?{ID}{WS}?")"       {
index fe010ff457cca5c18039b76c478302433328fb69..10cc59509d5bd814133fb700e58a4f1f0162ca86 100644 (file)
@@ -1270,6 +1270,7 @@ initialize_node_lattices (struct cgraph_node *node)
          plats->ctxlat.set_to_bottom ();
          set_agg_lats_to_bottom (plats);
          plats->bits_lattice.set_to_bottom ();
+         plats->m_value_range.m_vr = value_range ();
          plats->m_value_range.set_to_bottom ();
        }
       else
@@ -3898,8 +3899,10 @@ ipcp_propagate_stage (class ipa_topo_info *topo)
       {
         class ipa_node_params *info = IPA_NODE_REF (node);
         determine_versionability (node, info);
-       info->lattices = XCNEWVEC (class ipcp_param_lattices,
-                                  ipa_get_param_count (info));
+
+       unsigned nlattices = ipa_get_param_count (info);
+       void *chunk = XCNEWVEC (class ipcp_param_lattices, nlattices);
+       info->lattices = new (chunk) ipcp_param_lattices[nlattices];
        initialize_node_lattices (node);
       }
     ipa_size_summary *s = ipa_size_summaries->get (node);
index 55a0b272a96a1196ebf74c4f9fcb657fe07a553b..49bab04524b48d2664ef09b22619a9e9e220e0d0 100644 (file)
@@ -82,6 +82,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify.h"
 #include "stringpool.h"
 #include "attribs.h"
+#include <vector>
 #include "tree-into-ssa.h"
 
 /* Summaries.  */
@@ -330,7 +331,7 @@ static void
 evaluate_conditions_for_known_args (struct cgraph_node *node,
                                    bool inline_p,
                                    vec<tree> known_vals,
-                                   vec<value_range> known_value_ranges,
+                                   const std::vector<value_range> &known_value_ranges,
                                    vec<ipa_agg_value_set> known_aggs,
                                    clause_t *ret_clause,
                                    clause_t *ret_nonspec_clause)
@@ -445,7 +446,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
              continue;
            }
        }
-      if (c->operand_num < (int) known_value_ranges.length ()
+      if (c->operand_num < (int) known_value_ranges.size ()
          && !c->agg_contents
          && !known_value_ranges[c->operand_num].undefined_p ()
          && !known_value_ranges[c->operand_num].varying_p ()
@@ -554,7 +555,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
 {
   struct cgraph_node *callee = e->callee->ultimate_alias_target ();
   class ipa_fn_summary *info = ipa_fn_summaries->get (callee);
-  auto_vec<value_range, 32> known_value_ranges;
+  std::vector<value_range> known_value_ranges (32);
   class ipa_edge_args *args;
 
   if (clause_ptr)
@@ -629,8 +630,12 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
                                                                   i));
                    if (!vr.undefined_p () && !vr.varying_p ())
                      {
-                       if (!known_value_ranges.length ())
-                         known_value_ranges.safe_grow_cleared (count);
+                       if (!known_value_ranges.size ())
+                         {
+                           known_value_ranges.resize (count);
+                           for (int i = 0; i < count; ++i)
+                             known_value_ranges[i].set_undefined ();
+                         }
                        known_value_ranges[i] = vr;
                      }
                  }
@@ -803,7 +808,7 @@ ipa_fn_summary_t::duplicate (cgraph_node *src,
        }
       evaluate_conditions_for_known_args (dst, false,
                                          known_vals,
-                                         vNULL,
+                                         std::vector<value_range> (),
                                          vNULL,
                                          &possible_truths,
                                          /* We are going to specialize,
@@ -3687,7 +3692,8 @@ estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
   clause_t clause, nonspec_clause;
 
   /* TODO: Also pass known value ranges.  */
-  evaluate_conditions_for_known_args (node, false, known_vals, vNULL,
+  evaluate_conditions_for_known_args (node, false, known_vals,
+                                     std::vector<value_range> (),
                                      known_aggs, &clause, &nonspec_clause);
   ipa_call_context ctx (node, clause, nonspec_clause,
                        known_vals, known_contexts,
index 71ac0e104d240b41ceba6f453163a086d453740a..da50f0837fd73c7df3e729a34767280928e0ba1c 100644 (file)
@@ -2059,7 +2059,7 @@ ipa_get_value_range (value_range *tmp)
   if (*slot)
     return *slot;
 
-  value_range *vr = ggc_alloc<value_range> ();
+  value_range *vr = new (ggc_alloc<value_range> ()) value_range;
   *vr = *tmp;
   *slot = vr;
 
index 168c4c264430ef6dd8c4d5dfefabd424ed1c01ce..23fcf905ef353e8ec6003c8cd32c6f9fa4f7f013 100644 (file)
@@ -318,7 +318,7 @@ struct GTY (()) ipa_jump_func
   /* Information about value range, containing valid data only when vr_known is
      true.  The pointed to structure is shared betweed different jump
      functions.  Use ipa_set_jfunc_vr to set this field.  */
-  class value_range *m_vr;
+  value_range *m_vr;
 
   enum jump_func_type type;
   /* Represents a value of a jump function.  pass_through is used only in jump
index 5df075b15b5a5b8d637b7b1eb3b5a14eb65f9464..c62e3977ce535e2acdae7a68058e773130170b5d 100644 (file)
@@ -63,15 +63,17 @@ min_limit (const_tree type)
 }
 
 // If the range of either op1 or op2 is undefined, set the result to
-// undefined and return TRUE.
+// varying and return TRUE.  If the caller truely cares about a result,
+// they should pass in a varying if it has an undefined that it wants
+// treated as a varying.
 
 inline bool
-empty_range_check (value_range &r,
-                  const value_range &op1, const value_range & op2)
+empty_range_varying (irange &r, tree type,
+                    const irange &op1, const irange & op2)
 {
   if (op1.undefined_p () || op2.undefined_p ())
     {
-      r.set_undefined ();
+      r.set_varying (type);
       return true;
     }
   else
@@ -82,11 +84,11 @@ empty_range_check (value_range &r,
 // the appropriate range.
 
 static inline bool
-undefined_shift_range_check (value_range &r, tree type, const value_range op)
+undefined_shift_range_check (irange &r, tree type, const irange &op)
 {
   if (op.undefined_p ())
     {
-      r = value_range ();
+      r.set_undefined ();
       return true;
     }
 
@@ -98,7 +100,7 @@ undefined_shift_range_check (value_range &r, tree type, const value_range op)
       || wi::ge_p (op.upper_bound (),
                   TYPE_PRECISION (type), TYPE_SIGN (op.type ())))
     {
-      r = value_range (type);
+      r.set_varying (type);
       return true;
     }
   return false;
@@ -125,32 +127,43 @@ wi_zero_p (tree type, const wide_int &wmin, const wide_int &wmax)
 // Default wide_int fold operation returns [MIN, MAX].
 
 void
-range_operator::wi_fold (value_range &r, tree type,
+range_operator::wi_fold (irange &r, tree type,
                         const wide_int &lh_lb ATTRIBUTE_UNUSED,
                         const wide_int &lh_ub ATTRIBUTE_UNUSED,
                         const wide_int &rh_lb ATTRIBUTE_UNUSED,
                         const wide_int &rh_ub ATTRIBUTE_UNUSED) const
 {
-  gcc_checking_assert (value_range::supports_type_p (type));
-  r = value_range (type);
+  gcc_checking_assert (irange::supports_type_p (type));
+  r.set_varying (type);
 }
 
 // The default for fold is to break all ranges into sub-ranges and
 // invoke the wi_fold method on each sub-range pair.
 
 bool
-range_operator::fold_range (value_range &r, tree type,
-                           const value_range &lh,
-                           const value_range &rh) const
+range_operator::fold_range (irange &r, tree type,
+                           const irange &lh,
+                           const irange &rh) const
 {
-  gcc_checking_assert (value_range::supports_type_p (type));
-  if (empty_range_check (r, lh, rh))
+  gcc_checking_assert (irange::supports_type_p (type));
+  if (empty_range_varying (r, type, lh, rh))
     return true;
 
-  value_range tmp;
+  unsigned num_lh = lh.num_pairs ();
+  unsigned num_rh = rh.num_pairs ();
+
+  // If both ranges are single pairs, fold directly into the result range.
+  if (num_lh == 1 && num_rh == 1)
+    {
+      wi_fold (r, type, lh.lower_bound (0), lh.upper_bound (0),
+              rh.lower_bound (0), rh.upper_bound (0));
+      return true;
+    }
+
+  widest_irange tmp;
   r.set_undefined ();
-  for (unsigned x = 0; x < lh.num_pairs (); ++x)
-    for (unsigned y = 0; y < rh.num_pairs (); ++y)
+  for (unsigned x = 0; x < num_lh; ++x)
+    for (unsigned y = 0; y < num_rh; ++y)
       {
        wide_int lh_lb = lh.lower_bound (x);
        wide_int lh_ub = lh.upper_bound (x);
@@ -167,10 +180,10 @@ range_operator::fold_range (value_range &r, tree type,
 // The default for op1_range is to return false.
 
 bool
-range_operator::op1_range (value_range &r ATTRIBUTE_UNUSED,
+range_operator::op1_range (irange &r ATTRIBUTE_UNUSED,
                           tree type ATTRIBUTE_UNUSED,
-                          const value_range &lhs ATTRIBUTE_UNUSED,
-                          const value_range &op2 ATTRIBUTE_UNUSED) const
+                          const irange &lhs ATTRIBUTE_UNUSED,
+                          const irange &op2 ATTRIBUTE_UNUSED) const
 {
   return false;
 }
@@ -178,10 +191,10 @@ range_operator::op1_range (value_range &r ATTRIBUTE_UNUSED,
 // The default for op2_range is to return false.
 
 bool
-range_operator::op2_range (value_range &r ATTRIBUTE_UNUSED,
+range_operator::op2_range (irange &r ATTRIBUTE_UNUSED,
                           tree type ATTRIBUTE_UNUSED,
-                          const value_range &lhs ATTRIBUTE_UNUSED,
-                          const value_range &op1 ATTRIBUTE_UNUSED) const
+                          const irange &lhs ATTRIBUTE_UNUSED,
+                          const irange &op1 ATTRIBUTE_UNUSED) const
 {
   return false;
 }
@@ -191,7 +204,7 @@ range_operator::op2_range (value_range &r ATTRIBUTE_UNUSED,
 // to have overflowed (or underflowed).
 
 static void
-value_range_from_overflowed_bounds (value_range &r, tree type,
+value_range_from_overflowed_bounds (irange &r, tree type,
                                    const wide_int &wmin,
                                    const wide_int &wmax)
 {
@@ -214,9 +227,13 @@ value_range_from_overflowed_bounds (value_range &r, tree type,
   // Likewise if the anti-range bounds are outside of the types
   // values.
   if (covers || wi::cmp (tmin, tmax, sgn) > 0)
-    r = value_range (type);
+    r.set_varying (type);
   else
-    r = value_range (type, tmin, tmax, VR_ANTI_RANGE);
+    {
+      tree tree_min = wide_int_to_tree (type, tmin);
+      tree tree_max = wide_int_to_tree (type, tmax);
+      r.set (tree_min, tree_max, VR_ANTI_RANGE);
+    }
 }
 
 // Create and return a range from a pair of wide-ints.  MIN_OVF and
@@ -224,7 +241,7 @@ value_range_from_overflowed_bounds (value_range &r, tree type,
 // calculating WMIN and WMAX respectively.
 
 static void
-value_range_with_overflow (value_range &r, tree type,
+value_range_with_overflow (irange &r, tree type,
                           const wide_int &wmin, const wide_int &wmax,
                           wi::overflow_type min_ovf = wi::OVF_NONE,
                           wi::overflow_type max_ovf = wi::OVF_NONE)
@@ -237,7 +254,7 @@ value_range_with_overflow (value_range &r, tree type,
   // values.
   if (prec == 1 && wi::ne_p (wmax, wmin))
     {
-      r = value_range (type);
+      r.set_varying (type);
       return;
     }
 
@@ -252,11 +269,12 @@ value_range_with_overflow (value_range &r, tree type,
          // If the limits are swapped, we wrapped around and cover
          // the entire range.
          if (wi::gt_p (tmin, tmax, sgn))
-           r = value_range (type);
+           r.set_varying (type);
          else
            // No overflow or both overflow or underflow.  The range
            // kind stays normal.
-           r = value_range (type, tmin, tmax);
+           r.set (wide_int_to_tree (type, tmin),
+                  wide_int_to_tree (type, tmax));
          return;
        }
 
@@ -265,7 +283,7 @@ value_range_with_overflow (value_range &r, tree type,
        value_range_from_overflowed_bounds (r, type, wmin, wmax);
       else
        // Other underflow and/or overflow, drop to VR_VARYING.
-       r = value_range (type);
+       r.set_varying (type);
     }
   else
     {
@@ -285,7 +303,8 @@ value_range_with_overflow (value_range &r, tree type,
       else
         new_ub = wmax;
 
-      r = value_range (type, new_lb, new_ub);
+      r.set (wide_int_to_tree (type, new_lb),
+            wide_int_to_tree (type, new_ub));
     }
 }
 
@@ -294,7 +313,7 @@ value_range_with_overflow (value_range &r, tree type,
 // [10,5] into [MIN,5][10,MAX].
 
 static inline void
-create_possibly_reversed_range (value_range &r, tree type,
+create_possibly_reversed_range (irange &r, tree type,
                                const wide_int &new_lb, const wide_int &new_ub)
 {
   signop s = TYPE_SIGN (type);
@@ -302,35 +321,35 @@ create_possibly_reversed_range (value_range &r, tree type,
   if (wi::gt_p (new_lb, new_ub, s))
     value_range_from_overflowed_bounds (r, type, new_lb, new_ub);
   else
-    // Otherwise its just a normal range.
-    r = value_range (type, new_lb, new_ub);
+    // Otherwise it's just a normal range.
+    r.set (wide_int_to_tree (type, new_lb), wide_int_to_tree (type, new_ub));
 }
 
-// Return a value_range instance that is a boolean TRUE.
+// Return an irange instance that is a boolean TRUE.
 
-static inline value_range
+static inline int_range<1>
 range_true (tree type)
 {
   unsigned prec = TYPE_PRECISION (type);
-  return value_range (type, wi::one (prec), wi::one (prec));
+  return int_range<1> (type, wi::one (prec), wi::one (prec));
 }
 
-// Return a value_range instance that is a boolean FALSE.
+// Return an irange instance that is a boolean FALSE.
 
-static inline value_range
+static inline int_range<1>
 range_false (tree type)
 {
   unsigned prec = TYPE_PRECISION (type);
-  return value_range (type, wi::zero (prec), wi::zero (prec));
+  return int_range<1> (type, wi::zero (prec), wi::zero (prec));
 }
 
-// Return a value_range that covers both true and false.
+// Return an irange that covers both true and false.
 
-static inline value_range
+static inline int_range<1>
 range_true_and_false (tree type)
 {
   unsigned prec = TYPE_PRECISION (type);
-  return value_range (type, wi::zero (prec), wi::one (prec));
+  return int_range<1> (type, wi::zero (prec), wi::one (prec));
 }
 
 enum bool_range_state { BRS_FALSE, BRS_TRUE, BRS_EMPTY, BRS_FULL };
@@ -341,7 +360,7 @@ enum bool_range_state { BRS_FALSE, BRS_TRUE, BRS_EMPTY, BRS_FULL };
 // the bool range.
 
 static bool_range_state
-get_bool_state (value_range &r, const value_range &lhs, tree val_type)
+get_bool_state (irange &r, const irange &lhs, tree val_type)
 {
   // If there is no result, then this is unexecutable.
   if (lhs.undefined_p ())
@@ -350,16 +369,16 @@ get_bool_state (value_range &r, const value_range &lhs, tree val_type)
       return BRS_EMPTY;
     }
 
-  // If the bounds aren't the same, then it's not a constant.
-  if (!wi::eq_p (lhs.upper_bound (), lhs.lower_bound ()))
+  if (lhs.zero_p ())
+    return BRS_FALSE;
+
+  // For TRUE, we can't just test for [1,1] because Ada can have
+  // multi-bit booleans, and TRUE values can be: [1, MAX], ~[0], etc.
+  if (lhs.contains_p (build_zero_cst (lhs.type ())))
     {
       r.set_varying (val_type);
       return BRS_FULL;
     }
-
-  if (lhs.zero_p ())
-    return BRS_FALSE;
-
   return BRS_TRUE;
 }
 
@@ -367,23 +386,23 @@ get_bool_state (value_range &r, const value_range &lhs, tree val_type)
 class operator_equal : public range_operator
 {
 public:
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &op1,
-                          const value_range &op2) const;
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &val) const;
-  virtual bool op2_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &val) const;
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &op1,
+                          const irange &op2) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &val) const;
+  virtual bool op2_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &val) const;
 } op_equal;
 
 bool
-operator_equal::fold_range (value_range &r, tree type,
-                           const value_range &op1,
-                           const value_range &op2) const
+operator_equal::fold_range (irange &r, tree type,
+                           const irange &op1,
+                           const irange &op2) const
 {
-  if (empty_range_check (r, op1, op2))
+  if (empty_range_varying (r, type, op1, op2))
     return true;
 
   // We can be sure the values are always equal or not if both ranges
@@ -411,9 +430,9 @@ operator_equal::fold_range (value_range &r, tree type,
 }
 
 bool
-operator_equal::op1_range (value_range &r, tree type,
-                          const value_range &lhs,
-                          const value_range &op2) const
+operator_equal::op1_range (irange &r, tree type,
+                          const irange &lhs,
+                          const irange &op2) const
 {
   switch (get_bool_state (r, lhs, type))
     {
@@ -441,9 +460,9 @@ operator_equal::op1_range (value_range &r, tree type,
 }
 
 bool
-operator_equal::op2_range (value_range &r, tree type,
-                          const value_range &lhs,
-                          const value_range &op1) const
+operator_equal::op2_range (irange &r, tree type,
+                          const irange &lhs,
+                          const irange &op1) const
 {
   return operator_equal::op1_range (r, type, lhs, op1);
 }
@@ -452,23 +471,23 @@ operator_equal::op2_range (value_range &r, tree type,
 class operator_not_equal : public range_operator
 {
 public:
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &op1,
-                          const value_range &op2) const;
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
-  virtual bool op2_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op1) const;
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &op1,
+                          const irange &op2) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
+  virtual bool op2_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op1) const;
 } op_not_equal;
 
 bool
-operator_not_equal::fold_range (value_range &r, tree type,
-                               const value_range &op1,
-                               const value_range &op2) const
+operator_not_equal::fold_range (irange &r, tree type,
+                               const irange &op1,
+                               const irange &op2) const
 {
-  if (empty_range_check (r, op1, op2))
+  if (empty_range_varying (r, type, op1, op2))
     return true;
 
   // We can be sure the values are always equal or not if both ranges
@@ -496,9 +515,9 @@ operator_not_equal::fold_range (value_range &r, tree type,
 }
 
 bool
-operator_not_equal::op1_range (value_range &r, tree type,
-                              const value_range &lhs,
-                              const value_range &op2) const
+operator_not_equal::op1_range (irange &r, tree type,
+                              const irange &lhs,
+                              const irange &op2) const
 {
   switch (get_bool_state (r, lhs, type))
     {
@@ -527,9 +546,9 @@ operator_not_equal::op1_range (value_range &r, tree type,
 
 
 bool
-operator_not_equal::op2_range (value_range &r, tree type,
-                              const value_range &lhs,
-                              const value_range &op1) const
+operator_not_equal::op2_range (irange &r, tree type,
+                              const irange &lhs,
+                              const irange &op1) const
 {
   return operator_not_equal::op1_range (r, type, lhs, op1);
 }
@@ -537,7 +556,7 @@ operator_not_equal::op2_range (value_range &r, tree type,
 // (X < VAL) produces the range of [MIN, VAL - 1].
 
 static void
-build_lt (value_range &r, tree type, const wide_int &val)
+build_lt (irange &r, tree type, const wide_int &val)
 {
   wi::overflow_type ov;
   wide_int lim = wi::sub (val, 1, TYPE_SIGN (type), &ov);
@@ -546,21 +565,21 @@ build_lt (value_range &r, tree type, const wide_int &val)
   if (ov)
     r.set_undefined ();
   else
-    r = value_range (type, min_limit (type), lim);
+    r = int_range<1> (type, min_limit (type), lim);
 }
 
 // (X <= VAL) produces the range of [MIN, VAL].
 
 static void
-build_le (value_range &r, tree type, const wide_int &val)
+build_le (irange &r, tree type, const wide_int &val)
 {
-  r = value_range (type, min_limit (type), val);
+  r = int_range<1> (type, min_limit (type), val);
 }
 
 // (X > VAL) produces the range of [VAL + 1, MAX].
 
 static void
-build_gt (value_range &r, tree type, const wide_int &val)
+build_gt (irange &r, tree type, const wide_int &val)
 {
   wi::overflow_type ov;
   wide_int lim = wi::add (val, 1, TYPE_SIGN (type), &ov);
@@ -568,38 +587,38 @@ build_gt (value_range &r, tree type, const wide_int &val)
   if (ov)
     r.set_undefined ();
   else
-    r = value_range (type, lim, max_limit (type));
+    r = int_range<1> (type, lim, max_limit (type));
 }
 
 // (X >= val) produces the range of [VAL, MAX].
 
 static void
-build_ge (value_range &r, tree type, const wide_int &val)
+build_ge (irange &r, tree type, const wide_int &val)
 {
-  r = value_range (type, val, max_limit (type));
+  r = int_range<1> (type, val, max_limit (type));
 }
 
 
 class operator_lt :  public range_operator
 {
 public:
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &op1,
-                          const value_range &op2) const;
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
-  virtual bool op2_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op1) const;
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &op1,
+                          const irange &op2) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
+  virtual bool op2_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op1) const;
 } op_lt;
 
 bool
-operator_lt::fold_range (value_range &r, tree type,
-                        const value_range &op1,
-                        const value_range &op2) const
+operator_lt::fold_range (irange &r, tree type,
+                        const irange &op1,
+                        const irange &op2) const
 {
-  if (empty_range_check (r, op1, op2))
+  if (empty_range_varying (r, type, op1, op2))
     return true;
 
   signop sign = TYPE_SIGN (op1.type ());
@@ -615,9 +634,9 @@ operator_lt::fold_range (value_range &r, tree type,
 }
 
 bool
-operator_lt::op1_range (value_range &r, tree type,
-                       const value_range &lhs,
-                       const value_range &op2) const
+operator_lt::op1_range (irange &r, tree type,
+                       const irange &lhs,
+                       const irange &op2) const
 {
   switch (get_bool_state (r, lhs, type))
     {
@@ -636,9 +655,9 @@ operator_lt::op1_range (value_range &r, tree type,
 }
 
 bool
-operator_lt::op2_range (value_range &r, tree type,
-                       const value_range &lhs,
-                       const value_range &op1) const
+operator_lt::op2_range (irange &r, tree type,
+                       const irange &lhs,
+                       const irange &op1) const
 {
   switch (get_bool_state (r, lhs, type))
     {
@@ -660,23 +679,23 @@ operator_lt::op2_range (value_range &r, tree type,
 class operator_le :  public range_operator
 {
 public:
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &op1,
-                          const value_range &op2) const;
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
-  virtual bool op2_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op1) const;
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &op1,
+                          const irange &op2) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
+  virtual bool op2_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op1) const;
 } op_le;
 
 bool
-operator_le::fold_range (value_range &r, tree type,
-                        const value_range &op1,
-                        const value_range &op2) const
+operator_le::fold_range (irange &r, tree type,
+                        const irange &op1,
+                        const irange &op2) const
 {
-  if (empty_range_check (r, op1, op2))
+  if (empty_range_varying (r, type, op1, op2))
     return true;
 
   signop sign = TYPE_SIGN (op1.type ());
@@ -692,9 +711,9 @@ operator_le::fold_range (value_range &r, tree type,
 }
 
 bool
-operator_le::op1_range (value_range &r, tree type,
-                       const value_range &lhs,
-                       const value_range &op2) const
+operator_le::op1_range (irange &r, tree type,
+                       const irange &lhs,
+                       const irange &op2) const
 {
   switch (get_bool_state (r, lhs, type))
     {
@@ -713,9 +732,9 @@ operator_le::op1_range (value_range &r, tree type,
 }
 
 bool
-operator_le::op2_range (value_range &r, tree type,
-                       const value_range &lhs,
-                       const value_range &op1) const
+operator_le::op2_range (irange &r, tree type,
+                       const irange &lhs,
+                       const irange &op1) const
 {
   switch (get_bool_state (r, lhs, type))
     {
@@ -737,22 +756,22 @@ operator_le::op2_range (value_range &r, tree type,
 class operator_gt :  public range_operator
 {
 public:
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &op1,
-                          const value_range &op2) const;
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
-  virtual bool op2_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op1) const;
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &op1,
+                          const irange &op2) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
+  virtual bool op2_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op1) const;
 } op_gt;
 
 bool
-operator_gt::fold_range (value_range &r, tree type,
-                        const value_range &op1, const value_range &op2) const
+operator_gt::fold_range (irange &r, tree type,
+                        const irange &op1, const irange &op2) const
 {
-  if (empty_range_check (r, op1, op2))
+  if (empty_range_varying (r, type, op1, op2))
     return true;
 
   signop sign = TYPE_SIGN (op1.type ());
@@ -768,8 +787,8 @@ operator_gt::fold_range (value_range &r, tree type,
 }
 
 bool
-operator_gt::op1_range (value_range &r, tree type,
-                       const value_range &lhs, const value_range &op2) const
+operator_gt::op1_range (irange &r, tree type,
+                       const irange &lhs, const irange &op2) const
 {
   switch (get_bool_state (r, lhs, type))
     {
@@ -788,9 +807,9 @@ operator_gt::op1_range (value_range &r, tree type,
 }
 
 bool
-operator_gt::op2_range (value_range &r, tree type,
-                       const value_range &lhs,
-                       const value_range &op1) const
+operator_gt::op2_range (irange &r, tree type,
+                       const irange &lhs,
+                       const irange &op1) const
 {
   switch (get_bool_state (r, lhs, type))
     {
@@ -812,23 +831,23 @@ operator_gt::op2_range (value_range &r, tree type,
 class operator_ge :  public range_operator
 {
 public:
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &op1,
-                          const value_range &op2) const;
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
-  virtual bool op2_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op1) const;
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &op1,
+                          const irange &op2) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
+  virtual bool op2_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op1) const;
 } op_ge;
 
 bool
-operator_ge::fold_range (value_range &r, tree type,
-                        const value_range &op1,
-                        const value_range &op2) const
+operator_ge::fold_range (irange &r, tree type,
+                        const irange &op1,
+                        const irange &op2) const
 {
-  if (empty_range_check (r, op1, op2))
+  if (empty_range_varying (r, type, op1, op2))
     return true;
 
   signop sign = TYPE_SIGN (op1.type ());
@@ -844,9 +863,9 @@ operator_ge::fold_range (value_range &r, tree type,
 }
 
 bool
-operator_ge::op1_range (value_range &r, tree type,
-                       const value_range &lhs,
-                       const value_range &op2) const
+operator_ge::op1_range (irange &r, tree type,
+                       const irange &lhs,
+                       const irange &op2) const
 {
   switch (get_bool_state (r, lhs, type))
     {
@@ -865,9 +884,9 @@ operator_ge::op1_range (value_range &r, tree type,
 }
 
 bool
-operator_ge::op2_range (value_range &r, tree type,
-                       const value_range &lhs,
-                       const value_range &op1) const
+operator_ge::op2_range (irange &r, tree type,
+                       const irange &lhs,
+                       const irange &op1) const
 {
   switch (get_bool_state (r, lhs, type))
     {
@@ -889,13 +908,13 @@ operator_ge::op2_range (value_range &r, tree type,
 class operator_plus : public range_operator
 {
 public:
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
-  virtual bool op2_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op1) const;
-  virtual void wi_fold (value_range &r, tree type,
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
+  virtual bool op2_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op1) const;
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
                        const wide_int &lh_ub,
                        const wide_int &rh_lb,
@@ -903,7 +922,7 @@ public:
 } op_plus;
 
 void
-operator_plus::wi_fold (value_range &r, tree type,
+operator_plus::wi_fold (irange &r, tree type,
                        const wide_int &lh_lb, const wide_int &lh_ub,
                        const wide_int &rh_lb, const wide_int &rh_ub) const
 {
@@ -915,17 +934,17 @@ operator_plus::wi_fold (value_range &r, tree type,
 }
 
 bool
-operator_plus::op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const
+operator_plus::op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const
 {
   return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op2);
 }
 
 bool
-operator_plus::op2_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op1) const
+operator_plus::op2_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op1) const
 {
   return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op1);
 }
@@ -934,13 +953,13 @@ operator_plus::op2_range (value_range &r, tree type,
 class operator_minus : public range_operator
 {
 public:
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
-  virtual bool op2_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op1) const;
-  virtual void wi_fold (value_range &r, tree type,
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
+  virtual bool op2_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op1) const;
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
                        const wide_int &lh_ub,
                        const wide_int &rh_lb,
@@ -948,7 +967,7 @@ public:
 } op_minus;
 
 void 
-operator_minus::wi_fold (value_range &r, tree type,
+operator_minus::wi_fold (irange &r, tree type,
                         const wide_int &lh_lb, const wide_int &lh_ub,
                         const wide_int &rh_lb, const wide_int &rh_ub) const
 {
@@ -960,17 +979,17 @@ operator_minus::wi_fold (value_range &r, tree type,
 }
 
 bool
-operator_minus::op1_range (value_range &r, tree type,
-                          const value_range &lhs,
-                          const value_range &op2) const
+operator_minus::op1_range (irange &r, tree type,
+                          const irange &lhs,
+                          const irange &op2) const
 {
   return range_op_handler (PLUS_EXPR, type)->fold_range (r, type, lhs, op2);
 }
 
 bool
-operator_minus::op2_range (value_range &r, tree type,
-                          const value_range &lhs,
-                          const value_range &op1) const
+operator_minus::op2_range (irange &r, tree type,
+                          const irange &lhs,
+                          const irange &op1) const
 {
   return fold_range (r, type, op1, lhs);
 }
@@ -979,7 +998,7 @@ operator_minus::op2_range (value_range &r, tree type,
 class operator_min : public range_operator
 {
 public:
-  virtual void wi_fold (value_range &r, tree type,
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
                        const wide_int &lh_ub,
                        const wide_int &rh_lb,
@@ -987,7 +1006,7 @@ public:
 } op_min;
 
 void
-operator_min::wi_fold (value_range &r, tree type,
+operator_min::wi_fold (irange &r, tree type,
                       const wide_int &lh_lb, const wide_int &lh_ub,
                       const wide_int &rh_lb, const wide_int &rh_ub) const
 {
@@ -1001,7 +1020,7 @@ operator_min::wi_fold (value_range &r, tree type,
 class operator_max : public range_operator
 {
 public:
-  virtual void wi_fold (value_range &r, tree type,
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
                        const wide_int &lh_ub,
                        const wide_int &rh_lb,
@@ -1009,7 +1028,7 @@ public:
 } op_max;
 
 void
-operator_max::wi_fold (value_range &r, tree type,
+operator_max::wi_fold (irange &r, tree type,
                       const wide_int &lh_lb, const wide_int &lh_ub,
                       const wide_int &rh_lb, const wide_int &rh_ub) const
 {
@@ -1031,7 +1050,7 @@ public:
                                const wide_int &) const = 0;
 
   // Calculate the cross product of two sets of sub-ranges and return it.
-  void wi_cross_product (value_range &r, tree type,
+  void wi_cross_product (irange &r, tree type,
                         const wide_int &lh_lb,
                         const wide_int &lh_ub,
                         const wide_int &rh_lb,
@@ -1052,7 +1071,7 @@ public:
 // figure the smallest and largest values to form the new range.
 
 void
-cross_product_operator::wi_cross_product (value_range &r, tree type,
+cross_product_operator::wi_cross_product (irange &r, tree type,
                                          const wide_int &lh_lb,
                                          const wide_int &lh_ub,
                                          const wide_int &rh_lb,
@@ -1060,7 +1079,7 @@ cross_product_operator::wi_cross_product (value_range &r, tree type,
 {
   wide_int cp1, cp2, cp3, cp4;
   // Default to varying.
-  r = value_range (type);
+  r.set_varying (type);
 
   // Compute the 4 cross operations, bailing if we get an overflow we
   // can't handle.
@@ -1096,15 +1115,46 @@ cross_product_operator::wi_cross_product (value_range &r, tree type,
 class operator_mult : public cross_product_operator
 {
 public:
-  virtual void wi_fold (value_range &r, tree type,
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
                        const wide_int &lh_ub,
                        const wide_int &rh_lb,
                        const wide_int &rh_ub) const;
   virtual bool wi_op_overflows (wide_int &res, tree type,
                                const wide_int &w0, const wide_int &w1) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
+  virtual bool op2_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op1) const;
 } op_mult;
 
+bool
+operator_mult::op1_range (irange &r, tree type,
+                         const irange &lhs, const irange &op2) const
+{
+  tree offset;
+
+  // We can't solve 0 = OP1 * N by dividing by N with a wrapping type.
+  // For example: For 0 = OP1 * 2, OP1 could be 0, or MAXINT, whereas
+  // for 4 = OP1 * 2, OP1 could be 2 or 130 (unsigned 8-bit)
+  if (TYPE_OVERFLOW_WRAPS (type))
+    return false;
+
+  if (op2.singleton_p (&offset) && !integer_zerop (offset))
+    return range_op_handler (TRUNC_DIV_EXPR, type)->fold_range (r, type,
+                                                               lhs, op2);
+  return false;
+}
+
+bool
+operator_mult::op2_range (irange &r, tree type,
+                         const irange &lhs, const irange &op1) const
+{
+  return operator_mult::op1_range (r, type, lhs, op1);
+}
+
 bool
 operator_mult::wi_op_overflows (wide_int &res, tree type,
                                const wide_int &w0, const wide_int &w1) const
@@ -1126,7 +1176,7 @@ operator_mult::wi_op_overflows (wide_int &res, tree type,
 }
 
 void 
-operator_mult::wi_fold (value_range &r, tree type,
+operator_mult::wi_fold (irange &r, tree type,
                        const wide_int &lh_lb, const wide_int &lh_ub,
                        const wide_int &rh_lb, const wide_int &rh_ub) const
 {
@@ -1195,7 +1245,7 @@ operator_mult::wi_fold (value_range &r, tree type,
   prod2 = prod3 - prod0;
   if (wi::geu_p (prod2, sizem1))
     // The range covers all values.
-    r = value_range (type);
+    r.set_varying (type);
   else
     {
       wide_int new_lb = wide_int::from (prod0, prec, sign);
@@ -1209,7 +1259,7 @@ class operator_div : public cross_product_operator
 {
 public:
   operator_div (enum tree_code c)  { code = c; }
-  virtual void wi_fold (value_range &r, tree type,
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
                        const wide_int &lh_ub,
                        const wide_int &rh_lb,
@@ -1263,14 +1313,14 @@ operator_div::wi_op_overflows (wide_int &res, tree type,
 }
 
 void
-operator_div::wi_fold (value_range &r, tree type,
+operator_div::wi_fold (irange &r, tree type,
                       const wide_int &lh_lb, const wide_int &lh_ub,
                       const wide_int &rh_lb, const wide_int &rh_ub) const
 {
   // If we know we will divide by zero, return undefined.
   if (rh_lb == 0 && rh_ub == 0)
     {
-      r = value_range ();
+      r.set_undefined ();
       return;
     }
 
@@ -1293,14 +1343,14 @@ operator_div::wi_fold (value_range &r, tree type,
   // If flag_non_call_exceptions, we must not eliminate a division by zero.
   if (cfun->can_throw_non_call_exceptions)
     {
-      r = value_range (type);
+      r.set_varying (type);
       return;
     }
 
   // If we're definitely dividing by zero, there's nothing to do.
   if (wi_zero_p (type, divisor_min, divisor_max))
     {
-      r = value_range ();
+      r.set_undefined ();
       return;
     }
 
@@ -1312,12 +1362,12 @@ operator_div::wi_fold (value_range &r, tree type,
     wi_cross_product (r, type, dividend_min, dividend_max,
                      divisor_min, wi::minus_one (prec));
   else
-    r = value_range ();
+    r.set_undefined ();
 
   // Then divide by the non-zero positive numbers, if any.
   if (wi::gt_p (divisor_max, wi::zero (prec), sign))
     {
-      value_range tmp;
+      widest_irange tmp;
       wi_cross_product (tmp, type, dividend_min, dividend_max,
                        wi::one (prec), divisor_max);
       r.union_ (tmp);
@@ -1336,16 +1386,16 @@ class operator_exact_divide : public operator_div
 {
 public:
   operator_exact_divide () : operator_div (TRUNC_DIV_EXPR) { }
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
 
 } op_exact_div;
 
 bool
-operator_exact_divide::op1_range (value_range &r, tree type,
-                                 const value_range &lhs,
-                                 const value_range &op2) const
+operator_exact_divide::op1_range (irange &r, tree type,
+                                 const irange &lhs,
+                                 const irange &op2) const
 {
   tree offset;
   // [2, 4] = op1 / [3,3]   since its exact divide, no need to worry about
@@ -1364,11 +1414,14 @@ operator_exact_divide::op1_range (value_range &r, tree type,
 class operator_lshift : public cross_product_operator
 {
 public:
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &op1,
-                          const value_range &op2) const;
-
-  virtual void wi_fold (value_range &r, tree type,
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &op1,
+                          const irange &op2) const;
+
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb, const wide_int &lh_ub,
                        const wide_int &rh_lb, const wide_int &rh_ub) const;
   virtual bool wi_op_overflows (wide_int &res,
@@ -1378,9 +1431,9 @@ public:
 } op_lshift;
 
 bool
-operator_lshift::fold_range (value_range &r, tree type,
-                            const value_range &op1,
-                            const value_range &op2) const
+operator_lshift::fold_range (irange &r, tree type,
+                            const irange &op1,
+                            const irange &op2) const
 {
   if (undefined_shift_range_check (r, type, op2))
     return true;
@@ -1390,15 +1443,14 @@ operator_lshift::fold_range (value_range &r, tree type,
     {
       unsigned shift = op2.lower_bound ().to_uhwi ();
       wide_int tmp = wi::set_bit_in_zero (shift, TYPE_PRECISION (type));
-      value_range mult (type, tmp, tmp);
+      int_range<1> mult (type, tmp, tmp);
 
       // Force wrapping multiplication.
       bool saved_flag_wrapv = flag_wrapv;
       bool saved_flag_wrapv_pointer = flag_wrapv_pointer;
       flag_wrapv = 1;
       flag_wrapv_pointer = 1;
-      bool b = range_op_handler (MULT_EXPR, type)->fold_range (r, type, op1,
-                                                              mult);
+      bool b = op_mult.fold_range (r, type, op1, mult);
       flag_wrapv = saved_flag_wrapv;
       flag_wrapv_pointer = saved_flag_wrapv_pointer;
       return b;
@@ -1409,7 +1461,7 @@ operator_lshift::fold_range (value_range &r, tree type,
 }
 
 void
-operator_lshift::wi_fold (value_range &r, tree type,
+operator_lshift::wi_fold (irange &r, tree type,
                          const wide_int &lh_lb, const wide_int &lh_ub,
                          const wide_int &rh_lb, const wide_int &rh_ub) const
 {
@@ -1465,7 +1517,7 @@ operator_lshift::wi_fold (value_range &r, tree type,
   if (in_bounds)
     wi_cross_product (r, type, lh_lb, lh_ub, rh_lb, rh_ub);
   else
-   r = value_range (type);
+   r.set_varying (type);
 }
 
 bool
@@ -1485,14 +1537,56 @@ operator_lshift::wi_op_overflows (wide_int &res, tree type,
   return false;
 }
 
+bool
+operator_lshift::op1_range (irange &r,
+                           tree type,
+                           const irange &lhs,
+                           const irange &op2) const
+{
+  tree shift_amount;
+  if (op2.singleton_p (&shift_amount))
+    {
+      int_range<1> shifted (shift_amount, shift_amount), ub, lb;
+      const range_operator *rshift_op = range_op_handler (RSHIFT_EXPR, type);
+      rshift_op->fold_range (ub, type, lhs, shifted);
+      if (TYPE_UNSIGNED (type))
+       {
+         r = ub;
+         return true;
+       }
+      // For signed types, we can't just do an arithmetic rshift,
+      // because that will propagate the sign bit.
+      //
+      //  LHS
+      // 1110 = OP1 << 1
+      //
+      // Assuming a 4-bit signed integer, a right shift will result in
+      // OP1=1111, but OP1 could have also been 0111.  What we want is
+      // a range from 0111 to 1111.  That is, a range from the logical
+      // rshift (0111) to the arithmetic rshift (1111).
+      //
+      // Perform a logical rshift by doing the rshift as unsigned.
+      tree unsigned_type = unsigned_type_for (type);
+      widest_irange unsigned_lhs = lhs;
+      range_cast (unsigned_lhs, unsigned_type);
+      rshift_op = range_op_handler (RSHIFT_EXPR, unsigned_type);
+      rshift_op->fold_range (lb, unsigned_type, unsigned_lhs, shifted);
+      range_cast (lb, type);
+      r = lb;
+      r.union_ (ub);
+      return true;
+    }
+  return false;
+}
+
 
 class operator_rshift : public cross_product_operator
 {
 public:
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &op1,
-                          const value_range &op2) const;
-  virtual void wi_fold (value_range &r, tree type,
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &op1,
+                          const irange &op2) const;
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
                        const wide_int &lh_ub,
                        const wide_int &rh_lb,
@@ -1501,8 +1595,57 @@ public:
                                tree type,
                                const wide_int &w0,
                                const wide_int &w1) const;
+  virtual bool op1_range (irange &, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
 } op_rshift;
 
+bool
+operator_rshift::op1_range (irange &r,
+                           tree type,
+                           const irange &lhs,
+                           const irange &op2) const
+{
+  tree shift;
+  if (op2.singleton_p (&shift))
+    {
+      // Folding the original operation may discard some impossible
+      // ranges from the LHS.
+      widest_irange lhs_refined;
+      op_rshift.fold_range (lhs_refined, type, int_range<1> (type), op2);
+      lhs_refined.intersect (lhs);
+      if (lhs_refined.undefined_p ())
+       {
+         r.set_undefined ();
+         return true;
+       }
+      widest_irange shift_range (shift, shift);
+      widest_irange lb, ub;
+      op_lshift.fold_range (lb, type, lhs_refined, shift_range);
+      //    LHS
+      // 0000 0111 = OP1 >> 3
+      //
+      // OP1 is anything from 0011 1000 to 0011 1111.  That is, a
+      // range from LHS<<3 plus a mask of the 3 bits we shifted on the
+      // right hand side (0x07).
+      tree mask = fold_build1 (BIT_NOT_EXPR, type,
+                              fold_build2 (LSHIFT_EXPR, type,
+                                           build_minus_one_cst (type),
+                                           shift));
+      widest_irange mask_range (build_zero_cst (type), mask);
+      op_plus.fold_range (ub, type, lb, mask_range);
+      r = lb;
+      r.union_ (ub);
+      if (!lhs_refined.contains_p (build_zero_cst (type)))
+       {
+         mask_range.invert ();
+         r.intersect (mask_range);
+       }
+      return true;
+    }
+  return false;
+}
+
 bool
 operator_rshift::wi_op_overflows (wide_int &res,
                                  tree type,
@@ -1523,9 +1666,9 @@ operator_rshift::wi_op_overflows (wide_int &res,
 }
 
 bool
-operator_rshift::fold_range (value_range &r, tree type,
-                            const value_range &op1,
-                            const value_range &op2) const
+operator_rshift::fold_range (irange &r, tree type,
+                            const irange &op1,
+                            const irange &op2) const
 {
   // Invoke the generic fold routine if not undefined..
   if (undefined_shift_range_check (r, type, op2))
@@ -1535,7 +1678,7 @@ operator_rshift::fold_range (value_range &r, tree type,
 }
 
 void
-operator_rshift::wi_fold (value_range &r, tree type,
+operator_rshift::wi_fold (irange &r, tree type,
                          const wide_int &lh_lb, const wide_int &lh_ub,
                          const wide_int &rh_lb, const wide_int &rh_ub) const
 {
@@ -1546,139 +1689,180 @@ operator_rshift::wi_fold (value_range &r, tree type,
 class operator_cast: public range_operator
 {
 public:
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &op1,
-                          const value_range &op2) const;
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
-
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &op1,
+                          const irange &op2) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
+private:
+  bool truncating_cast_p (const irange &inner, const irange &outer) const;
+  bool inside_domain_p (const wide_int &min, const wide_int &max,
+                       const irange &outer) const;
+  void fold_pair (irange &r, unsigned index, const irange &inner,
+                          const irange &outer) const;
 } op_convert;
 
+// Return TRUE if casting from INNER to OUTER is a truncating cast.
+
+inline bool
+operator_cast::truncating_cast_p (const irange &inner,
+                                 const irange &outer) const
+{
+  return TYPE_PRECISION (outer.type ()) < TYPE_PRECISION (inner.type ());
+}
+
+// Return TRUE if [MIN,MAX] is inside the domain of RANGE's type.
+
 bool
-operator_cast::fold_range (value_range &r, tree type ATTRIBUTE_UNUSED,
-                          const value_range &lh,
-                          const value_range &rh) const
+operator_cast::inside_domain_p (const wide_int &min,
+                               const wide_int &max,
+                               const irange &range) const
 {
-  if (empty_range_check (r, lh, rh))
-    return true;
-  
-  tree inner = lh.type ();
-  tree outer = rh.type ();
-  gcc_checking_assert (rh.varying_p ());
-  gcc_checking_assert (types_compatible_p (outer, type));
-  signop inner_sign = TYPE_SIGN (inner);
-  signop outer_sign = TYPE_SIGN (outer);
-  unsigned inner_prec = TYPE_PRECISION (inner);
-  unsigned outer_prec = TYPE_PRECISION (outer);
-
-  // Start with an empty range and add subranges.
-  r = value_range ();
-  for (unsigned x = 0; x < lh.num_pairs (); ++x)
-    {
-      wide_int lh_lb = lh.lower_bound (x);
-      wide_int lh_ub = lh.upper_bound (x);
-
-      // If the conversion is not truncating we can convert the min
-      // and max values and canonicalize the resulting range.
-      // Otherwise, we can do the conversion if the size of the range
-      // is less than what the precision of the target type can
-      // represent.
-      if (outer_prec >= inner_prec
-         || wi::rshift (wi::sub (lh_ub, lh_lb),
-                        wi::uhwi (outer_prec, inner_prec),
-                        inner_sign) == 0)
+  wide_int domain_min = wi::to_wide (vrp_val_min (range.type ()));
+  wide_int domain_max = wi::to_wide (vrp_val_max (range.type ()));
+  signop domain_sign = TYPE_SIGN (range.type ());
+  return (wi::le_p (min, domain_max, domain_sign)
+         && wi::le_p (max, domain_max, domain_sign)
+         && wi::ge_p (min, domain_min, domain_sign)
+         && wi::ge_p (max, domain_min, domain_sign));
+}
+
+
+// Helper for fold_range which work on a pair at a time.
+
+void
+operator_cast::fold_pair (irange &r, unsigned index,
+                          const irange &inner,
+                          const irange &outer) const
+{
+  tree inner_type = inner.type ();
+  tree outer_type = outer.type ();
+  signop inner_sign = TYPE_SIGN (inner_type);
+  unsigned outer_prec = TYPE_PRECISION (outer_type);
+
+  // check to see if casting from INNER to OUTER is a conversion that
+  // fits in the resulting OUTER type.
+  wide_int inner_lb = inner.lower_bound (index);
+  wide_int inner_ub = inner.upper_bound (index);
+  if (truncating_cast_p (inner, outer))
+    {
+      // We may be able to accomodate a truncating cast if the
+      // resulting range can be represented in the target type...
+      if (wi::rshift (wi::sub (inner_ub, inner_lb),
+                     wi::uhwi (outer_prec, TYPE_PRECISION (inner.type ())),
+                               inner_sign) != 0)
        {
-         wide_int min = wide_int::from (lh_lb, outer_prec, inner_sign);
-         wide_int max = wide_int::from (lh_ub, outer_prec, inner_sign);
-         if (!wi::eq_p (min, wi::min_value (outer_prec, outer_sign))
-             || !wi::eq_p (max, wi::max_value (outer_prec, outer_sign)))
-           {
-             value_range tmp;
-             create_possibly_reversed_range (tmp, type, min, max);
-             r.union_ (tmp);
-             continue;
-           }
+         r.set_varying (outer_type);
+         return;
        }
-      r = value_range (type);
-      break;
+    }
+  // ...but we must still verify that the final range fits in the
+  // domain.  This catches -fstrict-enum restrictions where the domain
+  // range is smaller than what fits in the underlying type.
+  wide_int min = wide_int::from (inner_lb, outer_prec, inner_sign);
+  wide_int max = wide_int::from (inner_ub, outer_prec, inner_sign);
+  if (inside_domain_p (min, max, outer))
+    create_possibly_reversed_range (r, outer_type, min, max);
+  else
+    r.set_varying (outer_type);
+}
+
+
+bool
+operator_cast::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
+                          const irange &inner,
+                          const irange &outer) const
+{
+  if (empty_range_varying (r, type, inner, outer))
+    return true;
+
+  gcc_checking_assert (outer.varying_p ());
+  gcc_checking_assert (inner.num_pairs () > 0);
+
+  // Avoid a temporary by folding the first pair directly into the result.
+  fold_pair (r, 0, inner, outer);
+
+  // Then process any additonal pairs by unioning with their results.
+  for (unsigned x = 1; x < inner.num_pairs (); ++x)
+    {
+      widest_irange tmp;
+      fold_pair (tmp, x, inner, outer);
+      r.union_ (tmp);
+      if (r.varying_p ())
+       return true;
     }
   return true;
 }
 
 bool
-operator_cast::op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const
+operator_cast::op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const
 {
   tree lhs_type = lhs.type ();
-  value_range tmp;
   gcc_checking_assert (types_compatible_p (op2.type(), type));
 
-  // If the precision of the LHS is smaller than the precision of the
-  // RHS, then there would be truncation of the value on the RHS, and
-  // so we can tell nothing about it.
-  if (TYPE_PRECISION (lhs_type) < TYPE_PRECISION (type))
-    {
-      // If we've been passed an actual value for the RHS rather than
-      // the type, see if it fits the LHS, and if so, then we can allow
-      // it.
-      fold_range (r, lhs_type, op2, value_range (lhs_type));
-      fold_range (tmp, type, r, value_range (type));
-      if (tmp == op2)
+  if (truncating_cast_p (op2, lhs))
+    {
+      if (lhs.varying_p ())
+       r.set_varying (type);
+      else
         {
-         // We know the value of the RHS fits in the LHS type, so
-         // convert the LHS and remove any values that arent in OP2.
-         fold_range (r, type, lhs, value_range (type));
-         r.intersect (op2);
-         return true;
-       }
-      // Special case if the LHS is a boolean.  A 0 means the RHS is
-      // zero, and a 1 means the RHS is non-zero.
-      if (TREE_CODE (lhs_type) == BOOLEAN_TYPE)
-       {
-         // If the LHS is unknown, the result is whatever op2 already is.
-         if (!lhs.singleton_p ())
-           {
-             r = op2;
-             return true;
-           }
-         // Boolean casts are weird in GCC. It's actually an implied
-         // mask with 0x01, so all that is known is whether the
-         // rightmost bit is 0 or 1, which implies the only value
-         // *not* in the RHS is 0 or -1.
-         unsigned prec = TYPE_PRECISION (type);
-         if (lhs.zero_p ())
-           r = value_range (type, wi::minus_one (prec), wi::minus_one (prec),
-                            VR_ANTI_RANGE);
-         else
-           r = value_range (type, wi::zero (prec), wi::zero (prec),
-                            VR_ANTI_RANGE);
-         // And intersect it with what we know about op2.
-         r.intersect (op2);
+         // We want to insert the LHS as an unsigned value since it
+         // would not trigger the signed bit of the larger type.
+         widest_irange converted_lhs = lhs;
+         range_cast (converted_lhs, unsigned_type_for (lhs_type));
+         range_cast (converted_lhs, type);
+         // Start by building the positive signed outer range for the type.
+         wide_int lim = wi::set_bit_in_zero (TYPE_PRECISION (lhs_type),
+                                             TYPE_PRECISION (type));
+         r = int_range<1> (type, lim, wi::max_value (TYPE_PRECISION (type),
+                                                     SIGNED));
+         // For the signed part, we need to simply union the 2 ranges now.
+         r.union_ (converted_lhs);
+
+         // Create maximal negative number outside of LHS bits.
+         lim = wi::mask (TYPE_PRECISION (lhs_type), true,
+                         TYPE_PRECISION (type));
+         // Add this to the unsigned LHS range(s).
+         widest_irange lim_range (type, lim, lim);
+         widest_irange lhs_neg;
+         range_op_handler (PLUS_EXPR, type)->fold_range (lhs_neg,
+                                                         type,
+                                                         converted_lhs,
+                                                         lim_range);
+         // And union this with the entire outer types negative range.
+         widest_irange neg (type,
+                            wi::min_value (TYPE_PRECISION (type),
+                                           SIGNED),
+                            lim - 1);
+         neg.union_ (lhs_neg);
+         // And finally, munge the signed and unsigned portions.
+         r.union_ (neg);
        }
-      else
-       // Otherwise we'll have to assume it's whatever we know about op2.
-       r = op2;
+      // And intersect with any known value passed in the extra operand.
+      r.intersect (op2);
       return true;
     }
 
-  // If the LHS precision is greater than the rhs precision, the LHS
-  // range is restricted to the range of the RHS by this
-  // assignment.
-  if (TYPE_PRECISION (lhs_type) > TYPE_PRECISION (type))
+  widest_irange tmp;
+  if (TYPE_PRECISION (lhs_type) == TYPE_PRECISION (type))
+    tmp = lhs;
+  else
     {
+      // The cast is not truncating, and the range is restricted to
+      // the range of the RHS by this assignment.
+      //
       // Cast the range of the RHS to the type of the LHS.
-      fold_range (tmp, lhs_type, value_range (type), value_range (lhs_type));
-      // Intersect this with the LHS range will produce the range, which
-      // will be cast to the RHS type before returning.
+      fold_range (tmp, lhs_type, int_range<1> (type), int_range<1> (lhs_type));
+      // Intersect this with the LHS range will produce the range,
+      // which will be cast to the RHS type before returning.
       tmp.intersect (lhs);
     }
-  else
-    tmp = lhs;
 
   // Cast the calculated range to the type of the RHS.
-  fold_range (r, type, tmp, value_range (type));
+  fold_range (r, type, tmp, int_range<1> (type));
   return true;
 }
 
@@ -1686,24 +1870,24 @@ operator_cast::op1_range (value_range &r, tree type,
 class operator_logical_and : public range_operator
 {
 public:
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &lh,
-                          const value_range &rh) const;
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
-  virtual bool op2_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op1) const;
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &lh,
+                          const irange &rh) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
+  virtual bool op2_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op1) const;
 } op_logical_and;
 
 
 bool
-operator_logical_and::fold_range (value_range &r, tree type,
-                                 const value_range &lh,
-                                 const value_range &rh) const
+operator_logical_and::fold_range (irange &r, tree type,
+                                 const irange &lh,
+                                 const irange &rh) const
 {
-  if (empty_range_check (r, lh, rh))
+  if (empty_range_varying (r, type, lh, rh))
     return true;
 
   // 0 && anything is 0.
@@ -1721,9 +1905,9 @@ operator_logical_and::fold_range (value_range &r, tree type,
 }
 
 bool
-operator_logical_and::op1_range (value_range &r, tree type,
-                                const value_range &lhs,
-                                const value_range &op2 ATTRIBUTE_UNUSED) const
+operator_logical_and::op1_range (irange &r, tree type,
+                                const irange &lhs,
+                                const irange &op2 ATTRIBUTE_UNUSED) const
 {
    switch (get_bool_state (r, lhs, type))
      {
@@ -1742,9 +1926,9 @@ operator_logical_and::op1_range (value_range &r, tree type,
 }
 
 bool
-operator_logical_and::op2_range (value_range &r, tree type,
-                                const value_range &lhs,
-                                const value_range &op1) const
+operator_logical_and::op2_range (irange &r, tree type,
+                                const irange &lhs,
+                                const irange &op1) const
 {
   return operator_logical_and::op1_range (r, type, lhs, op1);
 }
@@ -1753,19 +1937,106 @@ operator_logical_and::op2_range (value_range &r, tree type,
 class operator_bitwise_and : public range_operator
 {
 public:
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
-  virtual bool op2_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op1) const;
-  virtual void wi_fold (value_range &r, tree type,
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &lh,
+                          const irange &rh) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
+  virtual bool op2_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op1) const;
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
                        const wide_int &lh_ub,
                        const wide_int &rh_lb,
                        const wide_int &rh_ub) const;
+private:
+  void simple_op1_range_solver (irange &r, tree type,
+                               const irange &lhs,
+                               const irange &op2) const;
+  void remove_impossible_ranges (irange &r, const irange &rh) const;
 } op_bitwise_and;
 
+static bool
+unsigned_singleton_p (const irange &op)
+{
+  tree mask;
+  if (op.singleton_p (&mask))
+    {
+      wide_int x = wi::to_wide (mask);
+      return wi::ge_p (x, 0, TYPE_SIGN (op.type ()));
+    }
+  return false;
+}
+
+// Remove any ranges from R that are known to be impossible when an
+// range is ANDed with MASK.
+
+void
+operator_bitwise_and::remove_impossible_ranges (irange &r,
+                                               const irange &rmask) const
+{
+  if (r.undefined_p () || !unsigned_singleton_p (rmask))
+    return;
+
+  wide_int mask = rmask.lower_bound ();
+  tree type = r.type ();
+  int prec = TYPE_PRECISION (type);
+  int leading_zeros = wi::clz (mask);
+  widest_irange impossible_ranges;
+
+  /* We know that starting at the most significant bit, any 0 in the
+     mask means the resulting range cannot contain a 1 in that same
+     position.  This means the following ranges are impossible:
+
+       x & 0b1001 1010
+                         IMPOSSIBLE RANGES
+             01xx xxxx   [0100 0000, 0111 1111]
+             001x xxxx   [0010 0000, 0011 1111]
+             0000 01xx   [0000 0100, 0000 0111]
+             0000 0001   [0000 0001, 0000 0001]
+  */
+  wide_int one = wi::one (prec);
+  for (int i = 0; i < prec - leading_zeros - 1; ++i)
+    if (wi::bit_and (mask, wi::lshift (one, wi::uhwi (i, prec))) == 0)
+      {
+       tree lb = fold_build2 (LSHIFT_EXPR, type,
+                              build_one_cst (type),
+                              build_int_cst (type, i));
+       tree ub_left = fold_build1 (BIT_NOT_EXPR, type,
+                                   fold_build2 (LSHIFT_EXPR, type,
+                                                build_minus_one_cst (type),
+                                                build_int_cst (type, i)));
+       tree ub_right = fold_build2 (LSHIFT_EXPR, type,
+                                    build_one_cst (type),
+                                    build_int_cst (type, i));
+       tree ub = fold_build2 (BIT_IOR_EXPR, type, ub_left, ub_right);
+       impossible_ranges.union_ (int_range<1> (lb, ub));
+      }
+  if (!impossible_ranges.undefined_p ())
+    {
+      impossible_ranges.invert ();
+      r.intersect (impossible_ranges);
+    }
+}
+
+bool
+operator_bitwise_and::fold_range (irange &r, tree type,
+                                 const irange &lh,
+                                 const irange &rh) const
+{
+  if (range_operator::fold_range (r, type, lh, rh))
+    {
+      // FIXME: This is temporarily disabled because, though it
+      // generates better ranges, it's noticeably slower for evrp.
+      // remove_impossible_ranges (r, rh);
+      return true;
+    }
+  return false;
+}
+
+
 // Optimize BIT_AND_EXPR and BIT_IOR_EXPR in terms of a mask if
 // possible.  Basically, see if we can optimize:
 //
@@ -1777,7 +2048,7 @@ public:
 // return TRUE.
 
 static bool
-wi_optimize_and_or (value_range &r,
+wi_optimize_and_or (irange &r,
                    enum tree_code code,
                    tree type,
                    const wide_int &lh_lb, const wide_int &lh_ub,
@@ -1886,7 +2157,7 @@ wi_set_zero_nonzero_bits (tree type,
 }
 
 void
-operator_bitwise_and::wi_fold (value_range &r, tree type,
+operator_bitwise_and::wi_fold (irange &r, tree type,
                               const wide_int &lh_lb,
                               const wide_int &lh_ub,
                               const wide_int &rh_lb,
@@ -1938,29 +2209,128 @@ operator_bitwise_and::wi_fold (value_range &r, tree type,
     }
   // If the limits got swapped around, return varying.
   if (wi::gt_p (new_lb, new_ub,sign))
-    r = value_range (type);
+    r.set_varying (type);
   else
     value_range_with_overflow (r, type, new_lb, new_ub);
 }
 
+static void
+set_nonzero_range_from_mask (irange &r, tree type, const irange &lhs)
+{
+  if (!lhs.contains_p (build_zero_cst (type)))
+    r = range_nonzero (type);
+  else
+    r.set_varying (type);
+}
+
+// This was shamelessly stolen from register_edge_assert_for_2 and
+// adjusted to work with iranges.
+
+void
+operator_bitwise_and::simple_op1_range_solver (irange &r, tree type,
+                                              const irange &lhs,
+                                              const irange &op2) const
+{
+  if (!op2.singleton_p ())
+    {
+      set_nonzero_range_from_mask (r, type, lhs);
+      return;
+    }
+  unsigned int nprec = TYPE_PRECISION (type);
+  wide_int cst2v = op2.lower_bound ();
+  bool cst2n = wi::neg_p (cst2v, TYPE_SIGN (type));
+  wide_int sgnbit;
+  if (cst2n)
+    sgnbit = wi::set_bit_in_zero (nprec - 1, nprec);
+  else
+    sgnbit = wi::zero (nprec);
+
+  // Solve [lhs.lower_bound (), +INF] = x & MASK.
+  //
+  // Minimum unsigned value for >= if (VAL & CST2) == VAL is VAL and
+  // maximum unsigned value is ~0.  For signed comparison, if CST2
+  // doesn't have the most significant bit set, handle it similarly.  If
+  // CST2 has MSB set, the minimum is the same, and maximum is ~0U/2.
+  wide_int valv = lhs.lower_bound ();
+  wide_int minv = valv & cst2v, maxv;
+  bool we_know_nothing = false;
+  if (minv != valv)
+    {
+      // If (VAL & CST2) != VAL, X & CST2 can't be equal to VAL.
+      minv = masked_increment (valv, cst2v, sgnbit, nprec);
+      if (minv == valv)
+       {
+         // If we can't determine anything on this bound, fall
+         // through and conservatively solve for the other end point.
+         we_know_nothing = true;
+       }
+    }
+  maxv = wi::mask (nprec - (cst2n ? 1 : 0), false, nprec);
+  if (we_know_nothing)
+    r.set_varying (type);
+  else
+    r = int_range<1> (type, minv, maxv);
+
+  // Solve [-INF, lhs.upper_bound ()] = x & MASK.
+  //
+  // Minimum unsigned value for <= is 0 and maximum unsigned value is
+  // VAL | ~CST2 if (VAL & CST2) == VAL.  Otherwise, find smallest
+  // VAL2 where
+  // VAL2 > VAL && (VAL2 & CST2) == VAL2 and use (VAL2 - 1) | ~CST2
+  // as maximum.
+  // For signed comparison, if CST2 doesn't have most significant bit
+  // set, handle it similarly.  If CST2 has MSB set, the maximum is
+  // the same and minimum is INT_MIN.
+  valv = lhs.upper_bound ();
+  minv = valv & cst2v;
+  if (minv == valv)
+    maxv = valv;
+  else
+    {
+      maxv = masked_increment (valv, cst2v, sgnbit, nprec);
+      if (maxv == valv)
+       {
+         // If we couldn't determine anything on either bound, return
+         // undefined.
+         if (we_know_nothing)
+           r.set_undefined ();
+         return;
+       }
+      maxv -= 1;
+    }
+  maxv |= ~cst2v;
+  minv = sgnbit;
+  int_range<1> upper_bits (type, minv, maxv);
+  r.intersect (upper_bits);
+}
+
 bool
-operator_bitwise_and::op1_range (value_range &r, tree type,
-                                const value_range &lhs,
-                                const value_range &op2) const
+operator_bitwise_and::op1_range (irange &r, tree type,
+                                const irange &lhs,
+                                const irange &op2) const
 {
-  // If this is really a logical wi_fold, call that.
   if (types_compatible_p (type, boolean_type_node))
     return op_logical_and.op1_range (r, type, lhs, op2);
 
-  // For now do nothing with bitwise AND of value_range's.
-  r.set_varying (type);
+  r.set_undefined ();
+  for (unsigned i = 0; i < lhs.num_pairs (); ++i)
+    {
+      widest_irange chunk (lhs.type (),
+                          lhs.lower_bound (i),
+                          lhs.upper_bound (i));
+      widest_irange res;
+      simple_op1_range_solver (res, type, chunk, op2);
+      r.union_ (res);
+    }
+  if (r.undefined_p ())
+    set_nonzero_range_from_mask (r, type, lhs);
   return true;
 }
 
 bool
-operator_bitwise_and::op2_range (value_range &r, tree type,
-                                const value_range &lhs,
-                                const value_range &op1) const
+operator_bitwise_and::op2_range (irange &r, tree type,
+                                const irange &lhs,
+                                const irange &op1) const
 {
   return operator_bitwise_and::op1_range (r, type, lhs, op1);
 }
@@ -1969,23 +2339,23 @@ operator_bitwise_and::op2_range (value_range &r, tree type,
 class operator_logical_or : public range_operator
 {
 public:
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &lh,
-                          const value_range &rh) const;
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
-  virtual bool op2_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op1) const;
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &lh,
+                          const irange &rh) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
+  virtual bool op2_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op1) const;
 } op_logical_or;
 
 bool
-operator_logical_or::fold_range (value_range &r, tree type ATTRIBUTE_UNUSED,
-                                const value_range &lh,
-                                const value_range &rh) const
+operator_logical_or::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
+                                const irange &lh,
+                                const irange &rh) const
 {
-  if (empty_range_check (r, lh, rh))
+  if (empty_range_varying (r, type, lh, rh))
     return true;
 
   r = lh;
@@ -1994,9 +2364,9 @@ operator_logical_or::fold_range (value_range &r, tree type ATTRIBUTE_UNUSED,
 }
 
 bool
-operator_logical_or::op1_range (value_range &r, tree type,
-                               const value_range &lhs,
-                               const value_range &op2 ATTRIBUTE_UNUSED) const
+operator_logical_or::op1_range (irange &r, tree type,
+                               const irange &lhs,
+                               const irange &op2 ATTRIBUTE_UNUSED) const
 {
    switch (get_bool_state (r, lhs, type))
      {
@@ -2015,9 +2385,9 @@ operator_logical_or::op1_range (value_range &r, tree type,
 }
 
 bool
-operator_logical_or::op2_range (value_range &r, tree type,
-                               const value_range &lhs,
-                               const value_range &op1) const
+operator_logical_or::op2_range (irange &r, tree type,
+                               const irange &lhs,
+                               const irange &op1) const
 {
   return operator_logical_or::op1_range (r, type, lhs, op1);
 }
@@ -2026,13 +2396,13 @@ operator_logical_or::op2_range (value_range &r, tree type,
 class operator_bitwise_or : public range_operator
 {
 public:
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
-  virtual bool op2_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op1) const;
-  virtual void wi_fold (value_range &r, tree type,
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
+  virtual bool op2_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op1) const;
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
                        const wide_int &lh_ub,
                        const wide_int &rh_lb,
@@ -2040,7 +2410,7 @@ public:
 } op_bitwise_or;
 
 void
-operator_bitwise_or::wi_fold (value_range &r, tree type,
+operator_bitwise_or::wi_fold (irange &r, tree type,
                              const wide_int &lh_lb,
                              const wide_int &lh_ub,
                              const wide_int &rh_lb,
@@ -2076,29 +2446,34 @@ operator_bitwise_or::wi_fold (value_range &r, tree type,
     new_lb = wi::max (new_lb, rh_lb, sign);
   // If the limits got swapped around, return varying.
   if (wi::gt_p (new_lb, new_ub,sign))
-    r = value_range (type);
+    r.set_varying (type);
   else
     value_range_with_overflow (r, type, new_lb, new_ub);
 }
 
 bool
-operator_bitwise_or::op1_range (value_range &r, tree type,
-                               const value_range &lhs,
-                               const value_range &op2) const
+operator_bitwise_or::op1_range (irange &r, tree type,
+                               const irange &lhs,
+                               const irange &op2) const
 {
   // If this is really a logical wi_fold, call that.
   if (types_compatible_p (type, boolean_type_node))
     return op_logical_or.op1_range (r, type, lhs, op2);
 
-  // For now do nothing with bitwise OR of value_range's.
+  if (lhs.zero_p ())
+    {
+      tree zero = build_zero_cst (type);
+      r = int_range<1> (zero, zero);
+      return true;
+    }
   r.set_varying (type);
   return true;
 }
 
 bool
-operator_bitwise_or::op2_range (value_range &r, tree type,
-                               const value_range &lhs,
-                               const value_range &op1) const
+operator_bitwise_or::op2_range (irange &r, tree type,
+                               const irange &lhs,
+                               const irange &op1) const
 {
   return operator_bitwise_or::op1_range (r, type, lhs, op1);
 }
@@ -2107,15 +2482,21 @@ operator_bitwise_or::op2_range (value_range &r, tree type,
 class operator_bitwise_xor : public range_operator
 {
 public:
-  virtual void wi_fold (value_range &r, tree type,
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
                        const wide_int &lh_ub,
                        const wide_int &rh_lb,
                        const wide_int &rh_ub) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
+  virtual bool op2_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op1) const;
 } op_bitwise_xor;
 
 void
-operator_bitwise_xor::wi_fold (value_range &r, tree type,
+operator_bitwise_xor::wi_fold (irange &r, tree type,
                               const wide_int &lh_lb,
                               const wide_int &lh_ub,
                               const wide_int &rh_lb,
@@ -2142,14 +2523,55 @@ operator_bitwise_xor::wi_fold (value_range &r, tree type,
   if (wi::lt_p (new_lb, 0, sign) || wi::ge_p (new_ub, 0, sign))
     value_range_with_overflow (r, type, new_lb, new_ub);
   else
-    r = value_range (type);
+    r.set_varying (type);
+}
+
+bool
+operator_bitwise_xor::op1_range (irange &r, tree type,
+                                const irange &lhs,
+                                const irange &op2) const
+{
+  if (lhs.undefined_p () || lhs.varying_p ())
+    {
+      r = lhs;
+      return true;
+    }
+  if (types_compatible_p (type, boolean_type_node))
+    {
+      switch (get_bool_state (r, lhs, type))
+       {
+       case BRS_TRUE:
+         if (op2.varying_p ())
+           r.set_varying (type);
+         else if (op2.zero_p ())
+           r = range_true (type);
+         else
+           r = range_false (type);
+         break;
+       case BRS_FALSE:
+         r = op2;
+         break;
+       default:
+         gcc_unreachable ();
+       }
+      return true;
+    }
+  r.set_varying (type);
+  return true;
 }
 
+bool
+operator_bitwise_xor::op2_range (irange &r, tree type,
+                                const irange &lhs,
+                                const irange &op1) const
+{
+  return operator_bitwise_xor::op1_range (r, type, lhs, op1);
+}
 
 class operator_trunc_mod : public range_operator
 {
 public:
-  virtual void wi_fold (value_range &r, tree type,
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
                        const wide_int &lh_ub,
                        const wide_int &rh_lb,
@@ -2157,7 +2579,7 @@ public:
 } op_trunc_mod;
 
 void
-operator_trunc_mod::wi_fold (value_range &r, tree type,
+operator_trunc_mod::wi_fold (irange &r, tree type,
                             const wide_int &lh_lb,
                             const wide_int &lh_ub,
                             const wide_int &rh_lb,
@@ -2170,7 +2592,7 @@ operator_trunc_mod::wi_fold (value_range &r, tree type,
   // Mod 0 is undefined.  Return undefined.
   if (wi_zero_p (type, rh_lb, rh_ub))
     {
-      r = value_range ();
+      r.set_undefined ();
       return;
     }
 
@@ -2204,12 +2626,12 @@ operator_trunc_mod::wi_fold (value_range &r, tree type,
 class operator_logical_not : public range_operator
 {
 public:
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &lh,
-                          const value_range &rh) const;
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &lh,
+                          const irange &rh) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
 } op_logical_not;
 
 // Folding a logical NOT, oddly enough, involves doing nothing on the
@@ -2227,11 +2649,11 @@ public:
 //   which is the result we are looking for.. so.. pass it through.
 
 bool
-operator_logical_not::fold_range (value_range &r, tree type,
-                                 const value_range &lh,
-                                 const value_range &rh ATTRIBUTE_UNUSED) const
+operator_logical_not::fold_range (irange &r, tree type,
+                                 const irange &lh,
+                                 const irange &rh ATTRIBUTE_UNUSED) const
 {
-  if (empty_range_check (r, lh, rh))
+  if (empty_range_varying (r, type, lh, rh))
     return true;
 
   if (lh.varying_p () || lh.undefined_p ())
@@ -2246,10 +2668,10 @@ operator_logical_not::fold_range (value_range &r, tree type,
 }
 
 bool
-operator_logical_not::op1_range (value_range &r,
+operator_logical_not::op1_range (irange &r,
                                 tree type ATTRIBUTE_UNUSED,
-                                const value_range &lhs,
-                                const value_range &op2 ATTRIBUTE_UNUSED) const
+                                const irange &lhs,
+                                const irange &op2 ATTRIBUTE_UNUSED) const
 {
   r = lhs;
   if (!lhs.varying_p () && !lhs.undefined_p ())
@@ -2261,33 +2683,33 @@ operator_logical_not::op1_range (value_range &r,
 class operator_bitwise_not : public range_operator
 {
 public:
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &lh,
-                          const value_range &rh) const;
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &lh,
+                          const irange &rh) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
 } op_bitwise_not;
 
 bool
-operator_bitwise_not::fold_range (value_range &r, tree type,
-                                 const value_range &lh,
-                                 const value_range &rh) const
+operator_bitwise_not::fold_range (irange &r, tree type,
+                                 const irange &lh,
+                                 const irange &rh) const
 {
-  if (empty_range_check (r, lh, rh))
+  if (empty_range_varying (r, type, lh, rh))
     return true;
 
   // ~X is simply -1 - X.
-  value_range minusone (type, wi::minus_one (TYPE_PRECISION (type)),
-                       wi::minus_one (TYPE_PRECISION (type)));
+  int_range<1> minusone (type, wi::minus_one (TYPE_PRECISION (type)),
+                        wi::minus_one (TYPE_PRECISION (type)));
   return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, minusone,
                                                          lh);
 }
 
 bool
-operator_bitwise_not::op1_range (value_range &r, tree type,
-                                const value_range &lhs,
-                                const value_range &op2) const
+operator_bitwise_not::op1_range (irange &r, tree type,
+                                const irange &lhs,
+                                const irange &op2) const
 {
   // ~X is -1 - X and since bitwise NOT is involutary...do it again.
   return fold_range (r, type, lhs, op2);
@@ -2297,15 +2719,15 @@ operator_bitwise_not::op1_range (value_range &r, tree type,
 class operator_cst : public range_operator
 {
 public:
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &op1,
-                          const value_range &op2) const;
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &op1,
+                          const irange &op2) const;
 } op_integer_cst;
 
 bool
-operator_cst::fold_range (value_range &r, tree type ATTRIBUTE_UNUSED,
-                         const value_range &lh,
-                         const value_range &rh ATTRIBUTE_UNUSED) const
+operator_cst::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
+                         const irange &lh,
+                         const irange &rh ATTRIBUTE_UNUSED) const
 {
   r = lh;
   return true;
@@ -2315,48 +2737,66 @@ operator_cst::fold_range (value_range &r, tree type ATTRIBUTE_UNUSED,
 class operator_identity : public range_operator
 {
 public:
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &op1,
-                          const value_range &op2) const;
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &op1,
+                          const irange &op2) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
 } op_identity;
 
 bool
-operator_identity::fold_range (value_range &r, tree type ATTRIBUTE_UNUSED,
-                              const value_range &lh,
-                              const value_range &rh ATTRIBUTE_UNUSED) const
+operator_identity::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
+                              const irange &lh,
+                              const irange &rh ATTRIBUTE_UNUSED) const
 {
   r = lh;
   return true;
 }
 
 bool
-operator_identity::op1_range (value_range &r, tree type ATTRIBUTE_UNUSED,
-                             const value_range &lhs,
-                             const value_range &op2 ATTRIBUTE_UNUSED) const
+operator_identity::op1_range (irange &r, tree type ATTRIBUTE_UNUSED,
+                             const irange &lhs,
+                             const irange &op2 ATTRIBUTE_UNUSED) const
 {
   r = lhs;
   return true;
 }
 
 
+class operator_unknown : public range_operator
+{
+public:
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &op1,
+                          const irange &op2) const;
+} op_unknown;
+
+bool
+operator_unknown::fold_range (irange &r, tree type,
+                             const irange &lh ATTRIBUTE_UNUSED,
+                             const irange &rh ATTRIBUTE_UNUSED) const
+{
+  r.set_varying (type);
+  return true;
+}
+
+
 class operator_abs : public range_operator
 {
  public:
-  virtual void wi_fold (value_range &r, tree type,
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
                        const wide_int &lh_ub,
                        const wide_int &rh_lb,
                        const wide_int &rh_ub) const;
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
 } op_abs;
 
 void
-operator_abs::wi_fold (value_range &r, tree type,
+operator_abs::wi_fold (irange &r, tree type,
                       const wide_int &lh_lb, const wide_int &lh_ub,
                       const wide_int &rh_lb ATTRIBUTE_UNUSED,
                       const wide_int &rh_ub ATTRIBUTE_UNUSED) const
@@ -2368,7 +2808,7 @@ operator_abs::wi_fold (value_range &r, tree type,
   // Pass through LH for the easy cases.
   if (sign == UNSIGNED || wi::ge_p (lh_lb, 0, sign))
     {
-      r = value_range (type, lh_lb, lh_ub);
+      r = int_range<1> (type, lh_lb, lh_ub);
       return;
     }
 
@@ -2378,7 +2818,7 @@ operator_abs::wi_fold (value_range &r, tree type,
   wide_int max_value = wi::max_value (prec, sign);
   if (!TYPE_OVERFLOW_UNDEFINED (type) && wi::eq_p (lh_lb, min_value))
     {
-      r = value_range (type);
+      r.set_varying (type);
       return;
     }
 
@@ -2416,15 +2856,15 @@ operator_abs::wi_fold (value_range &r, tree type,
       min = wi::zero (prec);
       max = max_value;
     }
-  r = value_range (type, min, max);
+  r = int_range<1> (type, min, max);
 }
 
 bool
-operator_abs::op1_range (value_range &r, tree type,
-                        const value_range &lhs,
-                        const value_range &op2) const
+operator_abs::op1_range (irange &r, tree type,
+                        const irange &lhs,
+                        const irange &op2) const
 {
-  if (empty_range_check (r, lhs, op2))
+  if (empty_range_varying (r, type, lhs, op2))
     return true;
   if (TYPE_UNSIGNED (type))
     {
@@ -2432,15 +2872,15 @@ operator_abs::op1_range (value_range &r, tree type,
       return true;
     }
   // Start with the positives because negatives are an impossible result.
-  value_range positives = range_positives (type);
+  widest_irange positives = range_positives (type);
   positives.intersect (lhs);
   r = positives;
   // Then add the negative of each pair:
   // ABS(op1) = [5,20] would yield op1 => [-20,-5][5,20].
   for (unsigned i = 0; i < positives.num_pairs (); ++i)
-    r.union_ (value_range (type,
-                          -positives.upper_bound (i),
-                          -positives.lower_bound (i)));
+    r.union_ (int_range<1> (type,
+                           -positives.upper_bound (i),
+                           -positives.lower_bound (i)));
   return true;
 }
 
@@ -2448,13 +2888,13 @@ operator_abs::op1_range (value_range &r, tree type,
 class operator_absu : public range_operator
 {
  public:
-  virtual void wi_fold (value_range &r, tree type,
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb, const wide_int &lh_ub,
                        const wide_int &rh_lb, const wide_int &rh_ub) const;
 } op_absu;
 
 void
-operator_absu::wi_fold (value_range &r, tree type,
+operator_absu::wi_fold (irange &r, tree type,
                        const wide_int &lh_lb, const wide_int &lh_ub,
                        const wide_int &rh_lb ATTRIBUTE_UNUSED,
                        const wide_int &rh_ub ATTRIBUTE_UNUSED) const
@@ -2485,27 +2925,27 @@ operator_absu::wi_fold (value_range &r, tree type,
     }
 
   gcc_checking_assert (TYPE_UNSIGNED (type));
-  r = value_range (type, new_lb, new_ub);
+  r = int_range<1> (type, new_lb, new_ub);
 }
 
 
 class operator_negate : public range_operator
 {
  public:
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &op1,
-                          const value_range &op2) const;
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &op1,
+                          const irange &op2) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
 } op_negate;
 
 bool
-operator_negate::fold_range (value_range &r, tree type,
-                            const value_range &lh,
-                            const value_range &rh) const
+operator_negate::fold_range (irange &r, tree type,
+                            const irange &lh,
+                            const irange &rh) const
 {
-  if (empty_range_check (r, lh, rh))
+  if (empty_range_varying (r, type, lh, rh))
     return true;
   // -X is simply 0 - X.
   return range_op_handler (MINUS_EXPR, type)->fold_range (r, type,
@@ -2514,9 +2954,9 @@ operator_negate::fold_range (value_range &r, tree type,
 }
 
 bool
-operator_negate::op1_range (value_range &r, tree type,
-                           const value_range &lhs,
-                           const value_range &op2) const
+operator_negate::op1_range (irange &r, tree type,
+                           const irange &lhs,
+                           const irange &op2) const
 {
   // NEGATE is involutory.
   return fold_range (r, type, lhs, op2);
@@ -2526,20 +2966,20 @@ operator_negate::op1_range (value_range &r, tree type,
 class operator_addr_expr : public range_operator
 {
 public:
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &op1,
-                          const value_range &op2) const;
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &op1,
+                          const irange &op2) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
 } op_addr;
 
 bool
-operator_addr_expr::fold_range (value_range &r, tree type,
-                               const value_range &lh,
-                               const value_range &rh) const
+operator_addr_expr::fold_range (irange &r, tree type,
+                               const irange &lh,
+                               const irange &rh) const
 {
-  if (empty_range_check (r, lh, rh))
+  if (empty_range_varying (r, type, lh, rh))
     return true;
 
   // Return a non-null pointer of the LHS type (passed in op2).
@@ -2548,14 +2988,14 @@ operator_addr_expr::fold_range (value_range &r, tree type,
   else if (!lh.contains_p (build_zero_cst (lh.type ())))
     r = range_nonzero (type);
   else
-    r = value_range (type);
+    r.set_varying (type);
   return true;
 }
 
 bool
-operator_addr_expr::op1_range (value_range &r, tree type,
-                              const value_range &lhs,
-                              const value_range &op2) const
+operator_addr_expr::op1_range (irange &r, tree type,
+                              const irange &lhs,
+                              const irange &op2) const
 {
   return operator_addr_expr::fold_range (r, type, lhs, op2);
 }
@@ -2564,7 +3004,7 @@ operator_addr_expr::op1_range (value_range &r, tree type,
 class pointer_plus_operator : public range_operator
 {
 public:
-  virtual void wi_fold (value_range &r, tree type,
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
                        const wide_int &lh_ub,
                        const wide_int &rh_lb,
@@ -2572,7 +3012,7 @@ public:
 } op_pointer_plus;
 
 void
-pointer_plus_operator::wi_fold (value_range &r, tree type,
+pointer_plus_operator::wi_fold (irange &r, tree type,
                                const wide_int &lh_lb,
                                const wide_int &lh_ub,
                                const wide_int &rh_lb,
@@ -2604,20 +3044,20 @@ pointer_plus_operator::wi_fold (value_range &r, tree type,
           && rh_lb == rh_ub && rh_lb == 0)
     r = range_zero (type);
   else
-   r = value_range (type);
+   r.set_varying (type);
 }
 
 
 class pointer_min_max_operator : public range_operator
 {
 public:
-  virtual void wi_fold (value_range & r, tree type,
+  virtual void wi_fold (irange & r, tree type,
                        const wide_int &lh_lb, const wide_int &lh_ub,
                        const wide_int &rh_lb, const wide_int &rh_ub) const;
 } op_ptr_min_max;
 
 void
-pointer_min_max_operator::wi_fold (value_range &r, tree type,
+pointer_min_max_operator::wi_fold (irange &r, tree type,
                                   const wide_int &lh_lb,
                                   const wide_int &lh_ub,
                                   const wide_int &rh_lb,
@@ -2633,20 +3073,20 @@ pointer_min_max_operator::wi_fold (value_range &r, tree type,
   else if (wi_zero_p (type, lh_lb, lh_ub) && wi_zero_p (type, rh_lb, rh_ub))
     r = range_zero (type);
   else
-    r = value_range (type);
+    r.set_varying (type);
 }
 
 
 class pointer_and_operator : public range_operator
 {
 public:
-  virtual void wi_fold (value_range &r, tree type,
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb, const wide_int &lh_ub,
                        const wide_int &rh_lb, const wide_int &rh_ub) const;
 } op_pointer_and;
 
 void
-pointer_and_operator::wi_fold (value_range &r, tree type,
+pointer_and_operator::wi_fold (irange &r, tree type,
                               const wide_int &lh_lb,
                               const wide_int &lh_ub,
                               const wide_int &rh_lb ATTRIBUTE_UNUSED,
@@ -2657,20 +3097,49 @@ pointer_and_operator::wi_fold (value_range &r, tree type,
   if (wi_zero_p (type, lh_lb, lh_ub) || wi_zero_p (type, lh_lb, lh_ub))
     r = range_zero (type);
   else 
-    r = value_range (type);
+    r.set_varying (type);
 }
 
 
 class pointer_or_operator : public range_operator
 {
 public:
-  virtual void wi_fold (value_range &r, tree type,
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
+  virtual bool op2_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op1) const;
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb, const wide_int &lh_ub,
                        const wide_int &rh_lb, const wide_int &rh_ub) const;
 } op_pointer_or;
 
+bool
+pointer_or_operator::op1_range (irange &r, tree type,
+                               const irange &lhs,
+                               const irange &op2 ATTRIBUTE_UNUSED) const
+{
+  if (lhs.zero_p ())
+    {
+      tree zero = build_zero_cst (type);
+      r = int_range<1> (zero, zero);
+      return true;
+    }
+  r.set_varying (type);
+  return true;
+}
+
+bool
+pointer_or_operator::op2_range (irange &r, tree type,
+                               const irange &lhs,
+                               const irange &op1) const
+{
+  return pointer_or_operator::op1_range (r, type, lhs, op1);
+}
+
 void
-pointer_or_operator::wi_fold (value_range &r, tree type,
+pointer_or_operator::wi_fold (irange &r, tree type,
                              const wide_int &lh_lb,
                              const wide_int &lh_ub,
                              const wide_int &rh_lb,
@@ -2684,7 +3153,7 @@ pointer_or_operator::wi_fold (value_range &r, tree type,
   else if (wi_zero_p (type, lh_lb, lh_ub) && wi_zero_p (type, rh_lb, rh_ub))
     r = range_zero (type);
   else
-    r = value_range (type);
+    r.set_varying (type);
 }
 \f
 // This implements the range operator tables as local objects in this file.
@@ -2760,6 +3229,8 @@ integral_table::integral_table ()
   set (SSA_NAME, op_identity);
   set (PAREN_EXPR, op_identity);
   set (OBJ_TYPE_REF, op_identity);
+  set (IMAGPART_EXPR, op_unknown);
+  set (POINTER_DIFF_EXPR, op_unknown);
   set (ABS_EXPR, op_abs);
   set (ABSU_EXPR, op_absu);
   set (NEGATE_EXPR, op_negate);
@@ -2811,13 +3282,13 @@ range_op_handler (enum tree_code code, tree type)
 // Cast the range in R to TYPE.
 
 void
-range_cast (value_range &r, tree type)
+range_cast (irange &r, tree type)
 {
-  value_range tmp = r;
+  widest_irange tmp = r;
   range_operator *op = range_op_handler (CONVERT_EXPR, type);
   // Call op_convert, if it fails, the result is varying.
-  if (!op->fold_range (r, type, tmp, value_range (type)))
-    r = value_range (type);
+  if (!op->fold_range (r, type, tmp, int_range<1> (type)))
+    r.set_varying (type);
 }
 
 #if CHECKING_P
@@ -2836,37 +3307,280 @@ namespace selftest
 #define UCHAR(N) build_int_cstu (unsigned_char_type_node, (N))
 #define SCHAR(N) build_int_cst (signed_char_type_node, (N))
 
+static int_range<3>
+build_range3 (int a, int b, int c, int d, int e, int f)
+{
+  int_range<3> i1 (INT (a), INT (b));
+  int_range<3> i2 (INT (c), INT (d));
+  int_range<3> i3 (INT (e), INT (f));
+  i1.union_ (i2);
+  i1.union_ (i3);
+  return i1;
+}
+
+static void
+range3_tests ()
+{
+  typedef int_range<3> irange3;
+  irange3 r0, r1, r2;
+  irange3 i1, i2, i3;
+
+  // ([10,20] U [5,8]) U [1,3] ==> [1,3][5,8][10,20].
+  r0 = irange3 (INT (10), INT (20));
+  r1 = irange3 (INT (5), INT (8));
+  r0.union_ (r1);
+  r1 = irange3 (INT (1), INT (3));
+  r0.union_ (r1);
+  ASSERT_TRUE (r0 == build_range3 (1, 3, 5, 8, 10, 20));
+
+  // [1,3][5,8][10,20] U [-5,0] => [-5,3][5,8][10,20].
+  r1 = irange3 (INT (-5), INT (0));
+  r0.union_ (r1);
+  ASSERT_TRUE (r0 == build_range3 (-5, 3, 5, 8, 10, 20));
+
+  // [10,20][30,40] U [50,60] ==> [10,20][30,40][50,60].
+  r1 = irange3 (INT (50), INT (60));
+  r0 = irange3 (INT (10), INT (20));
+  r0.union_ (irange3 (INT (30), INT (40)));
+  r0.union_ (r1);
+  ASSERT_TRUE (r0 == build_range3 (10, 20, 30, 40, 50, 60));
+  // [10,20][30,40][50,60] U [70, 80] ==> [10,20][30,40][50,60][70,80].
+  r1 = irange3 (INT (70), INT (80));
+  r0.union_ (r1);
+
+  r2 = build_range3 (10, 20, 30, 40, 50, 60);
+  r2.union_ (irange3 (INT (70), INT (80)));
+  ASSERT_TRUE (r0 == r2);
+
+  // [10,20][30,40][50,60] U [6,35] => [6,40][50,60].
+  r0 = build_range3 (10, 20, 30, 40, 50, 60);
+  r1 = irange3 (INT (6), INT (35));
+  r0.union_ (r1);
+  r1 = irange3 (INT (6), INT (40));
+  r1.union_ (irange3 (INT (50), INT (60)));
+  ASSERT_TRUE (r0 == r1);
+
+  // [10,20][30,40][50,60] U [6,60] => [6,60].
+  r0 = build_range3 (10, 20, 30, 40, 50, 60);
+  r1 = irange3 (INT (6), INT (60));
+  r0.union_ (r1);
+  ASSERT_TRUE (r0 == irange3 (INT (6), INT (60)));
+
+  // [10,20][30,40][50,60] U [6,70] => [6,70].
+  r0 = build_range3 (10, 20, 30, 40, 50, 60);
+  r1 = irange3 (INT (6), INT (70));
+  r0.union_ (r1);
+  ASSERT_TRUE (r0 == irange3 (INT (6), INT (70)));
+
+  // [10,20][30,40][50,60] U [35,70] => [10,20][30,70].
+  r0 = build_range3 (10, 20, 30, 40, 50, 60);
+  r1 = irange3 (INT (35), INT (70));
+  r0.union_ (r1);
+  r1 = irange3 (INT (10), INT (20));
+  r1.union_ (irange3 (INT (30), INT (70)));
+  ASSERT_TRUE (r0 == r1);
+
+  // [10,20][30,40][50,60] U [15,35] => [10,40][50,60].
+  r0 = build_range3 (10, 20, 30, 40, 50, 60);
+  r1 = irange3 (INT (15), INT (35));
+  r0.union_ (r1);
+  r1 = irange3 (INT (10), INT (40));
+  r1.union_ (irange3 (INT (50), INT (60)));
+  ASSERT_TRUE (r0 == r1);
+
+  // [10,20][30,40][50,60] U [35,35] => [10,20][30,40][50,60].
+  r0 = build_range3 (10, 20, 30, 40, 50, 60);
+  r1 = irange3 (INT (35), INT (35));
+  r0.union_ (r1);
+  ASSERT_TRUE (r0 == build_range3 (10, 20, 30, 40, 50, 60));
+}
+
+static void
+widest_irange_tests ()
+{
+  widest_irange big;
+  unsigned int nrange;
+
+  // Build a huge multi-range range.
+  for (nrange = 0; nrange < 50; ++nrange)
+    {
+      int_range<1> tmp (INT (nrange*10), INT (nrange*10 + 5));
+      big.union_ (tmp);
+    }
+  ASSERT_TRUE (big.num_pairs () == nrange);
+
+  // Verify that we can copy it without loosing precision.
+  widest_irange copy (big);
+  ASSERT_TRUE (copy.num_pairs () == nrange);
+
+  // Inverting it should produce one more sub-range.
+  big.invert ();
+  ASSERT_TRUE (big.num_pairs () == nrange + 1);
+
+  int_range<1> tmp (INT (5), INT (37));
+  big.intersect (tmp);
+  ASSERT_TRUE (big.num_pairs () == 4);
+
+  // Test that [10,10][20,20] does NOT contain 15.
+  {
+    widest_irange i1 (build_int_cst (integer_type_node, 10),
+                     build_int_cst (integer_type_node, 10));
+    widest_irange i2 (build_int_cst (integer_type_node, 20),
+                     build_int_cst (integer_type_node, 20));
+    i1.union_ (i2);
+    ASSERT_FALSE (i1.contains_p (build_int_cst (integer_type_node, 15)));
+  }
+
+}
+
+static void
+multi_precision_range_tests ()
+{
+  // Test truncating copy to int_range<1>.
+  int_range<3> big = build_range3 (10, 20, 30, 40, 50, 60);
+  int_range<1> small = big;
+  ASSERT_TRUE (small == int_range<1> (INT (10), INT (60)));
+
+  // Test truncating copy to int_range<2>.
+  int_range<2> medium = big;
+  ASSERT_TRUE (!medium.undefined_p ());
+
+  // Test that a truncating copy of [MIN,20][22,40][80,MAX]
+  // ends up as a conservative anti-range of ~[21,21].
+  big = int_range<3> (vrp_val_min (integer_type_node), INT (20));
+  big.union_ (int_range<1> (INT (22), INT (40)));
+  big.union_ (int_range<1> (INT (80), vrp_val_max (integer_type_node)));
+  small = big;
+  ASSERT_TRUE (small == int_range<1> (INT (21), INT (21), VR_ANTI_RANGE));
+
+  range3_tests ();
+}
+
+static void
+operator_tests ()
+{
+  tree min = vrp_val_min (integer_type_node);
+  tree max = vrp_val_max (integer_type_node);
+  tree tiny = fold_build2 (PLUS_EXPR, integer_type_node, min,
+                          build_one_cst (integer_type_node));
+  widest_irange res;
+  widest_irange i1 (tiny, max);
+  widest_irange i2 (build_int_cst (integer_type_node, 255),
+                   build_int_cst (integer_type_node, 255));
+
+  // [MIN+1, MAX] = OP1 & 255: OP1 is VARYING
+  op_bitwise_and.op1_range (res, integer_type_node, i1, i2);
+  ASSERT_TRUE (res == int_range<1> (integer_type_node));
+
+  // VARYING = OP1 & 255: OP1 is VARYING
+  i1 = int_range<1> (integer_type_node);
+  op_bitwise_and.op1_range (res, integer_type_node, i1, i2);
+  ASSERT_TRUE (res == int_range<1> (integer_type_node));
+
+  // Test that 0x808.... & 0x8.... still contains 0x8....
+  // for a large set of numbers.
+  {
+    tree big_type = long_long_unsigned_type_node;
+    // big_num = 0x808,0000,0000,0000
+    tree big_num = fold_build2 (LSHIFT_EXPR, big_type,
+                               build_int_cst (big_type, 0x808),
+                               build_int_cst (big_type, 48));
+    op_bitwise_and.fold_range (res, big_type,
+                              int_range <1> (big_type),
+                              int_range <1> (big_num, big_num));
+    // val = 0x8,0000,0000,0000
+    tree val = fold_build2 (LSHIFT_EXPR, big_type,
+                           build_int_cst (big_type, 0x8),
+                           build_int_cst (big_type, 48));
+    ASSERT_TRUE (res.contains_p (val));
+  }
+
+  // unsigned: [3, MAX] = OP1 >> 1
+  {
+    widest_irange lhs (build_int_cst (unsigned_type_node, 3),
+                      TYPE_MAX_VALUE (unsigned_type_node));
+    widest_irange one (build_one_cst (unsigned_type_node),
+                      build_one_cst (unsigned_type_node));
+    widest_irange op1;
+    op_rshift.op1_range (op1, unsigned_type_node, lhs, one);
+    ASSERT_FALSE (op1.contains_p (UINT (3)));
+  }
+
+  // signed: [3, MAX] = OP1 >> 1
+  {
+    widest_irange lhs (INT (3), TYPE_MAX_VALUE (integer_type_node));
+    widest_irange one (INT (1), INT (1));
+    widest_irange op1;
+    op_rshift.op1_range (op1, integer_type_node, lhs, one);
+    ASSERT_FALSE (op1.contains_p (INT (-2)));
+  }
+
+  // This is impossible, so OP1 should be [].
+  // signed: [MIN, MIN] = OP1 >> 1
+  {
+    widest_irange lhs (TYPE_MIN_VALUE (integer_type_node),
+                      TYPE_MIN_VALUE (integer_type_node));
+    widest_irange one (INT (1), INT (1));
+    widest_irange op1;
+    op_rshift.op1_range (op1, integer_type_node, lhs, one);
+    ASSERT_TRUE (op1.undefined_p ());
+  }
+
+  // signed: ~[-1] = OP1 >> 31
+  {
+    widest_irange lhs (INT (-1), INT (-1), VR_ANTI_RANGE);
+    widest_irange shift (INT (31), INT (31));
+    widest_irange op1;
+    op_rshift.op1_range (op1, integer_type_node, lhs, shift);
+    widest_irange negatives = range_negatives (integer_type_node);
+    negatives.intersect (op1);
+    ASSERT_TRUE (negatives.undefined_p ());
+  }
+}
+
 // Run all of the selftests within this file.
 
 void
 range_tests ()
 {
   tree u128_type = build_nonstandard_integer_type (128, /*unsigned=*/1);
-  value_range i1, i2, i3;
-  value_range r0, r1, rold;
+  int_range<1> i1, i2, i3;
+  int_range<1> r0, r1, rold;
+
+  // Test 1-bit signed integer union.
+  // [-1,-1] U [0,0] = VARYING.
+  tree one_bit_type = build_nonstandard_integer_type (1, 0);
+  {
+    tree one_bit_min = vrp_val_min (one_bit_type);
+    tree one_bit_max = vrp_val_max (one_bit_type);
+    int_range<2> min (one_bit_min, one_bit_min);
+    int_range<2> max (one_bit_max, one_bit_max);
+    max.union_ (min);
+    ASSERT_TRUE (max.varying_p ());
+  }
 
   // Test that NOT(255) is [0..254] in 8-bit land.
-  value_range not_255 (UCHAR (255), UCHAR (255), VR_ANTI_RANGE);
-  ASSERT_TRUE (not_255 == value_range (UCHAR (0), UCHAR (254)));
+  int_range<1> not_255 (UCHAR (255), UCHAR (255), VR_ANTI_RANGE);
+  ASSERT_TRUE (not_255 == int_range<1> (UCHAR (0), UCHAR (254)));
 
   // Test that NOT(0) is [1..255] in 8-bit land.
-  value_range not_zero = range_nonzero (unsigned_char_type_node);
-  ASSERT_TRUE (not_zero == value_range (UCHAR (1), UCHAR (255)));
+  int_range<1> not_zero = range_nonzero (unsigned_char_type_node);
+  ASSERT_TRUE (not_zero == int_range<1> (UCHAR (1), UCHAR (255)));
 
   // Check that [0,127][0x..ffffff80,0x..ffffff]
   //  => ~[128, 0x..ffffff7f].
-  r0 = value_range (UINT128 (0), UINT128 (127));
+  r0 = int_range<1> (UINT128 (0), UINT128 (127));
   tree high = build_minus_one_cst (u128_type);
   // low = -1 - 127 => 0x..ffffff80.
   tree low = fold_build2 (MINUS_EXPR, u128_type, high, UINT128(127));
-  r1 = value_range (low, high); // [0x..ffffff80, 0x..ffffffff]
+  r1 = int_range<1> (low, high); // [0x..ffffff80, 0x..ffffffff]
   // r0 = [0,127][0x..ffffff80,0x..fffffff].
   r0.union_ (r1);
   // r1 = [128, 0x..ffffff7f].
-  r1 = value_range (UINT128(128),
-                        fold_build2 (MINUS_EXPR, u128_type,
-                                     build_minus_one_cst (u128_type),
-                                     UINT128(128)));
+  r1 = int_range<1> (UINT128(128),
+                    fold_build2 (MINUS_EXPR, u128_type,
+                                 build_minus_one_cst (u128_type),
+                                 UINT128(128)));
   r0.invert ();
   ASSERT_TRUE (r0 == r1);
 
@@ -2882,38 +3596,38 @@ range_tests ()
   tree maxuint = wide_int_to_tree (unsigned_type_node, r0.upper_bound ());
 
   // Check that ~[0,5] => [6,MAX] for unsigned int.
-  r0 = value_range (UINT (0), UINT (5));
+  r0 = int_range<1> (UINT (0), UINT (5));
   r0.invert ();
-  ASSERT_TRUE (r0 == value_range (UINT(6), maxuint));
+  ASSERT_TRUE (r0 == int_range<1> (UINT(6), maxuint));
 
   // Check that ~[10,MAX] => [0,9] for unsigned int.
-  r0 = value_range (UINT(10), maxuint);
+  r0 = int_range<1> (UINT(10), maxuint);
   r0.invert ();
-  ASSERT_TRUE (r0 == value_range (UINT (0), UINT (9)));
+  ASSERT_TRUE (r0 == int_range<1> (UINT (0), UINT (9)));
 
   // Check that ~[0,5] => [6,MAX] for unsigned 128-bit numbers.
-  r0 = value_range (UINT128 (0), UINT128 (5), VR_ANTI_RANGE);
-  r1 = value_range (UINT128(6), build_minus_one_cst (u128_type));
+  r0 = int_range<1> (UINT128 (0), UINT128 (5), VR_ANTI_RANGE);
+  r1 = int_range<1> (UINT128(6), build_minus_one_cst (u128_type));
   ASSERT_TRUE (r0 == r1);
 
   // Check that [~5] is really [-MIN,4][6,MAX].
-  r0 = value_range (INT (5), INT (5), VR_ANTI_RANGE);
-  r1 = value_range (minint, INT (4));
-  r1.union_ (value_range (INT (6), maxint));
+  r0 = int_range<1> (INT (5), INT (5), VR_ANTI_RANGE);
+  r1 = int_range<1> (minint, INT (4));
+  r1.union_ (int_range<1> (INT (6), maxint));
   ASSERT_FALSE (r1.undefined_p ());
   ASSERT_TRUE (r0 == r1);
 
-  r1 = value_range (INT (5), INT (5));
-  value_range r2 (r1);
+  r1 = int_range<1> (INT (5), INT (5));
+  int_range<1> r2 (r1);
   ASSERT_TRUE (r1 == r2);
 
-  r1 = value_range (INT (5), INT (10));
+  r1 = int_range<1> (INT (5), INT (10));
 
-  r1 = value_range (integer_type_node,
-              wi::to_wide (INT (5)), wi::to_wide (INT (10)));
+  r1 = int_range<1> (integer_type_node,
+                    wi::to_wide (INT (5)), wi::to_wide (INT (10)));
   ASSERT_TRUE (r1.contains_p (INT (7)));
 
-  r1 = value_range (SCHAR (0), SCHAR (20));
+  r1 = int_range<1> (SCHAR (0), SCHAR (20));
   ASSERT_TRUE (r1.contains_p (SCHAR(15)));
   ASSERT_FALSE (r1.contains_p (SCHAR(300)));
 
@@ -2922,96 +3636,96 @@ range_tests ()
   if (TYPE_PRECISION (TREE_TYPE (maxint))
       > TYPE_PRECISION (short_integer_type_node))
     {
-      r1 = value_range (integer_zero_node, maxint);
+      r1 = int_range<1> (integer_zero_node, maxint);
       range_cast (r1, short_integer_type_node);
       ASSERT_TRUE (r1.lower_bound () == wi::to_wide (minshort)
                   && r1.upper_bound() == wi::to_wide (maxshort));
     }
 
   // (unsigned char)[-5,-1] => [251,255].
-  r0 = rold = value_range (SCHAR (-5), SCHAR (-1));
+  r0 = rold = int_range<1> (SCHAR (-5), SCHAR (-1));
   range_cast (r0, unsigned_char_type_node);
-  ASSERT_TRUE (r0 == value_range (UCHAR (251), UCHAR (255)));
+  ASSERT_TRUE (r0 == int_range<1> (UCHAR (251), UCHAR (255)));
   range_cast (r0, signed_char_type_node);
   ASSERT_TRUE (r0 == rold);
 
   // (signed char)[15, 150] => [-128,-106][15,127].
-  r0 = rold = value_range (UCHAR (15), UCHAR (150));
+  r0 = rold = int_range<1> (UCHAR (15), UCHAR (150));
   range_cast (r0, signed_char_type_node);
-  r1 = value_range (SCHAR (15), SCHAR (127));
-  r2 = value_range (SCHAR (-128), SCHAR (-106));
+  r1 = int_range<1> (SCHAR (15), SCHAR (127));
+  r2 = int_range<1> (SCHAR (-128), SCHAR (-106));
   r1.union_ (r2);
   ASSERT_TRUE (r1 == r0);
   range_cast (r0, unsigned_char_type_node);
   ASSERT_TRUE (r0 == rold);
 
   // (unsigned char)[-5, 5] => [0,5][251,255].
-  r0 = rold = value_range (SCHAR (-5), SCHAR (5));
+  r0 = rold = int_range<1> (SCHAR (-5), SCHAR (5));
   range_cast (r0, unsigned_char_type_node);
-  r1 = value_range (UCHAR (251), UCHAR (255));
-  r2 = value_range (UCHAR (0), UCHAR (5));
+  r1 = int_range<1> (UCHAR (251), UCHAR (255));
+  r2 = int_range<1> (UCHAR (0), UCHAR (5));
   r1.union_ (r2);
   ASSERT_TRUE (r0 == r1);
   range_cast (r0, signed_char_type_node);
   ASSERT_TRUE (r0 == rold);
 
   // (unsigned char)[-5,5] => [0,5][251,255].
-  r0 = value_range (INT (-5), INT (5));
+  r0 = int_range<1> (INT (-5), INT (5));
   range_cast (r0, unsigned_char_type_node);
-  r1 = value_range (UCHAR (0), UCHAR (5));
-  r1.union_ (value_range (UCHAR (251), UCHAR (255)));
+  r1 = int_range<1> (UCHAR (0), UCHAR (5));
+  r1.union_ (int_range<1> (UCHAR (251), UCHAR (255)));
   ASSERT_TRUE (r0 == r1);
 
   // (unsigned char)[5U,1974U] => [0,255].
-  r0 = value_range (UINT (5), UINT (1974));
+  r0 = int_range<1> (UINT (5), UINT (1974));
   range_cast (r0, unsigned_char_type_node);
-  ASSERT_TRUE (r0 == value_range (UCHAR (0), UCHAR (255)));
+  ASSERT_TRUE (r0 == int_range<1> (UCHAR (0), UCHAR (255)));
   range_cast (r0, integer_type_node);
   // Going to a wider range should not sign extend.
-  ASSERT_TRUE (r0 == value_range (INT (0), INT (255)));
+  ASSERT_TRUE (r0 == int_range<1> (INT (0), INT (255)));
 
   // (unsigned char)[-350,15] => [0,255].
-  r0 = value_range (INT (-350), INT (15));
+  r0 = int_range<1> (INT (-350), INT (15));
   range_cast (r0, unsigned_char_type_node);
-  ASSERT_TRUE (r0 == (value_range
+  ASSERT_TRUE (r0 == (int_range<1>
                      (TYPE_MIN_VALUE (unsigned_char_type_node),
                       TYPE_MAX_VALUE (unsigned_char_type_node))));
 
   // Casting [-120,20] from signed char to unsigned short.
   // => [0, 20][0xff88, 0xffff].
-  r0 = value_range (SCHAR (-120), SCHAR (20));
+  r0 = int_range<1> (SCHAR (-120), SCHAR (20));
   range_cast (r0, short_unsigned_type_node);
-  r1 = value_range (UINT16 (0), UINT16 (20));
-  r2 = value_range (UINT16 (0xff88), UINT16 (0xffff));
+  r1 = int_range<1> (UINT16 (0), UINT16 (20));
+  r2 = int_range<1> (UINT16 (0xff88), UINT16 (0xffff));
   r1.union_ (r2);
   ASSERT_TRUE (r0 == r1);
   // A truncating cast back to signed char will work because [-120, 20]
   // is representable in signed char.
   range_cast (r0, signed_char_type_node);
-  ASSERT_TRUE (r0 == value_range (SCHAR (-120), SCHAR (20)));
+  ASSERT_TRUE (r0 == int_range<1> (SCHAR (-120), SCHAR (20)));
 
   // unsigned char -> signed short
   //   (signed short)[(unsigned char)25, (unsigned char)250]
   // => [(signed short)25, (signed short)250]
-  r0 = rold = value_range (UCHAR (25), UCHAR (250));
+  r0 = rold = int_range<1> (UCHAR (25), UCHAR (250));
   range_cast (r0, short_integer_type_node);
-  r1 = value_range (INT16 (25), INT16 (250));
+  r1 = int_range<1> (INT16 (25), INT16 (250));
   ASSERT_TRUE (r0 == r1);
   range_cast (r0, unsigned_char_type_node);
   ASSERT_TRUE (r0 == rold);
 
   // Test casting a wider signed [-MIN,MAX] to a nar`rower unsigned.
-  r0 = value_range (TYPE_MIN_VALUE (long_long_integer_type_node),
+  r0 = int_range<1> (TYPE_MIN_VALUE (long_long_integer_type_node),
               TYPE_MAX_VALUE (long_long_integer_type_node));
   range_cast (r0, short_unsigned_type_node);
-  r1 = value_range (TYPE_MIN_VALUE (short_unsigned_type_node),
+  r1 = int_range<1> (TYPE_MIN_VALUE (short_unsigned_type_node),
               TYPE_MAX_VALUE (short_unsigned_type_node));
   ASSERT_TRUE (r0 == r1);
 
   // NOT([10,20]) ==> [-MIN,9][21,MAX].
-  r0 = r1 = value_range (INT (10), INT (20));
-  r2 = value_range (minint, INT(9));
-  r2.union_ (value_range (INT(21), maxint));
+  r0 = r1 = int_range<1> (INT (10), INT (20));
+  r2 = int_range<1> (minint, INT(9));
+  r2.union_ (int_range<1> (INT(21), maxint));
   ASSERT_FALSE (r2.undefined_p ());
   r1.invert ();
   ASSERT_TRUE (r1 == r2);
@@ -3021,11 +3735,11 @@ range_tests ()
 
   // Test that booleans and their inverse work as expected.
   r0 = range_zero (boolean_type_node);
-  ASSERT_TRUE (r0 == value_range (build_zero_cst (boolean_type_node),
-                                      build_zero_cst (boolean_type_node)));
+  ASSERT_TRUE (r0 == int_range<1> (build_zero_cst (boolean_type_node),
+                                  build_zero_cst (boolean_type_node)));
   r0.invert ();
-  ASSERT_TRUE (r0 == value_range (build_one_cst (boolean_type_node),
-                                      build_one_cst (boolean_type_node)));
+  ASSERT_TRUE (r0 == int_range<1> (build_one_cst (boolean_type_node),
+                                  build_one_cst (boolean_type_node)));
 
   // Casting NONZERO to a narrower type will wrap/overflow so
   // it's just the entire range for the narrower type.
@@ -3038,8 +3752,8 @@ range_tests ()
     {
       r0 = range_nonzero (integer_type_node);
       range_cast (r0, short_integer_type_node);
-      r1 = value_range (TYPE_MIN_VALUE (short_integer_type_node),
-                            TYPE_MAX_VALUE (short_integer_type_node));
+      r1 = int_range<1> (TYPE_MIN_VALUE (short_integer_type_node),
+                        TYPE_MAX_VALUE (short_integer_type_node));
       ASSERT_TRUE (r0 == r1);
     }
 
@@ -3049,8 +3763,8 @@ range_tests ()
   // Converting this to 32-bits signed is [-MIN_16,-1][1, +MAX_16].
   r0 = range_nonzero (short_integer_type_node);
   range_cast (r0, integer_type_node);
-  r1 = value_range (INT (-32768), INT (-1));
-  r2 = value_range (INT (1), INT (32767));
+  r1 = int_range<1> (INT (-32768), INT (-1));
+  r2 = int_range<1> (INT (1), INT (32767));
   r1.union_ (r2);
   ASSERT_TRUE (r0 == r1);
 
@@ -3064,34 +3778,34 @@ range_tests ()
   ASSERT_TRUE (r0 == r1);
 
   // [10,20] U [15, 30] => [10, 30].
-  r0 = value_range (INT (10), INT (20));
-  r1 = value_range (INT (15), INT (30));
+  r0 = int_range<1> (INT (10), INT (20));
+  r1 = int_range<1> (INT (15), INT (30));
   r0.union_ (r1);
-  ASSERT_TRUE (r0 == value_range (INT (10), INT (30)));
+  ASSERT_TRUE (r0 == int_range<1> (INT (10), INT (30)));
 
   // [15,40] U [] => [15,40].
-  r0 = value_range (INT (15), INT (40));
+  r0 = int_range<1> (INT (15), INT (40));
   r1.set_undefined ();
   r0.union_ (r1);
-  ASSERT_TRUE (r0 == value_range (INT (15), INT (40)));
+  ASSERT_TRUE (r0 == int_range<1> (INT (15), INT (40)));
 
   // [10,20] U [10,10] => [10,20].
-  r0 = value_range (INT (10), INT (20));
-  r1 = value_range (INT (10), INT (10));
+  r0 = int_range<1> (INT (10), INT (20));
+  r1 = int_range<1> (INT (10), INT (10));
   r0.union_ (r1);
-  ASSERT_TRUE (r0 == value_range (INT (10), INT (20)));
+  ASSERT_TRUE (r0 == int_range<1> (INT (10), INT (20)));
 
   // [10,20] U [9,9] => [9,20].
-  r0 = value_range (INT (10), INT (20));
-  r1 = value_range (INT (9), INT (9));
+  r0 = int_range<1> (INT (10), INT (20));
+  r1 = int_range<1> (INT (9), INT (9));
   r0.union_ (r1);
-  ASSERT_TRUE (r0 == value_range (INT (9), INT (20)));
+  ASSERT_TRUE (r0 == int_range<1> (INT (9), INT (20)));
 
   // [10,20] ^ [15,30] => [15,20].
-  r0 = value_range (INT (10), INT (20));
-  r1 = value_range (INT (15), INT (30));
+  r0 = int_range<1> (INT (10), INT (20));
+  r1 = int_range<1> (INT (15), INT (30));
   r0.intersect (r1);
-  ASSERT_TRUE (r0 == value_range (INT (15), INT (20)));
+  ASSERT_TRUE (r0 == int_range<1> (INT (15), INT (20)));
 
   // Test the internal sanity of wide_int's wrt HWIs.
   ASSERT_TRUE (wi::max_value (TYPE_PRECISION (boolean_type_node),
@@ -3099,13 +3813,17 @@ range_tests ()
               == wi::uhwi (1, TYPE_PRECISION (boolean_type_node)));
 
   // Test zero_p().
-  r0 = value_range (INT (0), INT (0));
+  r0 = int_range<1> (INT (0), INT (0));
   ASSERT_TRUE (r0.zero_p ());
 
   // Test nonzero_p().
-  r0 = value_range (INT (0), INT (0));
+  r0 = int_range<1> (INT (0), INT (0));
   r0.invert ();
   ASSERT_TRUE (r0.nonzero_p ());
+
+  multi_precision_range_tests ();
+  widest_irange_tests ();
+  operator_tests ();
 }
 
 } // namespace selftest
index 1311965f4f54e45139d043c285325b4f2169983f..08f6bf9f73f84eaeb901ea5bd3edc6cf1c2329de 100644 (file)
@@ -50,9 +50,9 @@ class range_operator
 {
 public:
   // Perform an operation between 2 ranges and return it.
-  virtual bool fold_range (value_range &r, tree type,
-                          const value_range &lh,
-                          const value_range &rh) const;
+  virtual bool fold_range (irange &r, tree type,
+                          const irange &lh,
+                          const irange &rh) const;
 
   // Return the range for op[12] in the general case.  LHS is the range for
   // the LHS of the expression, OP[12]is the range for the other
@@ -65,16 +65,16 @@ public:
   //
   // i.e.  [LHS] = ??? + OP2
   // is re-formed as R = [LHS] - OP2.
-  virtual bool op1_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op2) const;
-  virtual bool op2_range (value_range &r, tree type,
-                         const value_range &lhs,
-                         const value_range &op1) const;
+  virtual bool op1_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op2) const;
+  virtual bool op2_range (irange &r, tree type,
+                         const irange &lhs,
+                         const irange &op1) const;
 
 protected:
   // Perform an integral operation between 2 sub-ranges and return it.
-  virtual void wi_fold (value_range &r, tree type,
+  virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
                        const wide_int &lh_ub,
                        const wide_int &rh_lb,
@@ -82,7 +82,7 @@ protected:
 };
 
 extern range_operator *range_op_handler (enum tree_code code, tree type);
-extern void range_cast (value_range &, tree type);
+extern void range_cast (irange &, tree type);
 extern void wi_set_zero_nonzero_bits (tree type,
                                      const wide_int &, const wide_int &,
                                      wide_int &maybe_nonzero,
index 7193ca4ad5e7e95129b2a2dc9204a57233a5d41a..de84c1d505de2084995b3c878fa84fbc5c6a2fc1 100644 (file)
@@ -1151,25 +1151,29 @@ static bool
 range_fold_binary_symbolics_p (value_range *vr,
                               tree_code code,
                               tree expr_type,
-                              const value_range *vr0, const value_range *vr1)
+                              const value_range *vr0_,
+                              const value_range *vr1_)
 {
-  if (vr0->symbolic_p () || vr1->symbolic_p ())
+  if (vr0_->symbolic_p () || vr1_->symbolic_p ())
     {
+      value_range vr0 = drop_undefines_to_varying (vr0_, expr_type);
+      value_range vr1 = drop_undefines_to_varying (vr1_, expr_type);
       if ((code == PLUS_EXPR || code == MINUS_EXPR))
        {
-         extract_range_from_plus_minus_expr (vr, code, expr_type, vr0, vr1);
+         extract_range_from_plus_minus_expr (vr, code, expr_type,
+                                             &vr0, &vr1);
          return true;
        }
       if (POINTER_TYPE_P (expr_type) && code == POINTER_PLUS_EXPR)
        {
-         extract_range_from_pointer_plus_expr (vr, code, expr_type, vr0, vr1);
+         extract_range_from_pointer_plus_expr (vr, code, expr_type,
+                                               &vr0, &vr1);
          return true;
        }
       const range_operator *op = get_range_op_handler (vr, code, expr_type);
-      value_range vr0_cst (*vr0), vr1_cst (*vr1);
-      vr0_cst.normalize_symbolics ();
-      vr1_cst.normalize_symbolics ();
-      return op->fold_range (*vr, expr_type, vr0_cst, vr1_cst);
+      vr0.normalize_symbolics ();
+      vr1.normalize_symbolics ();
+      return op->fold_range (*vr, expr_type, vr0, vr1);
     }
   return false;
 }
@@ -1225,11 +1229,15 @@ range_fold_binary_expr (value_range *vr,
   if (!op)
     return;
 
-  value_range vr0 = drop_undefines_to_varying (vr0_, expr_type);
-  value_range vr1 = drop_undefines_to_varying (vr1_, expr_type);
-  if (range_fold_binary_symbolics_p (vr, code, expr_type, &vr0, &vr1))
+  if (range_fold_binary_symbolics_p (vr, code, expr_type, vr0_, vr1_))
     return;
 
+  value_range vr0 (*vr0_);
+  value_range vr1 (*vr1_);
+  if (vr0.undefined_p ())
+    vr0.set_varying (expr_type);
+  if (vr1.undefined_p ())
+    vr1.set_varying (expr_type);
   vr0.normalize_addresses ();
   vr1.normalize_addresses ();
   op->fold_range (*vr, expr_type, vr0, vr1);
@@ -1637,7 +1645,7 @@ extract_code_and_val_from_cond_with_ops (tree name, enum tree_code cond_code,
    (to transform signed values into unsigned) and at the end xor
    SGNBIT back.  */
 
-static wide_int
+wide_int
 masked_increment (const wide_int &val_in, const wide_int &mask,
                  const wide_int &sgnbit, unsigned int prec)
 {
index b3d187ffdf12b4cea565eef911bc1e091f87e491..371e58aa0ea13b9eaf5dd0e29452a6d692610014 100644 (file)
@@ -62,5 +62,7 @@ extern bool overflow_comparison_p (tree_code, tree, tree, bool, tree *);
 extern tree get_single_symbol (tree, bool *, tree *);
 extern void maybe_set_nonzero_bits (edge, tree);
 extern value_range_kind determine_value_range (tree, wide_int *, wide_int *);
+extern wide_int masked_increment (const wide_int &val_in, const wide_int &mask,
+                                 const wide_int &sgnbit, unsigned int prec);
 
 #endif /* GCC_TREE_VRP_H */
index 6522a089ddfe742e120e91666e651111a572ebb0..01a342c5b9235e1e21a63bf47879de65659e6bc2 100644 (file)
@@ -1483,6 +1483,31 @@ int_cst_hasher::equal (tree x, tree y)
   return true;
 }
 
+/* Cache wide_int CST into the TYPE_CACHED_VALUES cache for TYPE.
+   SLOT is the slot entry to store it in, and MAX_SLOTS is the maximum
+   number of slots that can be cached for the type.  */
+
+static inline tree
+cache_wide_int_in_type_cache (tree type, const wide_int &cst,
+                             int slot, int max_slots)
+{
+  gcc_checking_assert (slot >= 0);
+  /* Initialize cache.  */
+  if (!TYPE_CACHED_VALUES_P (type))
+    {
+      TYPE_CACHED_VALUES_P (type) = 1;
+      TYPE_CACHED_VALUES (type) = make_tree_vec (max_slots);
+    }
+  tree t = TREE_VEC_ELT (TYPE_CACHED_VALUES (type), slot);
+  if (!t)
+    {
+      /* Create a new shared int.  */
+      t = build_new_int_cst (type, cst);
+      TREE_VEC_ELT (TYPE_CACHED_VALUES (type), slot) = t;
+    }
+  return t;
+}
+
 /* Create an INT_CST node of TYPE and value CST.
    The returned node is always shared.  For small integers we use a
    per-type vector cache, for larger ones we use a single hash table.
@@ -1515,6 +1540,28 @@ wide_int_to_tree_1 (tree type, const wide_int_ref &pcst)
   wide_int cst = wide_int::from (pcst, prec, sgn);
   unsigned int ext_len = get_int_cst_ext_nunits (type, cst);
 
+  enum tree_code code = TREE_CODE (type);
+  if (code == POINTER_TYPE || code == REFERENCE_TYPE)
+    {
+      /* Cache NULL pointer and zero bounds.  */
+      if (cst == 0)
+       ix = 0;
+      /* Cache upper bounds of pointers.  */
+      else if (cst == wi::max_value (prec, sgn))
+       ix = 1;
+      /* Cache 1 which is used for a non-zero range.  */
+      else if (cst == 1)
+       ix = 2;
+
+      if (ix >= 0)
+       {
+         t = cache_wide_int_in_type_cache (type, cst, ix, 3);
+         /* Make sure no one is clobbering the shared constant.  */
+         gcc_checking_assert (TREE_TYPE (t) == type
+                              && cst == wi::to_wide (t));
+         return t;
+       }
+    }
   if (ext_len == 1)
     {
       /* We just need to store a single HOST_WIDE_INT.  */
@@ -1524,7 +1571,7 @@ wide_int_to_tree_1 (tree type, const wide_int_ref &pcst)
       else
        hwi = cst.to_shwi ();
 
-      switch (TREE_CODE (type))
+      switch (code)
        {
        case NULLPTR_TYPE:
          gcc_assert (hwi == 0);
@@ -1532,12 +1579,7 @@ wide_int_to_tree_1 (tree type, const wide_int_ref &pcst)
 
        case POINTER_TYPE:
        case REFERENCE_TYPE:
-         /* Cache NULL pointer and zero bounds.  */
-         if (hwi == 0)
-           {
-             limit = 1;
-             ix = 0;
-           }
+         /* Ignore pointers, as they were already handled above.  */
          break;
 
        case BOOLEAN_TYPE:
@@ -1574,27 +1616,14 @@ wide_int_to_tree_1 (tree type, const wide_int_ref &pcst)
 
       if (ix >= 0)
        {
-         /* Look for it in the type's vector of small shared ints.  */
-         if (!TYPE_CACHED_VALUES_P (type))
-           {
-             TYPE_CACHED_VALUES_P (type) = 1;
-             TYPE_CACHED_VALUES (type) = make_tree_vec (limit);
-           }
-
-         t = TREE_VEC_ELT (TYPE_CACHED_VALUES (type), ix);
-         if (t)
-           /* Make sure no one is clobbering the shared constant.  */
-           gcc_checking_assert (TREE_TYPE (t) == type
-                                && TREE_INT_CST_NUNITS (t) == 1
-                                && TREE_INT_CST_OFFSET_NUNITS (t) == 1
-                                && TREE_INT_CST_EXT_NUNITS (t) == 1
-                                && TREE_INT_CST_ELT (t, 0) == hwi);
-         else
-           {
-             /* Create a new shared int.  */
-             t = build_new_int_cst (type, cst);
-             TREE_VEC_ELT (TYPE_CACHED_VALUES (type), ix) = t;
-           }
+         t = cache_wide_int_in_type_cache (type, cst, ix, limit);
+         /* Make sure no one is clobbering the shared constant.  */
+         gcc_checking_assert (TREE_TYPE (t) == type
+                              && TREE_INT_CST_NUNITS (t) == 1
+                              && TREE_INT_CST_OFFSET_NUNITS (t) == 1
+                              && TREE_INT_CST_EXT_NUNITS (t) == 1
+                              && TREE_INT_CST_ELT (t, 0) == hwi);
+         return t;
        }
       else
        {
index 24132e3546e729beddb28d125683a74d1d4c0b28..7dc10b876e02318a0c425d7d020dd16e2666b70f 100644 (file)
@@ -90,13 +90,13 @@ value_range_equiv::update (tree min, tree max, value_range_kind kind)
 void
 value_range_equiv::deep_copy (const value_range_equiv *from)
 {
-  set (from->min (), from->max (), from->m_equiv, from->m_kind);
+  set (from->min (), from->max (), from->m_equiv, from->kind ());
 }
 
 void
 value_range_equiv::move (value_range_equiv *from)
 {
-  set (from->min (), from->max (), NULL, from->m_kind);
+  set (from->min (), from->max (), NULL, from->kind ());
   m_equiv = from->m_equiv;
   from->m_equiv = NULL;
 }
@@ -127,8 +127,8 @@ value_range_equiv::set_equiv (bitmap equiv)
 void
 value_range_equiv::check ()
 {
-  value_range::check ();
-  switch (m_kind)
+  value_range::verify_range ();
+  switch (kind ())
     {
     case VR_UNDEFINED:
     case VR_VARYING:
@@ -206,8 +206,9 @@ value_range_equiv::intersect (const value_range_equiv *other)
     this->deep_copy (other);
   else
     {
-      value_range tem = intersect_helper (this, other);
-      this->update (tem.min (), tem.max (), tem.kind ());
+      legacy_intersect (this, other);
+      if (varying_p () || undefined_p ())
+       equiv_clear ();
 
       /* If the result is VR_UNDEFINED there is no need to mess with
         equivalencies.  */
@@ -254,8 +255,9 @@ value_range_equiv::union_ (const value_range_equiv *other)
     this->deep_copy (other);
   else
     {
-      value_range tem = union_helper (this, other);
-      this->update (tem.min (), tem.max (), tem.kind ());
+      legacy_union (this, other);
+      if (varying_p () || undefined_p ())
+       equiv_clear ();
 
       /* The resulting set of equivalences is always the intersection of
         the two sets.  */
@@ -277,7 +279,7 @@ void
 value_range_equiv::dump (FILE *file) const
 {
   value_range::dump (file);
-  if ((m_kind == VR_RANGE || m_kind == VR_ANTI_RANGE)
+  if ((kind () == VR_RANGE || kind () == VR_ANTI_RANGE)
       && m_equiv)
     {
       bitmap_iterator bi;
index bc4b061da57170f7140ccfd6b50c68b75d958ec5..93164b7e2e213895a294d9a806806c326caefbe2 100644 (file)
@@ -1,5 +1,7 @@
 /* Support routines for value ranges.
    Copyright (C) 2019-2020 Free Software Foundation, Inc.
+   Major hacks by Aldy Hernandez <aldyh@redhat.com> and
+   Andrew MacLeod <amacleod@redhat.com>.
 
 This file is part of GCC.
 
@@ -27,45 +29,168 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pretty-print.h"
 #include "fold-const.h"
 
-value_range::value_range (tree min, tree max, value_range_kind kind)
+// Here we copy between any two irange's.  The ranges can be legacy or
+// multi-ranges, and copying between any combination works correctly.
+
+irange &
+irange::operator= (const irange &src)
+{
+  if (legacy_mode_p () != src.legacy_mode_p ())
+    {
+      copy_legacy_range (src);
+      return *this;
+    }
+  if (legacy_mode_p ())
+    {
+      gcc_checking_assert (src.legacy_mode_p ());
+      m_num_ranges = src.m_num_ranges;
+      m_base[0] = src.m_base[0];
+      m_base[1] = src.m_base[1];
+      m_kind = src.m_kind;
+      return *this;
+    }
+
+  unsigned x;
+  unsigned lim = src.m_num_ranges;
+  if (lim > m_max_ranges)
+    lim = m_max_ranges;
+
+  for (x = 0; x < lim * 2; ++x)
+    m_base[x] = src.m_base[x];
+
+  // If the range didn't fit, the last range should cover the rest.
+  if (lim != src.m_num_ranges)
+    m_base[x - 1] = src.m_base[src.m_num_ranges * 2 - 1];
+
+  m_num_ranges = lim;
+  return *this;
+}
+
+// Return TRUE if range is a multi-range that can be represented as a
+// VR_ANTI_RANGE.
+
+bool
+irange::maybe_anti_range () const
 {
-  set (min, max, kind);
+  tree ttype = type ();
+  unsigned int precision = TYPE_PRECISION (ttype);
+  signop sign = TYPE_SIGN (ttype);
+  return (num_pairs () > 1
+         && precision > 1
+         && lower_bound () == wi::min_value (precision, sign)
+         && upper_bound () == wi::max_value (precision, sign));
 }
 
-value_range::value_range (tree type)
+// Copy between a legacy and a multi-range, or vice-versa.
+
+void
+irange::copy_legacy_range (const irange &src)
 {
-  set_varying (type);
+  gcc_checking_assert (src.legacy_mode_p () != legacy_mode_p ());
+  if (src.undefined_p ())
+    set_undefined ();
+  else if (src.varying_p ())
+    set_varying (src.type ());
+  else if (src.kind () == VR_ANTI_RANGE)
+    set (src.min (), src.max (), VR_ANTI_RANGE);
+  else if (legacy_mode_p () && src.maybe_anti_range ())
+    {
+      int_range<3> tmp (src);
+      tmp.invert ();
+      set (tmp.min (), wide_int_to_tree (src.type (), tmp.upper_bound (0)),
+          VR_ANTI_RANGE);
+    }
+  else
+    set (src.min (), src.max (), VR_RANGE);
 }
 
-value_range::value_range (tree type,
-                         const wide_int &wmin, const wide_int &wmax,
-                         enum value_range_kind kind)
+// Swap min/max if they are out of order.  Return TRUE if further
+// processing of the range is necessary, FALSE otherwise.
+
+bool
+irange::swap_out_of_order_endpoints (tree &min, tree &max,
+                                         value_range_kind &kind)
 {
-  tree min = wide_int_to_tree (type, wmin);
-  tree max = wide_int_to_tree (type, wmax);
-  gcc_checking_assert (kind == VR_RANGE || kind == VR_ANTI_RANGE);
-  set (min, max, kind);
+  /* Wrong order for min and max, to swap them and the VR type we need
+     to adjust them.  */
+  if (tree_int_cst_lt (max, min))
+    {
+      tree one, tmp;
+
+      /* For one bit precision if max < min, then the swapped
+        range covers all values, so for VR_RANGE it is varying and
+        for VR_ANTI_RANGE empty range, so drop to varying as well.  */
+      if (TYPE_PRECISION (TREE_TYPE (min)) == 1)
+       {
+         set_varying (TREE_TYPE (min));
+         return false;
+       }
+
+      one = build_int_cst (TREE_TYPE (min), 1);
+      tmp = int_const_binop (PLUS_EXPR, max, one);
+      max = int_const_binop (MINUS_EXPR, min, one);
+      min = tmp;
+
+      /* There's one corner case, if we had [C+1, C] before we now have
+        that again.  But this represents an empty value range, so drop
+        to varying in this case.  */
+      if (tree_int_cst_lt (max, min))
+       {
+         set_varying (TREE_TYPE (min));
+         return false;
+       }
+      kind = kind == VR_RANGE ? VR_ANTI_RANGE : VR_RANGE;
+    }
+  return true;
 }
 
 void
-value_range::set_undefined ()
+irange::irange_set (tree min, tree max)
 {
-  m_kind = VR_UNDEFINED;
-  m_min = m_max = NULL;
+  gcc_checking_assert (!POLY_INT_CST_P (min));
+  gcc_checking_assert (!POLY_INT_CST_P (max));
+
+  m_base[0] = min;
+  m_base[1] = max;
+  m_num_ranges = 1;
+  if (flag_checking)
+    verify_range ();
 }
 
 void
-value_range::set_varying (tree type)
+irange::irange_set_anti_range (tree min, tree max)
 {
-  m_kind = VR_VARYING;
-  if (supports_type_p (type))
+  gcc_checking_assert (!POLY_INT_CST_P (min));
+  gcc_checking_assert (!POLY_INT_CST_P (max));
+
+  // set an anti-range
+  tree type = TREE_TYPE (min);
+  signop sign = TYPE_SIGN (type);
+  int_range<2> type_range (type);
+  // Calculate INVERSE([I,J]) as [-MIN, I-1][J+1, +MAX].
+  m_num_ranges = 0;
+  wi::overflow_type ovf;
+
+  wide_int w_min = wi::to_wide (min);
+  if (wi::ne_p (w_min, type_range.lower_bound ()))
     {
-      m_min = vrp_val_min (type);
-      m_max = vrp_val_max (type);
+      wide_int lim1 = wi::sub (w_min, 1, sign, &ovf);
+      gcc_checking_assert (ovf != wi::OVF_OVERFLOW);
+      m_base[0] = type_range.tree_lower_bound (0);
+      m_base[1] = wide_int_to_tree (type, lim1);
+      m_num_ranges = 1;
     }
-  else
-    /* We can't do anything range-wise with these types.  */
-    m_min = m_max = error_mark_node;
+  wide_int w_max = wi::to_wide (max);
+  if (wi::ne_p (w_max, type_range.upper_bound ()))
+    {
+      wide_int lim2 = wi::add (w_max, 1, sign, &ovf);
+      gcc_checking_assert (ovf != wi::OVF_OVERFLOW);
+      m_base[m_num_ranges * 2] = wide_int_to_tree (type, lim2);
+      m_base[m_num_ranges * 2 + 1] = type_range.tree_upper_bound (0);
+      ++m_num_ranges;
+    }
+  if (flag_checking)
+    verify_range ();
 }
 
 /* Set value range to the canonical form of {VRTYPE, MIN, MAX, EQUIV}.
@@ -78,15 +203,24 @@ value_range::set_varying (tree type)
    extract ranges from var + CST op limit.  */
 
 void
-value_range::set (tree min, tree max, value_range_kind kind)
+irange::set (tree min, tree max, value_range_kind kind)
 {
-  /* Use the canonical setters for VR_UNDEFINED and VR_VARYING.  */
+  if (!legacy_mode_p ())
+    {
+      if (kind == VR_RANGE)
+       irange_set (min, max);
+      else
+       {
+         gcc_checking_assert (kind == VR_ANTI_RANGE);
+         irange_set_anti_range (min, max);
+       }
+      return;
+    }
   if (kind == VR_UNDEFINED)
     {
       set_undefined ();
       return;
     }
-
   if (kind == VR_RANGE)
     {
       /* Convert POLY_INT_CST bounds into worst-case INTEGER_CST bounds.  */
@@ -109,68 +243,30 @@ value_range::set (tree min, tree max, value_range_kind kind)
     }
   else if (kind != VR_VARYING)
     {
-      if (POLY_INT_CST_P (min) || POLY_INT_CST_P (max))
-       kind = VR_VARYING;
+     if (POLY_INT_CST_P (min) || POLY_INT_CST_P (max))
+       kind = VR_VARYING;
     }
-
   if (kind == VR_VARYING)
     {
-      gcc_assert (TREE_TYPE (min) == TREE_TYPE (max));
-      tree typ = TREE_TYPE (min);
-      if (supports_type_p (typ))
-       {
-         gcc_assert (vrp_val_min (typ));
-         gcc_assert (vrp_val_max (typ));
-       }
-      set_varying (typ);
+      set_varying (TREE_TYPE (min));
       return;
     }
 
-  /* Nothing to canonicalize for symbolic ranges.  */
+  tree type = TREE_TYPE (min);
+  // Nothing to canonicalize for symbolic ranges.
   if (TREE_CODE (min) != INTEGER_CST
       || TREE_CODE (max) != INTEGER_CST)
     {
       m_kind = kind;
-      m_min = min;
-      m_max = max;
+      m_base[0] = min;
+      m_base[1] = max;
+      m_num_ranges = 1;
       return;
     }
+  if (!swap_out_of_order_endpoints (min, max, kind))
+    goto cleanup_set;
 
-  /* Wrong order for min and max, to swap them and the VR type we need
-     to adjust them.  */
-  if (tree_int_cst_lt (max, min))
-    {
-      tree one, tmp;
-
-      /* For one bit precision if max < min, then the swapped
-        range covers all values, so for VR_RANGE it is varying and
-        for VR_ANTI_RANGE empty range, so drop to varying as well.  */
-      if (TYPE_PRECISION (TREE_TYPE (min)) == 1)
-       {
-         set_varying (TREE_TYPE (min));
-         return;
-       }
-
-      one = build_int_cst (TREE_TYPE (min), 1);
-      tmp = int_const_binop (PLUS_EXPR, max, one);
-      max = int_const_binop (MINUS_EXPR, min, one);
-      min = tmp;
-
-      /* There's one corner case, if we had [C+1, C] before we now have
-        that again.  But this represents an empty value range, so drop
-        to varying in this case.  */
-      if (tree_int_cst_lt (max, min))
-       {
-         set_varying (TREE_TYPE (min));
-         return;
-       }
-
-      kind = kind == VR_RANGE ? VR_ANTI_RANGE : VR_RANGE;
-    }
-
-  tree type = TREE_TYPE (min);
-
-  /* Anti-ranges that can be represented as ranges should be so.  */
+  // Anti-ranges that can be represented as ranges should be so.
   if (kind == VR_ANTI_RANGE)
     {
       /* For -fstrict-enums we may receive out-of-range ranges so consider
@@ -211,109 +307,90 @@ value_range::set (tree min, tree max, value_range_kind kind)
          kind = VR_RANGE;
         }
     }
+  else if (!swap_out_of_order_endpoints (min, max, kind))
+    goto cleanup_set;
 
-  /* Normalize [MIN, MAX] into VARYING and ~[MIN, MAX] into UNDEFINED.
+  /* Do not drop [-INF(OVF), +INF(OVF)] to varying.  (OVF) has to be sticky
+     to make sure VRP iteration terminates, otherwise we can get into
+     oscillations.  */
+  if (!normalize_min_max (type, min, max, kind))
+    {
+      m_kind = kind;
+      m_base[0] = min;
+      m_base[1] = max;
+      m_num_ranges = 1;
+      if (flag_checking)
+       verify_range ();
+    }
 
-     Avoid using TYPE_{MIN,MAX}_VALUE because -fstrict-enums can
-     restrict those to a subset of what actually fits in the type.
-     Instead use the extremes of the type precision which will allow
-     compare_range_with_value() to check if a value is inside a range,
-     whereas if we used TYPE_*_VAL, said function would just punt
-     upon seeing a VARYING.  */
+ cleanup_set:
+  // Avoid using TYPE_{MIN,MAX}_VALUE because -fstrict-enums can
+  // restrict those to a subset of what actually fits in the type.
+  // Instead use the extremes of the type precision
   unsigned prec = TYPE_PRECISION (type);
   signop sign = TYPE_SIGN (type);
   if (wi::eq_p (wi::to_wide (min), wi::min_value (prec, sign))
       && wi::eq_p (wi::to_wide (max), wi::max_value (prec, sign)))
-    {
-      if (kind == VR_RANGE)
-       set_varying (type);
-      else if (kind == VR_ANTI_RANGE)
-       set_undefined ();
-      else
-       gcc_unreachable ();
-      return;
-    }
-
-  /* Do not drop [-INF(OVF), +INF(OVF)] to varying.  (OVF) has to be sticky
-     to make sure VRP iteration terminates, otherwise we can get into
-     oscillations.  */
-
-  m_kind = kind;
-  m_min = min;
-  m_max = max;
+    m_kind = VR_VARYING;
+  else if (undefined_p ())
+    m_kind = VR_UNDEFINED;
   if (flag_checking)
-    check ();
-}
-
-void
-value_range::set (tree val)
-{
-  gcc_assert (TREE_CODE (val) == SSA_NAME || is_gimple_min_invariant (val));
-  if (TREE_OVERFLOW_P (val))
-    val = drop_tree_overflow (val);
-  set (val, val);
-}
-
-/* Set value range VR to a nonzero range of type TYPE.  */
-
-void
-value_range::set_nonzero (tree type)
-{
-  tree zero = build_int_cst (type, 0);
-  set (zero, zero, VR_ANTI_RANGE);
-}
-
-/* Set value range VR to a ZERO range of type TYPE.  */
-
-void
-value_range::set_zero (tree type)
-{
-  set (build_int_cst (type, 0));
+    verify_range ();
 }
 
 /* Check the validity of the range.  */
 
 void
-value_range::check ()
+irange::verify_range ()
 {
-  switch (m_kind)
+  if (!legacy_mode_p ())
     {
-    case VR_RANGE:
-    case VR_ANTI_RANGE:
-      {
-       gcc_assert (m_min && m_max);
-       gcc_assert (!TREE_OVERFLOW_P (m_min) && !TREE_OVERFLOW_P (m_max));
-
-       /* Creating ~[-MIN, +MAX] is stupid because that would be
-          the empty set.  */
-       if (INTEGRAL_TYPE_P (TREE_TYPE (m_min)) && m_kind == VR_ANTI_RANGE)
-         gcc_assert (!vrp_val_is_min (m_min) || !vrp_val_is_max (m_max));
+      gcc_checking_assert (m_kind == VR_RANGE);
+      for (unsigned i = 0; i < m_num_ranges; ++i)
+       {
+         tree lb = tree_lower_bound (i);
+         tree ub = tree_upper_bound (i);
+         int c = compare_values (lb, ub);
+         gcc_assert (c == 0 || c == -1);
+       }
+      return;
+    }
 
-       int cmp = compare_values (m_min, m_max);
-       gcc_assert (cmp == 0 || cmp == -1 || cmp == -2);
-       break;
-      }
+  switch (m_kind)
+    {
     case VR_UNDEFINED:
-      gcc_assert (!min () && !max ());
+      gcc_assert (m_num_ranges == 0);
       break;
+
     case VR_VARYING:
-      gcc_assert (m_min && m_max);
+      gcc_assert (m_num_ranges == 1);
       break;
+
+    case VR_ANTI_RANGE:
+    case VR_RANGE:
+      {
+       gcc_assert (m_num_ranges == 1);
+       int cmp = compare_values (tree_lower_bound (0), tree_upper_bound (0));
+       gcc_assert (cmp == 0 || cmp == -1 || cmp == -2);
+       return;
+      }
+
     default:
       gcc_unreachable ();
     }
 }
 
-/* Return the number of sub-ranges in a range.  */
-
 unsigned
-value_range::num_pairs () const
+irange::legacy_num_pairs () const
 {
+  gcc_checking_assert (legacy_mode_p ());
+
   if (undefined_p ())
     return 0;
   if (varying_p ())
     return 1;
-  if (symbolic_p ())
+  // Inlined symbolic_p for performance:
+  if (!is_gimple_min_invariant (min ()) || !is_gimple_min_invariant (max ()))
     {
       value_range numeric_range (*this);
       numeric_range.normalize_symbolics ();
@@ -323,111 +400,124 @@ value_range::num_pairs () const
     {
       // ~[MIN, X] has one sub-range of [X+1, MAX], and
       // ~[X, MAX] has one sub-range of [MIN, X-1].
-      if (vrp_val_is_min (m_min) || vrp_val_is_max (m_max))
+      if (vrp_val_is_min (min ()) || vrp_val_is_max (max ()))
        return 1;
       return 2;
     }
+  gcc_checking_assert (m_num_ranges == 1);
   return 1;
 }
 
-/* Return the lower bound for a sub-range.  PAIR is the sub-range in
-   question.  */
+// Return the lower bound for a sub-range.  PAIR is the sub-range in
+// question.
 
 wide_int
-value_range::lower_bound (unsigned pair) const
+irange::legacy_lower_bound (unsigned pair) const
 {
+  gcc_checking_assert (legacy_mode_p ());
   if (symbolic_p ())
     {
       value_range numeric_range (*this);
       numeric_range.normalize_symbolics ();
-      return numeric_range.lower_bound (pair);
+      return numeric_range.legacy_lower_bound (pair);
     }
-
   gcc_checking_assert (!undefined_p ());
   gcc_checking_assert (pair + 1 <= num_pairs ());
-  tree t = NULL;
   if (m_kind == VR_ANTI_RANGE)
     {
-      tree typ = type ();
-      if (pair == 1 || vrp_val_is_min (m_min))
-       t = wide_int_to_tree (typ, wi::to_wide (m_max) + 1);
+      tree typ = type (), t;
+      if (pair == 1 || vrp_val_is_min (min ()))
+       t = wide_int_to_tree (typ, wi::to_wide (max ()) + 1);
       else
        t = vrp_val_min (typ);
+      return wi::to_wide (t);
     }
-  else
-    t = m_min;
-  return wi::to_wide (t);
+ return wi::to_wide (tree_lower_bound (pair));
 }
 
-/* Return the upper bound for a sub-range.  PAIR is the sub-range in
-   question.  */
+// Return the upper bound for a sub-range.  PAIR is the sub-range in
+// question.
 
 wide_int
-value_range::upper_bound (unsigned pair) const
+irange::legacy_upper_bound (unsigned pair) const
 {
+  gcc_checking_assert (legacy_mode_p ());
   if (symbolic_p ())
     {
       value_range numeric_range (*this);
       numeric_range.normalize_symbolics ();
-      return numeric_range.upper_bound (pair);
+      return numeric_range.legacy_upper_bound (pair);
     }
-
   gcc_checking_assert (!undefined_p ());
   gcc_checking_assert (pair + 1 <= num_pairs ());
-  tree t = NULL;
   if (m_kind == VR_ANTI_RANGE)
     {
-      tree typ = type ();
-      if (pair == 1 || vrp_val_is_min (m_min))
+      tree typ = type (), t;
+      if (pair == 1 || vrp_val_is_min (min ()))
        t = vrp_val_max (typ);
       else
-       t = wide_int_to_tree (typ, wi::to_wide (m_min) - 1);
+       t = wide_int_to_tree (typ, wi::to_wide (min ()) - 1);
+      return wi::to_wide (t);
     }
-  else
-    t = m_max;
-  return wi::to_wide (t);
-}
-
-/* Return the highest bound in a range.  */
-
-wide_int
-value_range::upper_bound () const
-{
-  unsigned pairs = num_pairs ();
-  gcc_checking_assert (pairs > 0);
-  return upper_bound (pairs - 1);
+  return wi::to_wide (tree_upper_bound (pair));
 }
 
 bool
-value_range::equal_p (const value_range &other) const
+irange::legacy_equal_p (const irange &other) const
 {
-  /* Ignore types for undefined.  All undefines are equal.  */
-  if (undefined_p ())
-    return m_kind == other.m_kind;
+  gcc_checking_assert (legacy_mode_p () && other.legacy_mode_p ());
 
-  return (m_kind == other.m_kind
-         && vrp_operand_equal_p (m_min, other.m_min)
-         && vrp_operand_equal_p (m_max, other.m_max));
+  if (m_kind != other.m_kind)
+   return false;
+  if (m_kind == VR_UNDEFINED || m_kind == VR_VARYING)
+    return true;
+  return (vrp_operand_equal_p (tree_lower_bound (0),
+                              other.tree_lower_bound (0))
+         && vrp_operand_equal_p (tree_upper_bound (0),
+                                 other.tree_upper_bound (0)));
 }
 
 bool
-value_range::operator== (const value_range &r) const
+irange::equal_p (const irange &other) const
 {
-  return equal_p (r);
+  if (legacy_mode_p ())
+    {
+      if (other.legacy_mode_p ())
+       return legacy_equal_p (other);
+      value_range tmp (other);
+      return legacy_equal_p (tmp);
+    }
+  if (other.legacy_mode_p ())
+    {
+      value_range tmp2 (*this);
+      return tmp2.legacy_equal_p (other);
+    }
+
+  if (m_num_ranges != other.m_num_ranges)
+    return false;
+
+  for (unsigned i = 0; i < m_num_ranges; ++i)
+    {
+      tree lb = tree_lower_bound (i);
+      tree ub = tree_upper_bound (i);
+      tree lb_other = other.tree_lower_bound (i);
+      tree ub_other = other.tree_upper_bound (i);
+      if (!operand_equal_p (lb, lb_other, 0)
+         || !operand_equal_p (ub, ub_other, 0))
+       return false;
+    }
+  return true;
 }
 
-/* If range is a singleton, place it in RESULT and return TRUE.
-   Note: A singleton can be any gimple invariant, not just constants.
-   So, [&x, &x] counts as a singleton.  */
 /* Return TRUE if this is a symbolic range.  */
 
 bool
-value_range::symbolic_p () const
+irange::symbolic_p () const
 {
   return (!varying_p ()
          && !undefined_p ()
-         && (!is_gimple_min_invariant (m_min)
-             || !is_gimple_min_invariant (m_max)));
+         && (!is_gimple_min_invariant (min ())
+             || !is_gimple_min_invariant (max ())));
 }
 
 /* NOTE: This is not the inverse of symbolic_p because the range
@@ -436,17 +526,32 @@ value_range::symbolic_p () const
    constants would be represented as [-MIN, +MAX].  */
 
 bool
-value_range::constant_p () const
+irange::constant_p () const
 {
   return (!varying_p ()
          && !undefined_p ()
-         && TREE_CODE (m_min) == INTEGER_CST
-         && TREE_CODE (m_max) == INTEGER_CST);
+         && TREE_CODE (min ()) == INTEGER_CST
+         && TREE_CODE (max ()) == INTEGER_CST);
 }
 
+/* If range is a singleton, place it in RESULT and return TRUE.
+   Note: A singleton can be any gimple invariant, not just constants.
+   So, [&x, &x] counts as a singleton.  */
+
 bool
-value_range::singleton_p (tree *result) const
+irange::singleton_p (tree *result) const
 {
+  if (!legacy_mode_p ())
+    {
+      if (num_pairs () == 1 && (wi::to_wide (tree_lower_bound ())
+                               == wi::to_wide (tree_upper_bound ())))
+       {
+         if (result)
+           *result = tree_lower_bound ();
+         return true;
+       }
+      return false;
+    }
   if (m_kind == VR_ANTI_RANGE)
     {
       if (nonzero_p ())
@@ -454,7 +559,7 @@ value_range::singleton_p (tree *result) const
          if (TYPE_PRECISION (type ()) == 1)
            {
              if (result)
-               *result = m_max;
+               *result = max ();
              return true;
            }
          return false;
@@ -462,10 +567,11 @@ value_range::singleton_p (tree *result) const
       if (num_pairs () == 1)
        {
          value_range vr0, vr1;
-         ranges_from_anti_range (this, &vr0, &vr1);
+         ranges_from_anti_range ((const value_range *) this, &vr0, &vr1);
          return vr0.singleton_p (result);
        }
     }
+  // Catches non-numeric extremes as well.
   if (m_kind == VR_RANGE
       && vrp_operand_equal_p (min (), max ())
       && is_gimple_min_invariant (min ()))
@@ -478,30 +584,31 @@ value_range::singleton_p (tree *result) const
 }
 
 /* Return 1 if VAL is inside value range.
-          0 if VAL is not inside value range.
+         0 if VAL is not inside value range.
         -2 if we cannot tell either way.
 
    Benchmark compile/20001226-1.c compilation time after changing this
    function.  */
 
 int
-value_range::value_inside_range (tree val) const
+irange::value_inside_range (tree val) const
 {
-  int cmp1, cmp2;
-
   if (varying_p ())
     return 1;
 
   if (undefined_p ())
     return 0;
 
-  cmp1 = operand_less_p (val, m_min);
+  if (!legacy_mode_p () && TREE_CODE (val) == INTEGER_CST)
+    return contains_p (val);
+
+  int cmp1 = operand_less_p (val, min ());
   if (cmp1 == -2)
     return -2;
   if (cmp1 == 1)
     return m_kind != VR_RANGE;
 
-  cmp2 = operand_less_p (m_max, val);
+  int cmp2 = operand_less_p (max (), val);
   if (cmp2 == -2)
     return -2;
 
@@ -514,30 +621,56 @@ value_range::value_inside_range (tree val) const
 /* Return TRUE if it is possible that range contains VAL.  */
 
 bool
-value_range::may_contain_p (tree val) const
+irange::may_contain_p (tree val) const
 {
   return value_inside_range (val) != 0;
 }
 
 /* Return TRUE if range contains INTEGER_CST.  */
+/* Return 1 if VAL is inside value range.
+         0 if VAL is not inside value range.
+
+   Benchmark compile/20001226-1.c compilation time after changing this
+   function.  */
+
 
 bool
-value_range::contains_p (tree cst) const
+irange::contains_p (tree cst) const
 {
+  if (undefined_p ())
+    return false;
+
+  if (legacy_mode_p ())
+    {
+      gcc_checking_assert (TREE_CODE (cst) == INTEGER_CST);
+      if (symbolic_p ())
+       {
+         value_range numeric_range (*this);
+         numeric_range.normalize_symbolics ();
+         return numeric_range.contains_p (cst);
+       }
+      return value_inside_range (cst) == 1;
+    }
+
   gcc_checking_assert (TREE_CODE (cst) == INTEGER_CST);
-  if (symbolic_p ())
+  signop sign = TYPE_SIGN (TREE_TYPE (cst));
+  wide_int v = wi::to_wide (cst);
+  for (unsigned r = 0; r < m_num_ranges; ++r)
     {
-      value_range numeric_range (*this);
-      numeric_range.normalize_symbolics ();
-      return numeric_range.contains_p (cst);
+      if (wi::lt_p (v, lower_bound (r), sign))
+       return false;
+      if (wi::le_p (v, upper_bound (r), sign))
+       return true;
     }
-  return value_inside_range (cst) == 1;
+
+  return false;
 }
 
+
 /* Normalize addresses into constants.  */
 
 void
-value_range::normalize_addresses ()
+irange::normalize_addresses ()
 {
   if (undefined_p ())
     return;
@@ -547,8 +680,8 @@ value_range::normalize_addresses ()
 
   if (!range_includes_zero_p (this))
     {
-      gcc_checking_assert (TREE_CODE (m_min) == ADDR_EXPR
-                          || TREE_CODE (m_max) == ADDR_EXPR);
+      gcc_checking_assert (TREE_CODE (min ()) == ADDR_EXPR
+                          || TREE_CODE (max ()) == ADDR_EXPR);
       set_nonzero (type ());
       return;
     }
@@ -558,7 +691,7 @@ value_range::normalize_addresses ()
 /* Normalize symbolics and addresses into constants.  */
 
 void
-value_range::normalize_symbolics ()
+irange::normalize_symbolics ()
 {
   if (varying_p () || undefined_p ())
     return;
@@ -939,45 +1072,64 @@ intersect_ranges (enum value_range_kind *vr0type,
 }
 
 /* Helper for the intersection operation for value ranges.  Given two
-   value ranges VR0 and VR1, return the intersection of the two
-   ranges.  This may not be the smallest possible such range.  */
+   ranges VR0 and VR1, set VR0 to the intersection of both ranges.
+   This may not be the smallest possible such range.  */
 
-value_range
-value_range::intersect_helper (const value_range *vr0, const value_range *vr1)
+void
+irange::legacy_intersect (irange *vr0, const irange *vr1)
 {
   /* If either range is VR_VARYING the other one wins.  */
   if (vr1->varying_p ())
-    return *vr0;
+    return;
   if (vr0->varying_p ())
-    return *vr1;
+    {
+      /* Avoid the full copy if we already know both sides are simple
+        and can be trivially copied.  */
+      if (vr1->legacy_mode_p ())
+       {
+         vr0->set (vr1->min (), vr1->max (), vr1->kind ());
+         return;
+       }
+      *vr0 = *vr1;
+      return;
+    }
 
   /* When either range is VR_UNDEFINED the resulting range is
      VR_UNDEFINED, too.  */
   if (vr0->undefined_p ())
-    return *vr0;
+    return;
   if (vr1->undefined_p ())
-    return *vr1;
+    {
+      vr0->set_undefined ();
+      return;
+    }
 
   value_range_kind vr0kind = vr0->kind ();
   tree vr0min = vr0->min ();
   tree vr0max = vr0->max ();
-  intersect_ranges (&vr0kind, &vr0min, &vr0max,
-                   vr1->kind (), vr1->min (), vr1->max ());
+  /* Handle multi-ranges that can be represented as anti-ranges.  */
+  if (!vr1->legacy_mode_p () && vr1->maybe_anti_range ())
+    {
+      int_range<3> tmp (*vr1);
+      tmp.invert ();
+      intersect_ranges (&vr0kind, &vr0min, &vr0max,
+                       VR_ANTI_RANGE, tmp.min (), tmp.max ());
+    }
+  else
+    intersect_ranges (&vr0kind, &vr0min, &vr0max,
+                     vr1->kind (), vr1->min (), vr1->max ());
+
   /* Make sure to canonicalize the result though as the inversion of a
-     VR_RANGE can still be a VR_RANGE.  Work on a temporary so we can
-     fall back to vr0 when this turns things to varying.  */
-  value_range tem;
+     VR_RANGE can still be a VR_RANGE.  */
   if (vr0kind == VR_UNDEFINED)
-    tem.set_undefined ();
+    vr0->set_undefined ();
   else if (vr0kind == VR_VARYING)
-    tem.set_varying (vr0->type ());
+    {
+      /* If we failed, use the original VR0.  */
+      return;
+    }
   else
-    tem.set (vr0min, vr0max, vr0kind);
-  /* If that failed, use the saved original VR0.  */
-  if (tem.varying_p ())
-    return *vr0;
-
-  return tem;
+    vr0->set (vr0min, vr0max, vr0kind);
 }
 
 /* Union the two value-ranges { *VR0TYPE, *VR0MIN, *VR0MAX } and
@@ -1253,50 +1405,67 @@ give_up:
   *vr0max = NULL_TREE;
 }
 
-/* Helper for meet operation for value ranges.  Given two value ranges VR0 and
-   VR1, return a range that contains both VR0 and VR1.  This may not be the
+/* Helper for meet operation for value ranges.  Given two ranges VR0
+   and VR1, set VR0 to the union of both ranges.  This may not be the
    smallest possible such range.  */
 
-value_range
-value_range::union_helper (const value_range *vr0, const value_range *vr1)
+void
+irange::legacy_union (irange *vr0, const irange *vr1)
 {
   /* VR0 has the resulting range if VR1 is undefined or VR0 is varying.  */
   if (vr1->undefined_p ()
       || vr0->varying_p ())
-    return *vr0;
+    return;
 
   /* VR1 has the resulting range if VR0 is undefined or VR1 is varying.  */
-  if (vr0->undefined_p ()
-      || vr1->varying_p ())
-    return *vr1;
+  if (vr0->undefined_p ())
+    {
+      /* Avoid the full copy if we already know both sides are simple
+        and can be trivially copied.  */
+      if (vr1->legacy_mode_p ())
+       {
+         vr0->set (vr1->min (), vr1->max (), vr1->kind ());
+         return;
+       }
+      *vr0 = *vr1;
+      return;
+    }
+  if (vr1->varying_p ())
+    {
+      vr0->set_varying (vr1->type ());
+      return;
+    }
 
   value_range_kind vr0kind = vr0->kind ();
   tree vr0min = vr0->min ();
   tree vr0max = vr0->max ();
-  union_ranges (&vr0kind, &vr0min, &vr0max,
-               vr1->kind (), vr1->min (), vr1->max ());
+  /* Handle multi-ranges that can be represented as anti-ranges.  */
+  if (!vr1->legacy_mode_p () && vr1->maybe_anti_range ())
+    {
+      int_range<3> tmp (*vr1);
+      tmp.invert ();
+      union_ranges (&vr0kind, &vr0min, &vr0max,
+                   VR_ANTI_RANGE, tmp.min (), tmp.max ());
+    }
+  else
+    union_ranges (&vr0kind, &vr0min, &vr0max,
+                 vr1->kind (), vr1->min (), vr1->max ());
 
-  /* Work on a temporary so we can still use vr0 when union returns varying.  */
-  value_range tem;
   if (vr0kind == VR_UNDEFINED)
-    tem.set_undefined ();
+    vr0->set_undefined ();
   else if (vr0kind == VR_VARYING)
-    tem.set_varying (vr0->type ());
-  else
-    tem.set (vr0min, vr0max, vr0kind);
-
-  /* Failed to find an efficient meet.  Before giving up and setting
-     the result to VARYING, see if we can at least derive a useful
-     anti-range.  */
-  if (tem.varying_p ()
-      && range_includes_zero_p (vr0) == 0
-      && range_includes_zero_p (vr1) == 0)
     {
-      tem.set_nonzero (vr0->type ());
-      return tem;
+      /* Failed to find an efficient meet.  Before giving up and
+        setting the result to VARYING, see if we can at least derive
+        a non-zero range.  */
+      if (range_includes_zero_p (vr0) == 0
+         && range_includes_zero_p (vr1) == 0)
+       vr0->set_nonzero (vr0->type ());
+      else
+       vr0->set_varying (vr0->type ());
     }
-
-  return tem;
+  else
+    vr0->set (vr0min, vr0max, vr0kind);
 }
 
 /* Meet operation for value ranges.  Given two value ranges VR0 and
@@ -1304,161 +1473,495 @@ value_range::union_helper (const value_range *vr0, const value_range *vr1)
    may not be the smallest possible such range.  */
 
 void
-value_range::union_ (const value_range *other)
+irange::union_ (const irange *other)
 {
-  if (dump_file && (dump_flags & TDF_DETAILS))
+  if (legacy_mode_p ())
     {
-      fprintf (dump_file, "Meeting\n  ");
-      dump_value_range (dump_file, this);
-      fprintf (dump_file, "\nand\n  ");
-      dump_value_range (dump_file, other);
-      fprintf (dump_file, "\n");
-    }
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "Meeting\n  ");
+         dump_value_range (dump_file, this);
+         fprintf (dump_file, "\nand\n  ");
+         dump_value_range (dump_file, other);
+         fprintf (dump_file, "\n");
+       }
 
-  *this = union_helper (this, other);
+      legacy_union (this, other);
 
-  if (dump_file && (dump_flags & TDF_DETAILS))
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "to\n  ");
+         dump_value_range (dump_file, this);
+         fprintf (dump_file, "\n");
+       }
+      return;
+    }
+
+  if (other->legacy_mode_p ())
     {
-      fprintf (dump_file, "to\n  ");
-      dump_value_range (dump_file, this);
-      fprintf (dump_file, "\n");
+      int_range<2> wider;
+      wider = *other;
+      irange_union (wider);
     }
+  else
+    irange_union (*other);
 }
 
-/* Range union, but for references.  */
-
 void
-value_range::union_ (const value_range &r)
+irange::intersect (const irange *other)
 {
-  /* Disable details for now, because it makes the ranger dump
-     unnecessarily verbose.  */
-  bool details = dump_flags & TDF_DETAILS;
-  if (details)
-    dump_flags &= ~TDF_DETAILS;
-  union_ (&r);
-  if (details)
-    dump_flags |= TDF_DETAILS;
+  if (legacy_mode_p ())
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "Intersecting\n  ");
+         dump_value_range (dump_file, this);
+         fprintf (dump_file, "\nand\n  ");
+         dump_value_range (dump_file, other);
+         fprintf (dump_file, "\n");
+       }
+
+      legacy_intersect (this, other);
+
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "to\n  ");
+         dump_value_range (dump_file, this);
+         fprintf (dump_file, "\n");
+       }
+      return;
+    }
+
+  if (other->legacy_mode_p ())
+    {
+      int_range<2> wider;
+      wider = *other;
+      irange_intersect (wider);
+    }
+  else
+    irange_intersect (*other);
 }
 
+// union_ for multi-ranges.
+
 void
-value_range::intersect (const value_range *other)
+irange::irange_union (const irange &r)
 {
-  if (dump_file && (dump_flags & TDF_DETAILS))
+  gcc_checking_assert (!legacy_mode_p () && !r.legacy_mode_p ());
+
+  if (r.undefined_p () || varying_p ())
+    return;
+
+  if (undefined_p () || r.varying_p ())
     {
-      fprintf (dump_file, "Intersecting\n  ");
-      dump_value_range (dump_file, this);
-      fprintf (dump_file, "\nand\n  ");
-      dump_value_range (dump_file, other);
-      fprintf (dump_file, "\n");
+      operator= (r);
+      return;
     }
 
-  *this = intersect_helper (this, other);
+  // Do not worry about merging and such by reserving twice as many
+  // pairs as needed, and then simply sort the 2 ranges into this
+  // intermediate form.
+  //
+  // The intermediate result will have the property that the beginning
+  // of each range is <= the beginning of the next range.  There may
+  // be overlapping ranges at this point.  I.e. this would be valid
+  // [-20, 10], [-10, 0], [0, 20], [40, 90] as it satisfies this
+  // contraint : -20 < -10 < 0 < 40.  When the range is rebuilt into r,
+  // the merge is performed.
+  //
+  // [Xi,Yi]..[Xn,Yn]  U  [Xj,Yj]..[Xm,Ym]   -->  [Xk,Yk]..[Xp,Yp]
+  tree ttype = r.type ();
+  signop sign = TYPE_SIGN (ttype);
+
+  auto_vec<tree, 20> res;
+  wide_int u1 ;
+  wi::overflow_type ovf;
+  unsigned i = 0, j = 0, k = 0;
+
+  while (i < m_num_ranges * 2 && j < r.m_num_ranges * 2)
+    {
+      // lower of Xi and Xj is the lowest point.
+      if (wi::le_p (wi::to_wide (m_base[i]), wi::to_wide (r.m_base[j]), sign))
+       {
+         res.safe_push (m_base[i]);
+         res.safe_push (m_base[i + 1]);
+         k += 2;
+         i += 2;
+       }
+      else
+       {
+         res.safe_push (r.m_base[j]);
+         res.safe_push (r.m_base[j + 1]);
+         k += 2;
+         j += 2;
+       }
+    }
+  for ( ; i < m_num_ranges * 2; i += 2)
+    {
+      res.safe_push (m_base[i]);
+      res.safe_push (m_base[i + 1]);
+      k += 2;
+    }
+  for ( ; j < r.m_num_ranges * 2; j += 2)
+    {
+      res.safe_push (r.m_base[j]);
+      res.safe_push (r.m_base[j + 1]);
+      k += 2;
+    }
 
-  if (dump_file && (dump_flags & TDF_DETAILS))
+  // Now normalize the vector removing any overlaps.
+  i = 2;
+  int prec = TYPE_PRECISION (ttype);
+  wide_int max_val = wi::max_value (prec, sign);
+  for (j = 2; j < k ; j += 2)
     {
-      fprintf (dump_file, "to\n  ");
-      dump_value_range (dump_file, this);
-      fprintf (dump_file, "\n");
+      wide_int val_im1 = wi::to_wide (res[i - 1]);
+      if (val_im1 == max_val)
+       break;
+      u1 = wi::add (val_im1, 1, sign, &ovf);
+
+      // Overflow indicates we are at MAX already.
+      // A wide int bug requires the previous max_val check
+      // trigger: gcc.c-torture/compile/pr80443.c  with -O3
+      if (ovf == wi::OVF_OVERFLOW)
+       break;
+
+      wide_int val_j = wi::to_wide (res[j]);
+      wide_int val_jp1 = wi::to_wide (res[j+1]);
+      // Current upper+1 is >= lower bound next pair, then we merge ranges.
+      if (wi::ge_p (u1, val_j, sign))
+       {
+         // New upper bounds is greater of current or the next one.
+         if (wi::gt_p (val_jp1, val_im1, sign))
+           res [i - 1] = res[j + 1];
+       }
+      else
+       {
+         // This is a new distinct range, but no point in copying it
+         // if it is already in the right place.
+         if (i != j)
+           {
+             res[i++] = res[j];
+             res[i++] = res[j + 1];
+           }
+         else
+           i += 2;
+       }
     }
+
+  // At this point, the vector should have i ranges, none overlapping.
+  // Now it simply needs to be copied, and if there are too many
+  // ranges, merge some.  We wont do any analysis as to what the
+  // "best" merges are, simply combine the final ranges into one.
+  if (i > m_max_ranges * 2)
+    {
+      res[m_max_ranges * 2 - 1] = res[i - 1];
+      i = m_max_ranges * 2;
+    }
+
+  for (j = 0; j < i ; j++)
+    m_base[j] = res [j];
+  m_num_ranges = i / 2;
+
+  if (flag_checking)
+    verify_range ();
 }
 
-/* Range intersect, but for references.  */
+// intersect for multi-ranges.
 
 void
-value_range::intersect (const value_range &r)
+irange::irange_intersect (const irange &r)
+{
+  gcc_checking_assert (!legacy_mode_p () && !r.legacy_mode_p ());
+
+  if (undefined_p () || r.varying_p ())
+    return;
+  if (r.undefined_p ())
+    {
+      set_undefined ();
+      return;
+    }
+  if (varying_p ())
+    {
+      operator= (r);
+      return;
+    }
+
+  signop sign = TYPE_SIGN (TREE_TYPE(m_base[0]));
+  unsigned bld_pair = 0;
+  unsigned bld_lim = m_max_ranges;
+  widest_irange r2 (*this);
+  unsigned r2_lim = r2.num_pairs ();
+  unsigned i2 = 0;
+  for (unsigned i = 0; i < r.num_pairs (); )
+    {
+      // If r1's upper is < r2's lower, we can skip r1's pair.
+      tree ru = r.m_base[i * 2 + 1];
+      tree r2l = r2.m_base[i2 * 2];
+      if (wi::lt_p (wi::to_wide (ru), wi::to_wide (r2l), sign))
+       {
+         i++;
+         continue;
+       }
+      // Likewise, skip r2's pair if its excluded.
+      tree r2u = r2.m_base[i2 * 2 + 1];
+      tree rl = r.m_base[i * 2];
+      if (wi::lt_p (wi::to_wide (r2u), wi::to_wide (rl), sign))
+       {
+         i2++;
+         if (i2 < r2_lim)
+           continue;
+         // No more r2, break.
+         break;
+       }
+
+      // Must be some overlap.  Find the highest of the lower bounds,
+      // and set it, unless the build limits lower bounds is already
+      // set.
+      if (bld_pair < bld_lim)
+       {
+         if (wi::ge_p (wi::to_wide (rl), wi::to_wide (r2l), sign))
+           m_base[bld_pair * 2] = rl;
+         else
+           m_base[bld_pair * 2] = r2l;
+       }
+      else
+       // Decrease and set a new upper.
+       bld_pair--;
+
+      // ...and choose the lower of the upper bounds.
+      if (wi::le_p (wi::to_wide (ru), wi::to_wide (r2u), sign))
+       {
+         m_base[bld_pair * 2 + 1] = ru;
+         bld_pair++;
+         // Move past the r1 pair and keep trying.
+         i++;
+         continue;
+       }
+      else
+       {
+         m_base[bld_pair * 2 + 1] = r2u;
+         bld_pair++;
+         i2++;
+         if (i2 < r2_lim)
+           continue;
+         // No more r2, break.
+         break;
+       }
+      // r2 has the higher lower bound.
+    }
+
+  // At the exit of this loop, it is one of 2 things:
+  // ran out of r1, or r2, but either means we are done.
+  m_num_ranges = bld_pair;
+  if (flag_checking)
+    verify_range ();
+}
+
+static wide_int inline
+subtract_one (const wide_int &x, tree type, wi::overflow_type &overflow)
 {
-  /* Disable details for now, because it makes the ranger dump
-     unnecessarily verbose.  */
-  bool details = dump_flags & TDF_DETAILS;
-  if (details)
-    dump_flags &= ~TDF_DETAILS;
-  intersect (&r);
-  if (details)
-    dump_flags |= TDF_DETAILS;
+  // A signed 1-bit bit-field, has a range of [-1,0] so subtracting +1
+  // overflows, since +1 is unrepresentable.  This is why we have an
+  // addition of -1 here.
+  if (TYPE_SIGN (type) == SIGNED)
+    return wi::add (x, -1 , SIGNED, &overflow);
+  else
+    return wi::sub (x, 1, UNSIGNED, &overflow);
 }
 
 /* Return the inverse of a range.  */
 
 void
-value_range::invert ()
+irange::invert ()
 {
-  /* We can't just invert VR_RANGE and VR_ANTI_RANGE because we may
-     create non-canonical ranges.  Use the constructors instead.  */
-  if (m_kind == VR_RANGE)
-    *this = value_range (m_min, m_max, VR_ANTI_RANGE);
-  else if (m_kind == VR_ANTI_RANGE)
-    *this = value_range (m_min, m_max);
+  if (legacy_mode_p ())
+    {
+      // We can't just invert VR_RANGE and VR_ANTI_RANGE because we may
+      // create non-canonical ranges.  Use the constructors instead.
+      if (m_kind == VR_RANGE)
+       *this = value_range (min (), max (), VR_ANTI_RANGE);
+      else if (m_kind == VR_ANTI_RANGE)
+       *this = value_range (min (), max ());
+      else
+       gcc_unreachable ();
+      return;
+    }
+
+  gcc_assert (!undefined_p () && !varying_p ());
+
+  // We always need one more set of bounds to represent an inverse, so
+  // if we're at the limit, we can't properly represent things.
+  //
+  // For instance, to represent the inverse of a 2 sub-range set
+  // [5, 10][20, 30], we would need a 3 sub-range set
+  // [-MIN, 4][11, 19][31, MAX].
+  //
+  // In this case, return the most conservative thing.
+  //
+  // However, if any of the extremes of the range are -MIN/+MAX, we
+  // know we will not need an extra bound.  For example:
+  //
+  //   INVERT([-MIN,20][30,40]) => [21,29][41,+MAX]
+  //   INVERT([-MIN,20][30,MAX]) => [21,29]
+  tree ttype = type ();
+  unsigned prec = TYPE_PRECISION (ttype);
+  signop sign = TYPE_SIGN (ttype);
+  wide_int type_min = wi::min_value (prec, sign);
+  wide_int type_max = wi::max_value (prec, sign);
+  if (m_num_ranges == m_max_ranges
+      && lower_bound () != type_min
+      && upper_bound () != type_max)
+    {
+      m_base[1] = wide_int_to_tree (ttype, type_max);
+      m_num_ranges = 1;
+      return;
+    }
+  // The algorithm is as follows.  To calculate INVERT ([a,b][c,d]), we
+  // generate [-MIN, a-1][b+1, c-1][d+1, MAX].
+  //
+  // If there is an over/underflow in the calculation for any
+  // sub-range, we eliminate that subrange.  This allows us to easily
+  // calculate INVERT([-MIN, 5]) with: [-MIN, -MIN-1][6, MAX].  And since
+  // we eliminate the underflow, only [6, MAX] remains.
+  unsigned i = 0;
+  wi::overflow_type ovf;
+  // Construct leftmost range.
+  widest_irange orig_range (*this);
+  unsigned nitems = 0;
+  wide_int tmp;
+  // If this is going to underflow on the MINUS 1, don't even bother
+  // checking.  This also handles subtracting one from an unsigned 0,
+  // which doesn't set the underflow bit.
+  if (type_min != orig_range.lower_bound ())
+    {
+      m_base[nitems++] = wide_int_to_tree (ttype, type_min);
+      tmp = subtract_one (orig_range.lower_bound (), ttype, ovf);
+      m_base[nitems++] = wide_int_to_tree (ttype, tmp);
+      if (ovf)
+       nitems = 0;
+    }
+  i++;
+  // Construct middle ranges if applicable.
+  if (orig_range.num_pairs () > 1)
+    {
+      unsigned j = i;
+      for (; j < (orig_range.num_pairs () * 2) - 1; j += 2)
+       {
+         // The middle ranges cannot have MAX/MIN, so there's no need
+         // to check for unsigned overflow on the +1 and -1 here.
+         tmp = wi::add (wi::to_wide (orig_range.m_base[j]), 1, sign, &ovf);
+         m_base[nitems++] = wide_int_to_tree (ttype, tmp);
+         tmp = subtract_one (wi::to_wide (orig_range.m_base[j + 1]),
+                             ttype, ovf);
+         m_base[nitems++] = wide_int_to_tree (ttype, tmp);
+         if (ovf)
+           nitems -= 2;
+       }
+      i = j;
+    }
+  // Construct rightmost range.
+  //
+  // However, if this will overflow on the PLUS 1, don't even bother.
+  // This also handles adding one to an unsigned MAX, which doesn't
+  // set the overflow bit.
+  if (type_max != wi::to_wide (orig_range.m_base[i]))
+    {
+      tmp = wi::add (wi::to_wide (orig_range.m_base[i]), 1, sign, &ovf);
+      m_base[nitems++] = wide_int_to_tree (ttype, tmp);
+      m_base[nitems++] = wide_int_to_tree (ttype, type_max);
+      if (ovf)
+       nitems -= 2;
+    }
+  m_num_ranges = nitems / 2;
+
+  if (flag_checking)
+    verify_range ();
+}
+
+static void
+dump_bound_with_infinite_markers (FILE *file, tree bound)
+{
+  tree type = TREE_TYPE (bound);
+  if (INTEGRAL_TYPE_P (type)
+      && !TYPE_UNSIGNED (type)
+      && vrp_val_is_min (bound)
+      && TYPE_PRECISION (type) != 1)
+    fprintf (file, "-INF");
+  else if (vrp_val_is_max (bound)
+          && TYPE_PRECISION (type) != 1)
+    fprintf (file, "+INF");
   else
-    gcc_unreachable ();
+    print_generic_expr (file, bound);
 }
 
 void
-value_range::dump (FILE *file) const
+irange::dump (FILE *file) const
 {
   if (undefined_p ())
-    fprintf (file, "UNDEFINED");
-  else if (m_kind == VR_RANGE || m_kind == VR_ANTI_RANGE)
     {
-      tree ttype = type ();
-
-      print_generic_expr (file, ttype);
-      fprintf (file, " ");
-
+      fprintf (file, "UNDEFINED");
+      return;
+    }
+  print_generic_expr (file, type ());
+  fprintf (file, " ");
+  if (varying_p ())
+    {
+      fprintf (file, "VARYING");
+      return;
+    }
+ if (legacy_mode_p ())
+    {
       fprintf (file, "%s[", (m_kind == VR_ANTI_RANGE) ? "~" : "");
-
-      if (INTEGRAL_TYPE_P (ttype)
-         && !TYPE_UNSIGNED (ttype)
-         && vrp_val_is_min (min ())
-         && TYPE_PRECISION (ttype) != 1)
-       fprintf (file, "-INF");
-      else
-       print_generic_expr (file, min ());
-
+      dump_bound_with_infinite_markers (file, min ());
       fprintf (file, ", ");
-
-      if (supports_type_p (ttype)
-         && vrp_val_is_max (max ())
-         && TYPE_PRECISION (ttype) != 1)
-       fprintf (file, "+INF");
-      else
-       print_generic_expr (file, max ());
-
+      dump_bound_with_infinite_markers (file, max ());
       fprintf (file, "]");
+      return;
     }
-  else if (varying_p ())
+  for (unsigned i = 0; i < m_num_ranges; ++i)
     {
-      print_generic_expr (file, type ());
-      fprintf (file, " VARYING");
+      tree lb = m_base[i * 2];
+      tree ub = m_base[i * 2 + 1];
+      fprintf (file, "[");
+      dump_bound_with_infinite_markers (file, lb);
+      fprintf (file, ", ");
+      dump_bound_with_infinite_markers (file, ub);
+      fprintf (file, "]");
     }
-  else
-    gcc_unreachable ();
 }
 
 void
-value_range::dump () const
+dump_value_range (FILE *file, const irange *vr)
 {
-  dump (stderr);
+  vr->dump (file);
 }
 
-void
-dump_value_range (FILE *file, const value_range *vr)
+DEBUG_FUNCTION void
+debug (const irange *vr)
 {
-  if (!vr)
-    fprintf (file, "[]");
-  else
-    vr->dump (file);
+  dump_value_range (stderr, vr);
+  fprintf (stderr, "\n");
+}
+
+DEBUG_FUNCTION void
+debug (const irange &vr)
+{
+  debug (&vr);
 }
 
 DEBUG_FUNCTION void
 debug (const value_range *vr)
 {
   dump_value_range (stderr, vr);
+  fprintf (stderr, "\n");
 }
 
 DEBUG_FUNCTION void
 debug (const value_range &vr)
 {
   dump_value_range (stderr, &vr);
+  fprintf (stderr, "\n");
 }
 
 /* Create two value-ranges in *VR0 and *VR1 from the anti-range *AR
@@ -1501,40 +2004,13 @@ ranges_from_anti_range (const value_range *ar,
 }
 
 bool
-range_has_numeric_bounds_p (const value_range *vr)
+range_has_numeric_bounds_p (const irange *vr)
 {
-  return (vr->min ()
+  return (!vr->undefined_p ()
          && TREE_CODE (vr->min ()) == INTEGER_CST
          && TREE_CODE (vr->max ()) == INTEGER_CST);
 }
 
-/* Return the maximum value for TYPE.  */
-
-tree
-vrp_val_max (const_tree type)
-{
-  if (INTEGRAL_TYPE_P (type))
-    return TYPE_MAX_VALUE (type);
-  if (POINTER_TYPE_P (type))
-    {
-      wide_int max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type));
-      return wide_int_to_tree (const_cast<tree> (type), max);
-    }
-  return NULL_TREE;
-}
-
-/* Return the minimum value for TYPE.  */
-
-tree
-vrp_val_min (const_tree type)
-{
-  if (INTEGRAL_TYPE_P (type))
-    return TYPE_MIN_VALUE (type);
-  if (POINTER_TYPE_P (type))
-    return build_zero_cst (const_cast<tree> (type));
-  return NULL_TREE;
-}
-
 /* Return whether VAL is equal to the maximum value of its type.
    We can't do a simple equality comparison with TYPE_MAX_VALUE because
    C typedefs and Ada subtypes can produce types whose TYPE_MAX_VALUE
@@ -1571,3 +2047,41 @@ vrp_operand_equal_p (const_tree val1, const_tree val2)
     return false;
   return true;
 }
+
+#define DEFINE_INT_RANGE_GC_STUBS(N)           \
+  void                                         \
+  gt_pch_nx (int_range<N> *&x)                 \
+  {                                            \
+    for (unsigned i = 0; i < N; ++i)           \
+      {                                                \
+       gt_pch_nx (x->m_ranges[i * 2]);         \
+       gt_pch_nx (x->m_ranges[i * 2 + 1]);     \
+      }                                                \
+  }                                            \
+                                               \
+  void                                         \
+  gt_ggc_mx (int_range<N> *&x)                 \
+  {                                            \
+    for (unsigned i = 0; i < N; ++i)           \
+      {                                                \
+         gt_ggc_mx (x->m_ranges[i * 2]);       \
+         gt_ggc_mx (x->m_ranges[i * 2 + 1]);   \
+      }                                                \
+  }
+
+#define DEFINE_INT_RANGE_INSTANCE(N)                                   \
+  template int_range<N>::int_range(tree, tree, value_range_kind);      \
+  template int_range<N>::int_range(tree_node *,                                \
+                                  const wide_int &,                    \
+                                  const wide_int &,                    \
+                                  value_range_kind);                   \
+  template int_range<N>::int_range(tree);                              \
+  template int_range<N>::int_range(const irange &);            \
+  template int_range<N>::int_range(const int_range &);                 \
+  template int_range<N>& int_range<N>::operator= (const int_range &);
+
+DEFINE_INT_RANGE_INSTANCE(1)
+DEFINE_INT_RANGE_INSTANCE(2)
+DEFINE_INT_RANGE_INSTANCE(3)
+DEFINE_INT_RANGE_INSTANCE(255)
+DEFINE_INT_RANGE_GC_STUBS(1)
index 0a9dc6f151f373096d6317595002e10920ac93ec..e3282c4ad03a22db557feabf818e5502fb4b39dd 100644 (file)
@@ -1,5 +1,7 @@
 /* Support routines for value ranges.
    Copyright (C) 2019-2020 Free Software Foundation, Inc.
+   Contributed by Aldy Hernandez <aldyh@redhat.com> and
+   Andrew Macleod <amacleod@redhat.com>.
 
 This file is part of GCC.
 
@@ -20,7 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_VALUE_RANGE_H
 #define GCC_VALUE_RANGE_H
 
-/* Types of value ranges.  */
+// Types of value ranges.
 enum value_range_kind
 {
   /* Empty range.  */
@@ -36,164 +38,292 @@ enum value_range_kind
 };
 
 // Range of values that can be associated with an SSA_NAME.
+//
+// This is the base class without any storage.
 
-class GTY((for_user)) value_range
+class irange
 {
 public:
-  value_range ();
-  value_range (tree, tree, value_range_kind = VR_RANGE);
-  value_range (tree type, const wide_int &, const wide_int &,
-              value_range_kind = VR_RANGE);
-  value_range (tree type);
-
+  // In-place setters.
   void set (tree, tree, value_range_kind = VR_RANGE);
-  void set (tree);
   void set_nonzero (tree);
   void set_zero (tree);
-
-  enum value_range_kind kind () const;
-  tree min () const;
-  tree max () const;
-
-  /* Types of value ranges.  */
-  bool symbolic_p () const;
-  bool constant_p () const;
-  bool undefined_p () const;
-  bool varying_p () const;
   void set_varying (tree type);
   void set_undefined ();
 
-  void union_ (const value_range *);
-  void intersect (const value_range *);
-  void union_ (const value_range &);
-  void intersect (const value_range &);
-
-  bool operator== (const value_range &) const;
-  bool operator!= (const value_range &) const /* = delete */;
-  bool equal_p (const value_range &) const;
-
-  /* Misc methods.  */
-  tree type () const;
-  bool may_contain_p (tree) const;
-  bool zero_p () const;
-  bool nonzero_p () const;
-  bool singleton_p (tree *result = NULL) const;
-  void dump (FILE *) const;
-  void dump () const;
-
+  // Range types.
   static bool supports_type_p (tree);
-  void normalize_symbolics ();
-  void normalize_addresses ();
+  tree type () const;
 
-  static const unsigned int m_max_pairs = 2;
-  bool contains_p (tree) const;
+  // Iteration over sub-ranges.
   unsigned num_pairs () const;
   wide_int lower_bound (unsigned = 0) const;
   wide_int upper_bound (unsigned) const;
   wide_int upper_bound () const;
+
+  // Predicates.
+  bool zero_p () const;
+  bool nonzero_p () const;
+  bool undefined_p () const;
+  bool varying_p () const;
+  bool singleton_p (tree *result = NULL) const;
+  bool contains_p (tree) const;
+
+  // In-place operators.
+  void union_ (const irange &);
+  void intersect (const irange &);
   void invert ();
 
+  // Operator overloads.
+  irange& operator= (const irange &);
+  bool operator== (const irange &) const;
+  bool operator!= (const irange &r) const { return !(*this == r); }
+
+  // Misc methods.
+  void dump (FILE * = stderr) const;
+
+  // Deprecated legacy public methods.
+  enum value_range_kind kind () const;         // DEPRECATED
+  tree min () const;                           // DEPRECATED
+  tree max () const;                           // DEPRECATED
+  bool symbolic_p () const;                    // DEPRECATED
+  bool constant_p () const;                    // DEPRECATED
+  void normalize_symbolics ();                 // DEPRECATED
+  void normalize_addresses ();                 // DEPRECATED
+  bool may_contain_p (tree) const;             // DEPRECATED
+  void set (tree);                             // DEPRECATED
+  bool equal_p (const irange &) const;         // DEPRECATED
+  void union_ (const class irange *);          // DEPRECATED
+  void intersect (const irange *);             // DEPRECATED
+
 protected:
-  void check ();
-  static value_range union_helper (const value_range *, const value_range *);
-  static value_range intersect_helper (const value_range *,
-                                      const value_range *);
-
-  friend void gt_ggc_mx_value_range (void *);
-  friend void gt_pch_p_11value_range (void *, void *,
-                                     gt_pointer_operator, void *);
-  friend void gt_pch_nx_value_range (void *);
-  friend void gt_ggc_mx (value_range &);
-  friend void gt_ggc_mx (value_range *&);
-  friend void gt_pch_nx (value_range &);
-  friend void gt_pch_nx (value_range *, gt_pointer_operator, void *);
-
-  enum value_range_kind m_kind;
-  tree m_min;
-  tree m_max;
+  irange (tree *, unsigned);
+  // potential promotion to public?
+  tree tree_lower_bound (unsigned = 0) const;
+  tree tree_upper_bound (unsigned) const;
+  tree tree_upper_bound () const;
+
+   // In-place operators.
+  void irange_union (const irange &);
+  void irange_intersect (const irange &);
+  void irange_set (tree, tree);
+  void irange_set_anti_range (tree, tree);
+
+  bool swap_out_of_order_endpoints (tree &min, tree &max, value_range_kind &);
+  bool normalize_min_max (tree type, tree min, tree max, value_range_kind);
+
+  bool legacy_mode_p () const;
+  bool legacy_equal_p (const irange &) const;
+  void legacy_union (irange *, const irange *);
+  void legacy_intersect (irange *, const irange *);
+  void verify_range ();
+  unsigned legacy_num_pairs () const;
+  wide_int legacy_lower_bound (unsigned = 0) const;
+  wide_int legacy_upper_bound (unsigned) const;
+  int value_inside_range (tree) const;
+  bool maybe_anti_range () const;
+  void copy_legacy_range (const irange &);
 
 private:
-  int value_inside_range (tree) const;
+  unsigned char m_num_ranges;
+  unsigned char m_max_ranges;
+  ENUM_BITFIELD(value_range_kind) m_kind : 8;
+  tree *m_base;
 };
 
-extern bool range_has_numeric_bounds_p (const value_range *);
+// Here we describe an irange with N pairs of ranges.  The storage for
+// the pairs is embedded in the class as an array.
+
+template<unsigned N>
+class GTY((user)) int_range : public irange
+{
+public:
+  int_range ();
+  int_range (tree, tree, value_range_kind = VR_RANGE);
+  int_range (tree type, const wide_int &, const wide_int &,
+            value_range_kind = VR_RANGE);
+  int_range (tree type);
+  int_range (const int_range &);
+  int_range (const irange &);
+  int_range& operator= (const int_range &);
+private:
+  template <unsigned X> friend void gt_ggc_mx (int_range<X> *);
+  template <unsigned X> friend void gt_pch_nx (int_range<X> *);
+  template <unsigned X> friend void gt_pch_nx (int_range<X> *,
+                                              gt_pointer_operator, void *);
+  // ?? hash-traits.h has its own extern for these, which is causing
+  // them to never be picked up by the templates.  For now, define
+  // elsewhere.
+  //template<unsigned X> friend void gt_ggc_mx (int_range<X> *&);
+  //template<unsigned X> friend void gt_pch_nx (int_range<X> *&);
+  friend void gt_ggc_mx (int_range<1> *&);
+  friend void gt_pch_nx (int_range<1> *&);
+
+  tree m_ranges[N*2];
+};
+
+// This is a special int_range<1> with only one pair, plus
+// VR_ANTI_RANGE magic to describe slightly more than can be described
+// in one pair.  It is described in the code as a "legacy range" (as
+// opposed to multi-ranges which have multiple sub-ranges).  It is
+// provided for backward compatibility with code that has not been
+// converted to multi-range irange's.
+//
+// There are copy operators to seamlessly copy to/fro multi-ranges.
+typedef int_range<1> value_range;
+
+// This is an "infinite" precision irange for use in temporary
+// calculations.
+typedef int_range<255> widest_irange;
+
+// Returns true for an old-school value_range as described above.
+inline bool
+irange::legacy_mode_p () const
+{
+  return m_max_ranges == 1;
+}
+
+extern bool range_has_numeric_bounds_p (const irange *);
 extern bool ranges_from_anti_range (const value_range *,
                                    value_range *, value_range *);
-extern void dump_value_range (FILE *, const value_range *);
+extern void dump_value_range (FILE *, const irange *);
 extern bool vrp_val_is_min (const_tree);
 extern bool vrp_val_is_max (const_tree);
-extern tree vrp_val_min (const_tree);
-extern tree vrp_val_max (const_tree);
 extern bool vrp_operand_equal_p (const_tree, const_tree);
 
-inline
-value_range::value_range ()
+inline value_range_kind
+irange::kind () const
+{
+  if (legacy_mode_p ())
+    return m_kind;
+
+  if (undefined_p ())
+    return VR_UNDEFINED;
+
+  if (varying_p ())
+    return VR_VARYING;
+
+  return VR_RANGE;
+}
+
+// Number of sub-ranges in a range.
+
+inline unsigned
+irange::num_pairs () const
 {
-  m_kind = VR_UNDEFINED;
-  m_min = m_max = NULL;
+  if (!legacy_mode_p ())
+    return m_num_ranges;
+  else
+    return legacy_num_pairs ();
 }
 
-inline value_range_kind
-value_range::kind () const
+inline tree
+irange::type () const
+{
+  gcc_checking_assert (!undefined_p ());
+  return TREE_TYPE (m_base[0]);
+}
+
+// Return the lower bound of a sub-range expressed as a tree.  PAIR is
+// the sub-range in question.
+
+inline tree
+irange::tree_lower_bound (unsigned pair) const
+{
+  return m_base[pair * 2];
+}
+
+// Return the upper bound of a sub-range expressed as a tree.  PAIR is
+// the sub-range in question.
+
+inline tree
+irange::tree_upper_bound (unsigned pair) const
 {
-  return m_kind;
+  return m_base[pair * 2 + 1];
 }
 
+// Return the highest bound of a range expressed as a tree.
+
 inline tree
-value_range::type () const
+irange::tree_upper_bound () const
 {
-  return TREE_TYPE (min ());
+  gcc_checking_assert (m_num_ranges);
+  return tree_upper_bound (m_num_ranges - 1);
 }
 
 inline tree
-value_range::min () const
+irange::min () const
 {
-  return m_min;
+  return tree_lower_bound (0);
 }
 
 inline tree
-value_range::max () const
+irange::max () const
 {
-  return m_max;
+  if (m_num_ranges)
+    return tree_upper_bound ();
+  else
+    return NULL;
 }
 
 inline bool
-value_range::varying_p () const
+irange::varying_p () const
 {
-  return m_kind == VR_VARYING;
+  if (legacy_mode_p ())
+    return m_kind == VR_VARYING;
+
+  if (m_num_ranges != 1)
+    return false;
+
+  tree l = m_base[0];
+  tree u = m_base[1];
+  tree t = TREE_TYPE (l);
+  if (INTEGRAL_TYPE_P (t))
+    return l == TYPE_MIN_VALUE (t) && u == TYPE_MAX_VALUE (t);
+  if (POINTER_TYPE_P (t))
+    return wi::to_wide (l) == 0
+          && wi::to_wide (u) == wi::max_value (TYPE_PRECISION (t),
+                                               TYPE_SIGN (t));
+  return true;
+
 }
 
 inline bool
-value_range::undefined_p () const
+irange::undefined_p () const
 {
+  if (!legacy_mode_p ())
+    return m_num_ranges == 0;
+
+  if (CHECKING_P && legacy_mode_p ())
+    {
+      if (m_kind == VR_UNDEFINED)
+       gcc_checking_assert (m_num_ranges == 0);
+      else
+       gcc_checking_assert (m_num_ranges != 0);
+    }
   return m_kind == VR_UNDEFINED;
 }
 
 inline bool
-value_range::zero_p () const
+irange::zero_p () const
 {
-  return (m_kind == VR_RANGE
-         && integer_zerop (m_min)
-         && integer_zerop (m_max));
+  return (m_kind == VR_RANGE && m_num_ranges == 1
+         && integer_zerop (tree_lower_bound (0))
+         && integer_zerop (tree_upper_bound (0)));
 }
 
 inline bool
-value_range::nonzero_p () const
+irange::nonzero_p () const
 {
-  if (m_kind == VR_ANTI_RANGE
-      && !TYPE_UNSIGNED (type ())
-      && integer_zerop (m_min)
-      && integer_zerop (m_max))
-    return true;
+  if (undefined_p ())
+    return false;
 
-  return (m_kind == VR_RANGE
-         && TYPE_UNSIGNED (type ())
-         && integer_onep (m_min)
-         && vrp_val_is_max (m_max));
+  tree zero = build_zero_cst (type ());
+  return *this == int_range<1> (zero, zero, VR_ANTI_RANGE);
 }
 
 inline bool
-value_range::supports_type_p (tree type)
+irange::supports_type_p (tree type)
 {
   if (type && (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)))
     return type;
@@ -201,7 +331,7 @@ value_range::supports_type_p (tree type)
 }
 
 inline bool
-range_includes_zero_p (const value_range *vr)
+range_includes_zero_p (const irange *vr)
 {
   if (vr->undefined_p ())
     return false;
@@ -212,4 +342,281 @@ range_includes_zero_p (const value_range *vr)
   return vr->may_contain_p (build_zero_cst (vr->type ()));
 }
 
+template<unsigned N>
+static inline void
+gt_ggc_mx (int_range<N> *x)
+{
+  for (unsigned i = 0; i < N; ++i)
+    {
+      gt_ggc_mx (x->m_ranges[i * 2]);
+      gt_ggc_mx (x->m_ranges[i * 2 + 1]);
+    }
+}
+
+template<unsigned N>
+static inline void
+gt_pch_nx (int_range<N> *x)
+{
+  for (unsigned i = 0; i < N; ++i)
+    {
+      gt_pch_nx (x->m_ranges[i * 2]);
+      gt_pch_nx (x->m_ranges[i * 2 + 1]);
+    }
+}
+
+template<unsigned N>
+static inline void
+gt_pch_nx (int_range<N> *x, gt_pointer_operator op, void *cookie)
+{
+  for (unsigned i = 0; i < N; ++i)
+    {
+      op (&x->m_ranges[i * 2], cookie);
+      op (&x->m_ranges[i * 2 + 1], cookie);
+    }
+}
+
+// Constructors for irange
+
+inline
+irange::irange (tree *base, unsigned nranges)
+{
+  m_base = base;
+  m_num_ranges = 0;
+  m_max_ranges = nranges;
+  if (legacy_mode_p ())
+    m_kind = VR_UNDEFINED;
+  else
+    m_kind = VR_RANGE;
+}
+
+// Constructors for int_range<>.
+
+template<unsigned N>
+inline
+int_range<N>::int_range ()
+  : irange (m_ranges, N)
+{
+}
+
+template<unsigned N>
+int_range<N>::int_range (const int_range &other)
+  : irange (m_ranges, N)
+{
+  irange::operator= (other);
+}
+
+template<unsigned N>
+int_range<N>::int_range (tree min, tree max, value_range_kind kind)
+  : irange (m_ranges, N)
+{
+  irange::set (min, max, kind);
+}
+
+template<unsigned N>
+int_range<N>::int_range (tree type)
+  : irange (m_ranges, N)
+{
+  set_varying (type);
+}
+
+template<unsigned N>
+int_range<N>::int_range (tree type, const wide_int &wmin, const wide_int &wmax,
+                        value_range_kind kind)
+  : irange (m_ranges, N)
+{
+  tree min = wide_int_to_tree (type, wmin);
+  tree max = wide_int_to_tree (type, wmax);
+  set (min, max, kind);
+}
+
+template<unsigned N>
+int_range<N>::int_range (const irange &other)
+  : irange (m_ranges, N)
+{
+  irange::operator= (other);
+}
+
+template<unsigned N>
+int_range<N>&
+int_range<N>::operator= (const int_range &src)
+{
+  irange::operator= (src);
+  return *this;
+}
+
+inline void
+irange::set (tree val)
+{
+  set (val, val);
+}
+
+inline void
+irange::set_undefined ()
+{
+  m_num_ranges = 0;
+  if (legacy_mode_p ())
+    m_kind = VR_UNDEFINED;
+}
+
+inline void
+irange::set_varying (tree type)
+{
+  if (legacy_mode_p ())
+    m_kind = VR_VARYING;
+
+  m_num_ranges = 1;
+  if (INTEGRAL_TYPE_P (type))
+    {
+      m_base[0] = TYPE_MIN_VALUE (type);
+      m_base[1] = TYPE_MAX_VALUE (type);
+    }
+  else if (POINTER_TYPE_P (type))
+    {
+      m_base[0] = build_int_cst (type, 0);
+      m_base[1] = build_int_cst (type, -1);
+    }
+  else
+    m_base[0] = m_base[1] = error_mark_node;
+}
+
+inline bool
+irange::operator== (const irange &r) const
+{
+  return equal_p (r);
+}
+
+// Return the lower bound of a sub-range.  PAIR is the sub-range in
+// question.
+
+inline wide_int
+irange::lower_bound (unsigned pair) const
+{
+  if (legacy_mode_p ())
+    return legacy_lower_bound (pair);
+  gcc_checking_assert (!undefined_p ());
+  gcc_checking_assert (pair + 1 <= num_pairs ());
+  return wi::to_wide (tree_lower_bound (pair));
+}
+
+// Return the upper bound of a sub-range.  PAIR is the sub-range in
+// question.
+
+inline wide_int
+irange::upper_bound (unsigned pair) const
+{
+  if (legacy_mode_p ())
+    return legacy_upper_bound (pair);
+  gcc_checking_assert (!undefined_p ());
+  gcc_checking_assert (pair + 1 <= num_pairs ());
+  return wi::to_wide (tree_upper_bound (pair));
+}
+
+// Return the highest bound of a range.
+
+inline wide_int
+irange::upper_bound () const
+{
+  unsigned pairs = num_pairs ();
+  gcc_checking_assert (pairs > 0);
+  return upper_bound (pairs - 1);
+}
+
+inline void
+irange::union_ (const irange &r)
+{
+  dump_flags_t m_flags = dump_flags;
+  dump_flags &= ~TDF_DETAILS;
+  irange::union_ (&r);
+  dump_flags = m_flags;
+}
+
+inline void
+irange::intersect (const irange &r)
+{
+  dump_flags_t m_flags = dump_flags;
+  dump_flags &= ~TDF_DETAILS;
+  irange::intersect (&r);
+  dump_flags = m_flags;
+}
+
+// Set value range VR to a nonzero range of type TYPE.
+
+inline void
+irange::set_nonzero (tree type)
+{
+  tree zero = build_int_cst (type, 0);
+  if (legacy_mode_p ())
+    set (zero, zero, VR_ANTI_RANGE);
+  else
+    irange_set_anti_range (zero, zero);
+}
+
+// Set value range VR to a ZERO range of type TYPE.
+
+inline void
+irange::set_zero (tree type)
+{
+  tree z = build_int_cst (type, 0);
+  if (legacy_mode_p ())
+    set (z);
+  else
+    irange_set (z, z);
+}
+
+// Normalize [MIN, MAX] into VARYING and ~[MIN, MAX] into UNDEFINED.
+//
+// Avoid using TYPE_{MIN,MAX}_VALUE because -fstrict-enums can
+// restrict those to a subset of what actually fits in the type.
+// Instead use the extremes of the type precision which will allow
+// compare_range_with_value() to check if a value is inside a range,
+// whereas if we used TYPE_*_VAL, said function would just punt upon
+// seeing a VARYING.
+
+inline bool
+irange::normalize_min_max (tree type, tree min, tree max,
+                          value_range_kind kind)
+{
+  unsigned prec = TYPE_PRECISION (type);
+  signop sign = TYPE_SIGN (type);
+  if (wi::eq_p (wi::to_wide (min), wi::min_value (prec, sign))
+      && wi::eq_p (wi::to_wide (max), wi::max_value (prec, sign)))
+    {
+      if (kind == VR_RANGE)
+       set_varying (type);
+      else if (kind == VR_ANTI_RANGE)
+       set_undefined ();
+      else
+       gcc_unreachable ();
+      return true;
+    }
+  return false;
+}
+
+// Return the maximum value for TYPE.
+
+inline tree
+vrp_val_max (const_tree type)
+{
+  if (INTEGRAL_TYPE_P (type))
+    return TYPE_MAX_VALUE (type);
+  if (POINTER_TYPE_P (type))
+    {
+      wide_int max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type));
+      return wide_int_to_tree (const_cast<tree> (type), max);
+    }
+  return NULL_TREE;
+}
+
+// Return the minimum value for TYPE.
+
+inline tree
+vrp_val_min (const_tree type)
+{
+  if (INTEGRAL_TYPE_P (type))
+    return TYPE_MIN_VALUE (type);
+  if (POINTER_TYPE_P (type))
+    return build_zero_cst (const_cast<tree> (type));
+  return NULL_TREE;
+}
+
 #endif // GCC_VALUE_RANGE_H
index d0303599002604ff02268eab66b17237525ff7f7..609375c072eaa0ca18d0d9ef252b02e6ad36af23 100644 (file)
@@ -92,7 +92,8 @@ vr_values::get_lattice_entry (const_tree var)
     return vr;
 
   /* Create a default value range.  */
-  vr_value[ver] = vr = vrp_value_range_pool.allocate ();
+  vr = new (vrp_value_range_pool.allocate ()) value_range_equiv;
+  vr_value[ver] = vr;
 
   /* After propagation finished return varying.  */
   if (values_propagated)