diff --git a/gcc/data-streamer-in.cc b/gcc/data-streamer-in.cc
index 8ebcac43479..76954b12c95 100644
--- a/gcc/data-streamer-in.cc
+++ b/gcc/data-streamer-in.cc
@@ -28,6 +28,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple.h"
 #include "cgraph.h"
 #include "data-streamer.h"
+#include "value-range.h"
+#include "streamer-hooks.h"
 
 /* Read a string from the string table in DATA_IN using input block
    IB.  Write the length to RLEN.  */
@@ -206,6 +208,60 @@ streamer_read_gcov_count (class lto_input_block *ib)
   return ret;
 }
 
+/* Read REAL_VALUE_TYPE from IB.  */
+
+void
+streamer_read_real_value (class lto_input_block *ib, REAL_VALUE_TYPE *r)
+{
+  struct bitpack_d bp = streamer_read_bitpack (ib);
+  bp_unpack_real_value (&bp, r);
+}
+
+void
+streamer_read_value_range (class lto_input_block *ib, data_in *data_in,
+			   Value_Range &vr)
+{
+  // Read the common fields to all vranges.
+  value_range_kind kind = streamer_read_enum (ib, value_range_kind, VR_LAST);
+  gcc_checking_assert (kind != VR_UNDEFINED);
+  tree type = stream_read_tree (ib, data_in);
+
+  // Initialize the Value_Range to the correct type.
+  vr.set_type (type);
+
+  if (is_a <irange> (vr))
+    {
+      irange &r = as_a <irange> (vr);
+      r.set_undefined ();
+      unsigned HOST_WIDE_INT num_pairs = streamer_read_uhwi (ib);
+      for (unsigned i = 0; i < num_pairs; ++i)
+	{
+	  wide_int lb = streamer_read_wide_int (ib);
+	  wide_int ub = streamer_read_wide_int (ib);
+	  int_range<2> tmp (type, lb, ub);
+	  r.union_ (tmp);
+	}
+      wide_int nz = streamer_read_wide_int (ib);
+      r.set_nonzero_bits (nz);
+      return;
+    }
+  if (is_a <frange> (vr))
+    {
+      frange &r = as_a <frange> (vr);
+
+      r.m_type = type;
+      streamer_read_real_value (ib, &r.m_min);
+      streamer_read_real_value (ib, &r.m_max);
+      struct bitpack_d bp = streamer_read_bitpack (ib);
+      r.m_pos_nan = (bool) bp_unpack_value (&bp, 1);
+      r.m_neg_nan = (bool) bp_unpack_value (&bp, 1);
+      if (flag_checking)
+	r.verify_range ();
+      return;
+    }
+  gcc_unreachable ();
+}
+
 /* Read the physical representation of a wide_int val from
    input block IB.  */
 
diff --git a/gcc/data-streamer-out.cc b/gcc/data-streamer-out.cc
index cd25745b8dc..888fc395d0d 100644
--- a/gcc/data-streamer-out.cc
+++ b/gcc/data-streamer-out.cc
@@ -28,6 +28,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple.h"
 #include "cgraph.h"
 #include "data-streamer.h"
+#include "value-range.h"
+#include "streamer-hooks.h"
 
 
 /* Adds a new block to output stream OBS.  */
@@ -392,6 +394,52 @@ streamer_write_data_stream (struct lto_output_stream *obs, const void *data,
     }
 }
 
+/* Write REAL_VALUE_TYPE into OB.  */
+
+void
+streamer_write_real_value (struct output_block *ob, const REAL_VALUE_TYPE *r)
+{
+  bitpack_d bp = bitpack_create (ob->main_stream);
+  bp_pack_real_value (&bp, r);
+  streamer_write_bitpack (&bp);
+}
+
+void
+streamer_write_vrange (struct output_block *ob, const vrange &v)
+{
+  gcc_checking_assert (!v.undefined_p ());
+
+  // Write the common fields to all vranges.
+  value_range_kind kind = v.varying_p () ? VR_VARYING : VR_RANGE;
+  streamer_write_enum (ob->main_stream, value_range_kind, VR_LAST, kind);
+  stream_write_tree (ob, v.type (), true);
+
+  if (is_a <irange> (v))
+    {
+      const irange &r = as_a <irange> (v);
+      streamer_write_uhwi (ob, r.num_pairs ());
+      for (unsigned i = 0; i < r.num_pairs (); ++i)
+	{
+	  streamer_write_wide_int (ob, r.lower_bound (i));
+	  streamer_write_wide_int (ob, r.upper_bound (i));
+	}
+      streamer_write_wide_int (ob, r.get_nonzero_bits ());
+      return;
+    }
+  if (is_a <frange> (v))
+    {
+      const frange &r = as_a <frange> (v);
+      streamer_write_real_value (ob, &r.m_min);
+      streamer_write_real_value (ob, &r.m_max);
+      bitpack_d bp = bitpack_create (ob->main_stream);
+      bp_pack_value (&bp, r.m_pos_nan, 1);
+      bp_pack_value (&bp, r.m_neg_nan, 1);
+      streamer_write_bitpack (&bp);
+      return;
+    }
+  gcc_unreachable ();
+}
+
 /* Emit the physical representation of wide_int VAL to output block OB.  */
 
 void
diff --git a/gcc/data-streamer.h b/gcc/data-streamer.h
index 19c9d6ea606..7e69eb9992b 100644
--- a/gcc/data-streamer.h
+++ b/gcc/data-streamer.h
@@ -75,6 +75,7 @@ void streamer_write_data_stream (struct lto_output_stream *, const void *,
 				 size_t);
 void streamer_write_wide_int (struct output_block *, const wide_int &);
 void streamer_write_widest_int (struct output_block *, const widest_int &);
+void streamer_write_vrange (struct output_block *, const class vrange &);
 
 /* In data-streamer-in.cc  */
 const char *streamer_read_string (class data_in *, class lto_input_block *);
@@ -91,6 +92,8 @@ poly_int64 streamer_read_poly_int64 (class lto_input_block *);
 gcov_type streamer_read_gcov_count (class lto_input_block *);
 wide_int streamer_read_wide_int (class lto_input_block *);
 widest_int streamer_read_widest_int (class lto_input_block *);
+void streamer_read_value_range (class lto_input_block *, class data_in *,
+				class Value_Range &);
 
 /* Returns a new bit-packing context for bit-packing into S.  */
 inline struct bitpack_d
diff --git a/gcc/value-range.h b/gcc/value-range.h
index f8aa0ca7bec..e56df9db901 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -328,6 +328,10 @@ class frange : public vrange
 {
   friend class frange_storage_slot;
   friend class vrange_printer;
+  friend void streamer_write_vrange (struct output_block *, const vrange &);
+  friend void streamer_read_value_range (class lto_input_block *,
+					 class data_in *,
+					 class Value_Range &);
 public:
   frange ();
   frange (const frange &);
