diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 7adbf55c6a6..dc06f8b0078 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -260,66 +260,93 @@ frange::accept (const vrange_visitor &v) const
   v.visit (*this);
 }
 
-// Setter for franges.  Currently only singletons are supported.
+// Helper function to compare floats.  Returns TRUE if op1 .CODE. op2
+// is nonzero.
+
+static inline bool
+tree_compare (tree_code code, tree op1, tree op2)
+{
+  return !integer_zerop (fold_build2 (code, integer_type_node, op1, op2));
+}
+
+// Setter for franges.
 
 void
 frange::set (tree min, tree max, value_range_kind kind)
 {
-  gcc_checking_assert (kind == VR_RANGE);
-  gcc_checking_assert (operand_equal_p (min, max));
   gcc_checking_assert (TREE_CODE (min) == REAL_CST);
+  gcc_checking_assert (TREE_CODE (max) == REAL_CST);
+
+  if (kind == VR_UNDEFINED)
+    {
+      set_undefined ();
+      return;
+    }
+
+  // Treat VR_ANTI_RANGE and VR_VARYING as varying.
+  if (kind != VR_RANGE)
+    {
+      set_varying (TREE_TYPE (min));
+      return;
+    }
 
   m_kind = kind;
   m_type = TREE_TYPE (min);
 
-  REAL_VALUE_TYPE *const cst = TREE_REAL_CST_PTR (min);
-  if (real_isnan (cst))
-    m_props.nan_set_yes ();
-  else
-    m_props.nan_set_no ();
-
-  if (real_isinf (cst))
+  // Mark NANness.
+  if (real_isnan (TREE_REAL_CST_PTR (min))
+      || real_isnan (TREE_REAL_CST_PTR (max)))
     {
-      if (real_isneg (cst))
-	{
-	  m_props.inf_set_no ();
-	  m_props.ninf_set_yes ();
-	}
-      else
-	{
-	  m_props.inf_set_yes ();
-	  m_props.ninf_set_no ();
-	}
+      gcc_checking_assert (operand_equal_p (min, max));
+      m_props.nan_set_yes ();
     }
   else
+    m_props.nan_set_no ();
+
+  bool is_min = vrp_val_is_min (min);
+  bool is_max = vrp_val_is_max (max);
+
+  // Mark when the endpoints can't be INF.
+  if (!is_min)
+    m_props.ninf_set_no ();
+  if (!is_max)
+    m_props.inf_set_no ();
+
+  // Mark when the endpoints are definitely INF.
+  if (operand_equal_p (min, max))
     {
-      m_props.inf_set_no ();
-      m_props.ninf_set_no ();
+      if (is_min)
+	m_props.ninf_set_yes ();
+      else if (is_max)
+	m_props.inf_set_yes ();
     }
 
+  // Check for swapped ranges.
+  gcc_checking_assert (m_props.nan_yes_p ()
+		       || tree_compare (LE_EXPR, min, max));
+
   if (flag_checking)
     verify_range ();
 }
 
-// Normalize range to VARYING or UNDEFINED, or vice versa.
+// Normalize range to VARYING or UNDEFINED, or vice versa.  Return
+// TRUE if anything changed.
 //
 // A range with no known properties can be dropped to VARYING.
 // Similarly, a VARYING with any properties should be dropped to a
 // VR_RANGE.  Normalizing ranges upon changing them ensures there is
 // only one representation for a given range.
 
-void
+bool
 frange::normalize_kind ()
 {
   if (m_kind == VR_RANGE)
     {
       // No FP properties set means varying.
-      if (m_props.nan_varying_p ()
-	  && m_props.inf_varying_p ()
-	  && m_props.ninf_varying_p ())
+      if (m_props.varying_p ())
 	{
 	  set_varying (m_type);
-	  return;
+	  return true;
 	}
       // Undefined is viral.
       if (m_props.nan_undefined_p ()
@@ -327,17 +354,19 @@ frange::normalize_kind ()
 	  || m_props.ninf_undefined_p ())
 	{
 	  set_undefined ();
-	  return;
+	  return true;
 	}
     }
   else if (m_kind == VR_VARYING)
     {
       // If a VARYING has any FP properties, it's no longer VARYING.
-      if (!m_props.nan_varying_p ()
-	  || !m_props.inf_varying_p ()
-	  || !m_props.ninf_varying_p ())
-	m_kind = VR_RANGE;
+      if (!m_props.varying_p ())
+	{
+	  m_kind = VR_RANGE;
+	  return true;
+	}
     }
+  return false;
 }
 
 bool
@@ -354,7 +383,7 @@ frange::union_ (const vrange &v)
     }
 
   bool ret = m_props.union_ (r.m_props);
-  normalize_kind ();
+  ret |= normalize_kind ();
 
   if (flag_checking)
     verify_range ();
@@ -380,7 +409,7 @@ frange::intersect (const vrange &v)
     }
 
   bool ret = m_props.intersect (r.m_props);
-  normalize_kind ();
+  ret |= normalize_kind ();
 
   if (flag_checking)
     verify_range ();
@@ -429,12 +458,11 @@ frange::verify_range ()
       gcc_checking_assert (m_props.undefined_p ());
       return;
     }
-  else if (varying_p ())
+  if (varying_p ())
     {
       gcc_checking_assert (m_props.varying_p ());
       return;
     }
-
   gcc_checking_assert (m_kind == VR_RANGE);
   gcc_checking_assert (!m_props.varying_p () && !m_props.undefined_p ());
 }
diff --git a/gcc/value-range.h b/gcc/value-range.h
index c6ab955c407..390fcb8fd99 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -359,7 +359,7 @@ public:
   FRANGE_PROP_ACCESSOR(ninf)
 private:
   void verify_range ();
-  void normalize_kind ();
+  bool normalize_kind ();
 
   frange_props m_props;
   tree m_type;
@@ -1010,6 +1010,45 @@ irange::normalize_kind ()
     }
 }
 
+// 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);
+    }
+  if (frange::supports_p (type))
+    {
+      REAL_VALUE_TYPE real;
+      real_inf (&real);
+      return build_real (const_cast <tree> (type), real);
+    }
+  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));
+  if (frange::supports_p (type))
+    {
+      REAL_VALUE_TYPE real, real_ninf;
+      real_inf (&real);
+      real_ninf = real_value_negate (&real);
+      return build_real (const_cast <tree> (type), real_ninf);
+    }
+  return NULL_TREE;
+}
 
 // Supporting methods for frange.
 
@@ -1039,7 +1078,6 @@ inline
 frange::frange ()
 {
   m_discriminator = VR_FRANGE;
-  m_type = nullptr;
   set_undefined ();
 }
 
@@ -1072,32 +1110,4 @@ frange::set_undefined ()
   m_props.set_undefined ();
 }
 
-
-// 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
