From 13326e365f4c88ccce87422dc574739fd785bca2 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 5 Feb 2026 12:43:52 -0500
Subject: [PATCH 45/98] FIXME: gcc17: not-yet-working WIP on unifying concrete
 bit and byte offsets and sizes as "quantities"

---
 gcc/analyzer/access-diagram.cc               |  22 +-
 gcc/analyzer/access-diagram.h                |  21 +-
 gcc/analyzer/ana-state-to-diagnostic-state.h |   6 +-
 gcc/analyzer/analyzer.cc                     |  10 +-
 gcc/analyzer/call-summary.cc                 |   2 +-
 gcc/analyzer/common.h                        |  71 ++--
 gcc/analyzer/quantities.h                    | 362 +++++++++++++++++++
 gcc/analyzer/ranges.cc                       |   6 +-
 gcc/analyzer/record-layout.cc                |  28 +-
 gcc/analyzer/record-layout.h                 |  19 +-
 gcc/analyzer/region-model-infoleak.cc        |  32 +-
 gcc/analyzer/region-model-manager.cc         |  18 +-
 gcc/analyzer/region-model-manager.h          |   6 +-
 gcc/analyzer/region-model.h                  |   4 +-
 gcc/analyzer/region.cc                       |   5 +-
 gcc/analyzer/region.h                        |  44 +--
 gcc/analyzer/store.cc                        | 281 +++++++-------
 gcc/analyzer/store.h                         | 255 +++----------
 gcc/analyzer/svalue.cc                       |  49 +--
 gcc/analyzer/svalue.h                        |  28 +-
 20 files changed, 757 insertions(+), 512 deletions(-)
 create mode 100644 gcc/analyzer/quantities.h

diff --git a/gcc/analyzer/access-diagram.cc b/gcc/analyzer/access-diagram.cc
index 6a3ad635f0c0..e45d4df16bc6 100644
--- a/gcc/analyzer/access-diagram.cc
+++ b/gcc/analyzer/access-diagram.cc
@@ -202,16 +202,20 @@ class access_diagram_impl;
 class bit_to_table_map;
 
 static void
-pp_bit_size_t (pretty_printer *pp, bit_size_t num_bits)
+pp_byte_size_t (pretty_printer *pp, concrete_byte_size_t num_bytes)
 {
-  if (num_bits % BITS_PER_UNIT == 0)
-    {
-      byte_size_t num_bytes = num_bits / BITS_PER_UNIT;
-      if (num_bytes == 1)
-	pp_printf (pp, _("%wi byte"), num_bytes.to_uhwi ());
-      else
-	pp_printf (pp, _("%wi bytes"), num_bytes.to_uhwi ());
-    }
+  if (num_bytes == 1)
+    pp_printf (pp, _("%wi byte"), num_bytes.to_uhwi ());
+  else
+    pp_printf (pp, _("%wi bytes"), num_bytes.to_uhwi ());
+}
+
+static void
+pp_bit_size_t (pretty_printer *pp, concrete_bit_size_t num_bits)
+{
+  concrete_byte_size_t num_bytes;
+  if (maybe_as_bytes (num_bits, num_bytes))
+    pp_byte_size_t (pp, num_bytes);
   else
     {
       if (num_bits == 1)
diff --git a/gcc/analyzer/access-diagram.h b/gcc/analyzer/access-diagram.h
index 33c9864f4471..7e3617a05339 100644
--- a/gcc/analyzer/access-diagram.h
+++ b/gcc/analyzer/access-diagram.h
@@ -65,8 +65,8 @@ struct access_range
 		region_model_manager &mgr)
   : m_start (strip_types (start, mgr)), m_next (strip_types (next, mgr))
   {}
-  access_range (const region *base_region, const bit_range &bits);
-  access_range (const region *base_region, const byte_range &bytes);
+  access_range (const region *base_region, const concrete_bit_range_t &bits);
+  access_range (const region *base_region, const concrete_byte_range_t &bytes);
   access_range (const region &reg, region_model_manager *);
 
   bool concrete_p () const
@@ -78,30 +78,31 @@ struct access_range
 
   bit_size_expr get_size (region_model_manager *mgr) const;
 
-  bool get_size_in_bits (bit_size_t *out) const
+  bool get_size_in_bits (concrete_bit_size_t *out) const
   {
     if (concrete_p ())
       {
-	*out = m_next.get_bit_offset () - m_start.get_bit_offset ();
+	*out =  concrete_bit_size_t (m_next.get_concrete_bit_offset ()
+				     - m_start.get_concrete_bit_offset ());
 	return true;
       }
     return false;
   }
 
-  bool as_concrete_bit_range (bit_range *out) const
+  bool as_concrete_bit_range (concrete_bit_range_t *out) const
   {
     if (!concrete_p ())
       return false;
-    bit_size_t size = m_next.get_bit_offset () - m_start.get_bit_offset ();
-    *out = bit_range (m_start.get_bit_offset (), size);
+    concrete_bit_size_t size = m_next.get_bit_offset () - m_start.get_bit_offset ();
+    *out = concrete_bit_range_t (m_start.get_bit_offset (), size);
     return true;
   }
-  bool as_concrete_byte_range (byte_range *out) const
+  bool as_concrete_byte_range (concrete_byte_range_t *out) const
   {
-    bit_range bits (0, 0);
+    concrete_bit_range_t bits;
     if (!as_concrete_bit_range (&bits))
       return false;
-    return bits.as_byte_range (out);
+    return maybe_as_bytes (bits, out);
   }
 
   bool contains_p (const access_range &other) const;
diff --git a/gcc/analyzer/ana-state-to-diagnostic-state.h b/gcc/analyzer/ana-state-to-diagnostic-state.h
index 78cfbbdaded5..3ee3955dc38f 100644
--- a/gcc/analyzer/ana-state-to-diagnostic-state.h
+++ b/gcc/analyzer/ana-state-to-diagnostic-state.h
@@ -60,7 +60,7 @@ private:
   create_state_node (const region &reg);
 
   /* Spatially sorted concrete bindings.  */
-  typedef std::map<bit_range, const svalue *> concrete_bindings_t;
+  typedef std::map<concrete_bit_range_t, const svalue *> concrete_bindings_t;
 
   void
   create_state_nodes_for_binding_cluster (const binding_cluster &cluster,
@@ -69,10 +69,10 @@ private:
   std::unique_ptr<diagnostics::digraphs::node>
   create_state_node_for_conc_bindings (const concrete_bindings_t &conc_bindings);
 
-  // Try to get the bit_range of REG within its base region
+  // Try to get the bit range of REG within its base region
   bool
   get_bit_range_within_base_region (const region &reg,
-				    bit_range &out);
+				    concrete_bit_range_t &out);
 
   void
   populate_state_node_for_typed_region (diagnostics::digraphs::node &,
diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc
index cf9d822629dc..c4c28b0c8ad3 100644
--- a/gcc/analyzer/analyzer.cc
+++ b/gcc/analyzer/analyzer.cc
@@ -244,29 +244,31 @@ diagnostic_event_id_to_json (const diagnostics::paths::event_id_t &event_id)
     return std::make_unique<json::literal> (json::JSON_NULL);
 }
 
-/* Generate a JSON value for OFFSET.
+/* Generate a JSON value for this offset.
    This is intended for debugging the analyzer rather than serialization and
    thus is a string.  */
+#if 0
 
 std::unique_ptr<json::value>
-bit_offset_to_json (const bit_offset_t &offset)
+concrete_bit_offset::to_json () const
 {
   pretty_printer pp;
   pp_wide_int_large (&pp, offset, SIGNED);
   return std::make_unique<json::string> (pp_formatted_text (&pp));
 }
 
-/* Generate a JSON value for OFFSET.
+/* Generate a JSON value for this offset.
    This is intended for debugging the analyzer rather than serialization and
    thus is a string.  */
 
 std::unique_ptr<json::value>
-byte_offset_to_json (const byte_offset_t &offset)
+concrete_byte_offset::to_json () const
 {
   pretty_printer pp;
   pp_wide_int_large (&pp, offset, SIGNED);
   return std::make_unique<json::string> (pp_formatted_text (&pp));
 }
+#endif
 
 /* Workaround for lack of const-correctness of ssa_default_def.  */
 
diff --git a/gcc/analyzer/call-summary.cc b/gcc/analyzer/call-summary.cc
index 9220958afcaa..831e00221322 100644
--- a/gcc/analyzer/call-summary.cc
+++ b/gcc/analyzer/call-summary.cc
@@ -363,7 +363,7 @@ call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval)
       {
 	const bits_within_svalue *bits_within_summary_sval
 	  = as_a <const bits_within_svalue *> (summary_sval);
-	const bit_range &bits = bits_within_summary_sval->get_bits ();
+	const concrete_bit_range_t &bits = bits_within_summary_sval->get_bits ();
 	const svalue *summary_inner_sval
 	  = bits_within_summary_sval->get_inner_svalue ();
 	const svalue *caller_inner_sval
diff --git a/gcc/analyzer/common.h b/gcc/analyzer/common.h
index b64dd828ed2a..29bd0633f139 100644
--- a/gcc/analyzer/common.h
+++ b/gcc/analyzer/common.h
@@ -198,14 +198,20 @@ public:
   int m_stack_depth; // or -1 for globals?
 };
 
-typedef offset_int bit_offset_t;
-typedef offset_int bit_size_t;
-typedef offset_int byte_offset_t;
-typedef offset_int byte_size_t;
+} // namespace ana
+
+// FIXME: move this include elsewhere
+#include "analyzer/quantities.h"
+
+namespace ana {
 
-extern bool int_size_in_bits (const_tree type, bit_size_t *out);
+extern bool
+int_size_in_bits (const_tree type,
+		  concrete_bit_size_t *out);
 
-extern tree get_field_at_bit_offset (tree record_type, bit_offset_t bit_offset);
+extern tree
+get_field_at_bit_offset (tree record_type,
+			 concrete_bit_offset_t bit_offset);
 
 /* The location of a region expressesd as an offset relative to a
    base region.  */
@@ -214,50 +220,47 @@ class region_offset
 {
 public:
   region_offset ()
-  : m_base_region (nullptr), m_offset (0), m_sym_offset (nullptr)
+    : m_base_region (nullptr),
+      m_bit_offset ()
   {
   }
 
   static region_offset make_concrete (const region *base_region,
-				      bit_offset_t offset)
+				      concrete_bit_offset_t offset)
   {
-    return region_offset (base_region, offset, nullptr);
+    return region_offset (base_region, FIXME_bit_offset_t (offset));
   }
   static region_offset make_symbolic (const region *base_region,
-				      const svalue *sym_offset)
+				      const svalue &sym_offset)
   {
-    return region_offset (base_region, 0, sym_offset);
+    return region_offset (base_region, FIXME_bit_offset_t (&sym_offset));
   }
   static region_offset make_byte_offset (const region *base_region,
 					 const svalue *num_bytes_sval);
 
   const region *get_base_region () const { return m_base_region; }
 
-  bool concrete_p () const { return m_sym_offset == nullptr; }
-  bool symbolic_p () const { return m_sym_offset != nullptr; }
+  bool concrete_p () const { return m_bit_offset.concrete_p (); }
+  bool symbolic_p () const { return m_bit_offset.symbolic_p (); }
 
-  bit_offset_t get_bit_offset () const
+  concrete_bit_offset_t
+  get_concrete_bit_offset () const
   {
-    gcc_assert (!symbolic_p ());
-    return m_offset;
+    return m_bit_offset.get_concrete ();
   }
 
-  bool get_concrete_byte_offset (byte_offset_t *out) const
+#if 0
+  bool
+  get_concrete_byte_offset (concrete_byte_offset_t *out) const
   {
-    gcc_assert (!symbolic_p ());
-    if (m_offset % BITS_PER_UNIT == 0)
-      {
-	*out = m_offset / BITS_PER_UNIT;
-	return true;
-      }
-    return false;
+    return m_bit_offset.get_concrete (*out);
   }
 
   const svalue *get_symbolic_byte_offset () const
   {
-    gcc_assert (symbolic_p ());
-    return m_sym_offset;
+    return m_bit_offset.get_symbolic ();
   }
+#endif
 
   const svalue &calc_symbolic_bit_offset (region_model_manager *mgr) const;
   const svalue *calc_symbolic_byte_offset (region_model_manager *mgr) const;
@@ -265,22 +268,20 @@ public:
   bool operator== (const region_offset &other) const
   {
     return (m_base_region == other.m_base_region
-	    && m_offset == other.m_offset
-	    && m_sym_offset == other.m_sym_offset);
+	    && m_bit_offset == other.m_bit_offset);
   }
 
   void dump_to_pp (pretty_printer *pp, bool) const;
   void dump (bool) const;
 
 private:
-  region_offset (const region *base_region, bit_offset_t offset,
-		 const svalue *sym_offset)
-  : m_base_region (base_region), m_offset (offset), m_sym_offset (sym_offset)
+  region_offset (const region *base_region,
+		 const FIXME_bit_offset_t &bit_offset)
+  : m_base_region (base_region), m_bit_offset (bit_offset)
   {}
 
   const region *m_base_region;
-  bit_offset_t m_offset;
-  const svalue *m_sym_offset;
+  FIXME_bit_offset_t m_bit_offset;
 };
 
 extern bool operator< (const region_offset &, const region_offset &);
@@ -496,10 +497,10 @@ extern std::unique_ptr<json::value>
 diagnostic_event_id_to_json (const diagnostics::paths::event_id_t &);
 
 extern std::unique_ptr<json::value>
-bit_offset_to_json (const bit_offset_t &offset);
+concrete_bit_offset_to_json (const concrete_bit_offset_t &offset);
 
 extern std::unique_ptr<json::value>
-byte_offset_to_json (const byte_offset_t &offset);
+concrete_byte_offset_to_json (const concrete_byte_offset_t &offset);
 
 extern tristate
 compare_constants (tree lhs_const, enum tree_code op, tree rhs_const);
diff --git a/gcc/analyzer/quantities.h b/gcc/analyzer/quantities.h
new file mode 100644
index 000000000000..778f66c271d1
--- /dev/null
+++ b/gcc/analyzer/quantities.h
@@ -0,0 +1,362 @@
+/* Typesafe quantities involving bits and bytes.
+   Copyright (C) 2020-2026 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_ANALYZER_QUANTITIES_H
+#define GCC_ANALYZER_QUANTITIES_H
+
+namespace ana {
+
+/* This header declares a family of templates for describing
+   quantities:
+   - sizes of memory areas
+   - offsets within memory areas
+   - ranges within memory areas
+   in which the quantities can be in either bits or bytes,
+   and which could either be concrete or symbolic, or known at
+   compile time to be concrete, symbolic.
+
+   The intent is that the C++ type system should enforce that we
+   don't e.g. confuse bits with bytes.  */
+
+// Traits for distinguishing bits vs bytes ("Unit")
+struct bits;
+struct bytes;
+
+// Traits for distinguishing offset vs sizes ("Purpose")
+struct offset;
+struct size;
+
+#if 0
+// Traits for distinguishing concrete vs symbolic???
+struct concrete;
+struct symbolic;
+#endif
+
+/* Template for a concrete quantity, measured in either bits or bytes (Unit),
+   and measuring either an offset or a size (Purpose).  */
+
+template <typename Unit, typename Purpose>
+struct concrete_quantity_t
+{
+  concrete_quantity_t () { /* uninitialized */ }
+  concrete_quantity_t (offset_int inner) : m_inner (inner) {}
+
+  template <typename OtherPurpose>
+  explicit concrete_quantity_t (const concrete_quantity_t<Unit, OtherPurpose> &other)
+  : m_inner (other.m_inner)
+  {}
+
+  /* Comparisons.  */
+  bool
+  operator== (const concrete_quantity_t &other) const
+  {
+    return m_inner == other.m_inner;
+  }
+  bool
+  operator< (const concrete_quantity_t &other) const
+  {
+    return m_inner < other.m_inner;
+  }
+  bool
+  operator<= (const concrete_quantity_t &other) const
+  {
+    return m_inner <- other.m_inner;
+  }
+  bool
+  operator> (const concrete_quantity_t &other) const
+  {
+    return m_inner > other.m_inner;
+  }
+  bool
+  operator>= (const concrete_quantity_t &other) const
+  {
+    return m_inner > other.m_inner;
+  }
+
+  concrete_quantity_t
+  operator- (const concrete_quantity_t &other) const
+  {
+   return m_inner - other.m_inner;
+  }
+
+  offset_int m_inner;
+};
+
+/* Conversion of a concrete quantity from bytes to bits.  */
+
+template <typename Purpose>
+inline concrete_quantity_t<bits, Purpose>
+as_bits (concrete_quantity_t<bytes, Purpose> byte_val)
+{
+  return byte_val.m_inner * BITS_PER_UNIT;
+}
+
+/* Attempt to convert a concrete quantity from bits to bytes.  */
+
+template <typename Purpose>
+inline bool
+maybe_as_bytes (const concrete_quantity_t<bits, Purpose> &bit_val,
+		concrete_quantity_t<bytes, Purpose> &out)
+{
+  if (bit_val.m_inner % BITS_PER_UNIT == 0)
+    {
+      out = concrete_quantity_t<bytes, Purpose> (bit_val.m_inner / BITS_PER_UNIT);
+      return true;
+    }
+  return false;
+}
+
+/* Typedefs for concrete offsets and sizes, as bits and bytes.  */
+
+template <typename Unit>
+using concrete_offset_t = concrete_quantity_t<Unit, offset>;
+
+using concrete_bit_offset_t = concrete_offset_t<bits>;
+using concrete_byte_offset_t = concrete_offset_t<bytes>;
+
+template <typename Unit>
+using concrete_size_t = concrete_quantity_t<Unit, size>;
+
+using concrete_bit_size_t = concrete_size_t<bits>;
+using concrete_byte_size_t = concrete_size_t<bytes>;
+
+/* A concrete range, of either bits or bytes
+   (e.g. "bits [0-31]" or "bytes [0-3]").  */
+
+template <typename Unit>
+struct concrete_range_t
+{
+  concrete_range_t (concrete_quantity_t<Unit, offset> start_offset,
+		    concrete_quantity_t<Unit, size> size)
+  : m_start_offset (start_offset),
+    m_size (size)
+  {}
+
+  void dump_to_pp (pretty_printer *pp) const;
+  void dump () const;
+
+  std::unique_ptr<json::object> to_json () const;
+
+  bool empty_p () const
+  {
+    return m_size.m_inner == 0;
+  }
+
+  concrete_offset_t<Unit> get_start_offset () const
+  {
+    return m_start_offset;
+  }
+  concrete_offset_t<Unit> get_next_offset () const
+  {
+    return concrete_offset_t<Unit> (m_start_offset.m_inner + m_size.m_inner);
+  }
+  concrete_offset_t<Unit> get_last_offset () const
+  {
+    gcc_assert (!empty_p ());
+    return get_next_offset () - 1;
+  }
+
+  bool contains_p (concrete_offset_t<Unit> offset) const
+  {
+    return (offset >= get_start_offset ()
+	    && offset < get_next_offset ());
+  }
+
+  bool contains_p (const concrete_range_t &other, concrete_range_t *out) const;
+
+  bool operator== (const concrete_range_t &other) const
+  {
+    return (m_start_offset == other.m_start_offset
+	    && m_size == other.m_size);
+  }
+
+  bool intersects_p (const concrete_range_t &other) const
+  {
+    return (get_start_offset () < other.get_next_offset ()
+	    && other.get_start_offset () < get_next_offset ());
+  }
+  bool intersects_p (const concrete_range_t<Unit> &other,
+		     concrete_size_t<Unit> *out_num_overlap) const;
+  bool intersects_p (const concrete_range_t<Unit> &other,
+		     concrete_range_t<Unit> *out_this,
+		     concrete_range_t<Unit> *out_other) const;
+
+  bool exceeds_p (const concrete_range_t<Unit> &other,
+		  concrete_range_t<Unit> *out_overhanging_bit_range) const;
+
+  bool falls_short_of_p (concrete_offset_t<Unit> offset,
+			 concrete_range_t<Unit> *out_fall_short_bits) const;
+
+  static int cmp (const concrete_range_t<Unit> &br1, const concrete_range_t<Unit> &br2);
+
+  concrete_range_t<Unit> operator- (concrete_offset_t<Unit> offset) const;
+
+#if 0
+  static bool from_mask (unsigned HOST_WIDE_INT mask, concrete_range_t<Unit> *out);
+
+  bool as_byte_range (concrete_byte_range &out) const;
+#endif
+
+  bool
+  operator< (const concrete_range_t<Unit> &other) const
+  {
+    if (m_start_offset < other.m_start_offset)
+      return true;
+    if (m_start_offset > other.m_start_offset)
+      return false;
+    return (m_size < other.m_size);
+  }
+
+  hashval_t hash () const
+  {
+    inchash::hash hstate;
+    hstate.add_wide_int (m_start_offset.m_inner);
+    hstate.add_wide_int (m_size.m_inner);
+    return hstate.end ();
+  }
+
+  concrete_offset_t<Unit> m_start_offset;
+  concrete_size_t<Unit> m_size;
+};
+
+using concrete_bit_range_t = concrete_range_t<bits>;
+using concrete_byte_range_t = concrete_range_t<bytes>;
+
+inline concrete_bit_range_t
+as_bits (const concrete_byte_range_t &bytes_)
+{
+  return concrete_bit_range_t (as_bits (bytes_.m_start_offset),
+			       as_bits (bytes_.m_size));
+}
+
+inline bool
+maybe_as_bytes (const concrete_bit_range_t &bits,
+		concrete_byte_range_t &out)
+{
+  if (maybe_as_bytes (bits.m_start_offset, out.m_start_offset))
+    if (maybe_as_bytes (bits.m_size, out.m_size))
+      return true;
+  return false;
+}
+
+/* Template for a symbolic quantity, measured in either bits or bytes (Unit),
+   and measuring either an offset or a size (Purpose).  */
+
+template <typename Unit, typename Purpose>
+struct symbolic_quantity_t
+{
+  symbolic_quantity_t () : m_sval (nullptr) {}
+  symbolic_quantity_t (const svalue *sval) : m_sval (sval) {}
+
+  bool
+  operator== (const symbolic_quantity_t &other) const
+  {
+    return m_sval == other.m_sval;
+  }
+
+  const svalue *m_sval;
+};
+
+/* Typedefs for symbolic offsets and sizes, as bits and bytes.  */
+
+template <typename Unit>
+using symbolic_offset_t = symbolic_quantity_t<Unit, offset>;
+
+using symbolic_bit_offset_t = symbolic_offset_t<bits>;
+using symbolic_byte_offset_t = symbolic_offset_t<bytes>;
+
+template <typename Unit>
+using symbolic_size_t = symbolic_quantity_t<Unit, size>;
+
+using symbolic_bit_size_t = symbolic_size_t<bits>;
+using symbolic_byte_size_t = symbolic_size_t<bytes>;
+
+/* Template for a quantity that could be either concrete or symbolic,
+   measured in either bits or bytes (Unit),
+   and measuring either an offset or a size (Purpose).  */
+
+template <typename Unit, typename Purpose>
+struct FIXME_quantity_t
+{
+  FIXME_quantity_t ()
+  : m_concrete (0), m_symbolic (nullptr)
+  {
+  }
+
+  FIXME_quantity_t (concrete_quantity_t<Unit, Purpose> concrete)
+  : m_concrete (concrete), m_symbolic (nullptr)
+  {
+  }
+
+  FIXME_quantity_t (symbolic_quantity_t<Unit, Purpose> symbolic)
+  : m_concrete (0),
+    m_symbolic (symbolic)
+  {
+    // FIXME: what to do if sval is constant?
+  }
+
+  bool concrete_p () const { return m_symbolic.m_sval == nullptr; }
+  bool symbolic_p () const { return m_symbolic.m_sval != nullptr; }
+
+  concrete_quantity_t<Unit, Purpose>
+  get_concrete () const
+  {
+    gcc_assert (!symbolic_p ());
+    return m_concrete;
+  }
+
+  symbolic_quantity_t<Unit, Purpose>
+  get_symbolic () const
+  {
+    gcc_assert (symbolic_p ());
+    return m_symbolic;
+  }
+
+  bool operator== (const FIXME_quantity_t &other) const
+  {
+    return (m_concrete == other.m_concrete
+	    && m_symbolic == other.m_symbolic);
+  }
+
+  void dump_to_pp (pretty_printer *pp, bool) const;
+  void dump (bool) const;
+
+  concrete_quantity_t<Unit, Purpose> m_concrete;
+  symbolic_quantity_t<Unit, Purpose> m_symbolic;
+};
+
+/* Typedefs for quantities that could be either concrete or symbolic,
+   for offsets and sizes, as bits and bytes.  */
+
+template <typename Unit>
+using FIXME_offset_t = FIXME_quantity_t<Unit, offset>;
+
+using FIXME_bit_offset_t = FIXME_offset_t<bits>;
+using FIXME_byte_offset_t = FIXME_offset_t<bytes>;
+
+template <typename Unit>
+using FIXME_size_t = FIXME_quantity_t<Unit, size>;
+
+using FIXME_bit_size_t = FIXME_size_t<bits>;
+using FIXME_byte_size_t = FIXME_size_t<bytes>;
+
+} // namespace ana
+
+#endif /* GCC_ANALYZER_QUANTITIES_H */
diff --git a/gcc/analyzer/ranges.cc b/gcc/analyzer/ranges.cc
index 241d7bfd07df..ef603888c160 100644
--- a/gcc/analyzer/ranges.cc
+++ b/gcc/analyzer/ranges.cc
@@ -54,9 +54,9 @@ symbolic_byte_offset::symbolic_byte_offset (region_offset offset,
 {
   if (offset.concrete_p ())
     {
-      bit_offset_t num_bits = offset.get_bit_offset ();
-      gcc_assert (num_bits % BITS_PER_UNIT == 0);
-      byte_offset_t num_bytes = num_bits / BITS_PER_UNIT;
+      concrete_bit_offset_t num_bits = offset.get_concrete_bit_offset ();
+      gcc_assert (num_bits.m_inner % BITS_PER_UNIT == 0);
+      concrete_byte_offset_t num_bytes = num_bits.m_inner / BITS_PER_UNIT;
       m_num_bytes_sval = mgr.get_or_create_int_cst (size_type_node, num_bytes);
     }
   else
diff --git a/gcc/analyzer/record-layout.cc b/gcc/analyzer/record-layout.cc
index 29295b0098f6..d5bfbf5212ff 100644
--- a/gcc/analyzer/record-layout.cc
+++ b/gcc/analyzer/record-layout.cc
@@ -39,24 +39,24 @@ record_layout::record_layout (const_tree record_type)
     {
       if (TREE_CODE (iter) == FIELD_DECL)
 	{
-	  int iter_field_offset = int_bit_position (iter);
-	  bit_size_t size_in_bits;
+	  concrete_bit_offset_t iter_field_offset (int_bit_position (iter));
+	  concrete_bit_size_t size_in_bits;
 	  if (!int_size_in_bits (TREE_TYPE (iter), &size_in_bits))
-	    size_in_bits = 0;
+	    size_in_bits = concrete_bit_size_t (0);
 
 	  maybe_pad_to (iter_field_offset);
 
 	  /* Add field.  */
-	  m_items.safe_push (item (bit_range (iter_field_offset,
-					      size_in_bits),
+	  m_items.safe_push (item (concrete_bit_range_t (iter_field_offset,
+							 size_in_bits),
 				   iter, false));
 	}
     }
 
   /* Add any trailing padding.  */
-  bit_size_t size_in_bits;
+  concrete_bit_size_t size_in_bits;
   if (int_size_in_bits (record_type, &size_in_bits))
-    maybe_pad_to (size_in_bits);
+    maybe_pad_to (concrete_bit_offset_t (size_in_bits.m_inner));
 }
 
 void
@@ -79,7 +79,7 @@ record_layout::dump () const
 }
 
 const record_layout::item *
-record_layout::get_item_at (bit_offset_t offset) const
+record_layout::get_item_at (concrete_bit_offset_t offset) const
 {
   unsigned i;
   item *it;
@@ -92,19 +92,19 @@ record_layout::get_item_at (bit_offset_t offset) const
 /* Subroutine of ctor.  Add padding item to NEXT_OFFSET if necessary.  */
 
 void
-record_layout::maybe_pad_to (bit_offset_t next_offset)
+record_layout::maybe_pad_to (concrete_bit_offset_t next_offset)
 {
   if (m_items.length () > 0)
     {
       const item &last_item = m_items[m_items.length () - 1];
-      bit_offset_t offset_after_last_item
+      concrete_bit_offset_t offset_after_last_item
 	= last_item.get_next_bit_offset ();
       if (next_offset > offset_after_last_item)
 	{
-	  bit_size_t padding_size
-	    = next_offset - offset_after_last_item;
-	  m_items.safe_push (item (bit_range (offset_after_last_item,
-					      padding_size),
+	  concrete_bit_size_t padding_size
+	    = concrete_bit_size_t (next_offset - offset_after_last_item);
+	  m_items.safe_push (item (concrete_bit_range_t (offset_after_last_item,
+							 padding_size),
 				   last_item.m_field, true));
 	}
     }
diff --git a/gcc/analyzer/record-layout.h b/gcc/analyzer/record-layout.h
index 1ec63c7146c7..cb0a61c12de3 100644
--- a/gcc/analyzer/record-layout.h
+++ b/gcc/analyzer/record-layout.h
@@ -35,7 +35,7 @@ public:
   struct item
   {
   public:
-    item (const bit_range &br,
+    item (const concrete_bit_range_t &br,
 	  const_tree field,
 	  bool is_padding)
     : m_bit_range (br),
@@ -44,16 +44,16 @@ public:
     {
     }
 
-    bit_offset_t get_start_bit_offset () const
+    concrete_bit_offset_t get_start_bit_offset () const
     {
-      return m_bit_range.get_start_bit_offset ();
+      return m_bit_range.get_start_offset ();
     }
-    bit_offset_t get_next_bit_offset () const
+    concrete_bit_offset_t get_next_bit_offset () const
     {
-      return m_bit_range.get_next_bit_offset ();
+      return m_bit_range.get_next_offset ();
     }
 
-    bool contains_p (bit_offset_t offset) const
+    bool contains_p (concrete_bit_offset_t offset) const
     {
       return m_bit_range.contains_p (offset);
     }
@@ -68,7 +68,7 @@ public:
       m_bit_range.dump_to_pp (pp);
     }
 
-    bit_range m_bit_range;
+    concrete_bit_range_t m_bit_range;
     const_tree m_field;
     bool m_is_padding;
   };
@@ -78,13 +78,14 @@ public:
   void dump_to_pp (pretty_printer *pp) const;
   DEBUG_FUNCTION void dump () const;
 
-  const record_layout::item *get_item_at (bit_offset_t offset) const;
+  const record_layout::item *
+  get_item_at (concrete_bit_offset_t offset) const;
 
   auto begin () const { return m_items.begin (); }
   auto end () const { return m_items.end (); }
 
 private:
-  void maybe_pad_to (bit_offset_t next_offset);
+  void maybe_pad_to (concrete_bit_offset_t next_offset);
 
   auto_vec<item> m_items;
 };
diff --git a/gcc/analyzer/region-model-infoleak.cc b/gcc/analyzer/region-model-infoleak.cc
index 71cb11a039c0..d5eb9a11011d 100644
--- a/gcc/analyzer/region-model-infoleak.cc
+++ b/gcc/analyzer/region-model-infoleak.cc
@@ -260,8 +260,8 @@ private:
   }
 
   void complain_about_uninit_range (location_t loc,
-				    bit_offset_t start_bit,
-				    bit_offset_t next_bit,
+				    concrete_bit_offset_t start_bit,
+				    concrete_bit_offset_t next_bit,
 				    const record_layout *layout) const
   {
     if (layout)
@@ -271,14 +271,14 @@ private:
 	    if (const record_layout::item *item
 		  = layout->get_item_at (start_bit))
 	      {
-		gcc_assert (start_bit >= item->get_start_bit_offset ());
-		gcc_assert (start_bit < item->get_next_bit_offset ());
-		if (item->get_start_bit_offset () == start_bit
-		    && item->get_next_bit_offset () <= next_bit)
+		gcc_assert (start_bit >= item->get_start_offset ());
+		gcc_assert (start_bit < item->get_next_offset ());
+		if (item->get_start_offset () == start_bit
+		    && item->get_next_offset () <= next_bit)
 		  complain_about_fully_uninit_item (*item);
 		else
 		  complain_about_partially_uninit_item (*item);
-		start_bit = item->get_next_bit_offset ();
+		start_bit = item->get_next_offset ();
 		continue;
 	      }
 	    else
@@ -289,11 +289,13 @@ private:
     if (start_bit >= next_bit)
       return;
 
-    if (start_bit % 8 == 0 && next_bit % 8 == 0)
+    concrete_byte_offset_t start_byte;
+    concrete_byte_offset_t next_byte;
+    if (maybe_as_bytes (start_bit, start_byte)
+	&& maybe_as_bytes (next_bit, next_byte))
       {
 	/* Express in bytes.  */
-	byte_offset_t start_byte = start_bit / 8;
-	byte_offset_t last_byte = (next_bit / 8) - 1;
+	concrete_byte_offset_t last_byte = next_byte - 1;
 	if (last_byte == start_byte)
 	  inform (loc,
 		  "byte %wu is uninitialized",
@@ -324,13 +326,13 @@ private:
   complain_about_fully_uninit_item (const record_layout::item &item)
   {
     const_tree field = item.m_field;
-    bit_size_t num_bits = item.m_bit_range.m_size_in_bits;
+    concrete_bit_size_t num_bits = item.m_bit_range.m_size_in_bits;
     if (item.m_is_padding)
       {
-	if (num_bits % 8 == 0)
+	concrete_byte_size_t num_bytes;
+	if (maybe_as_bytes (num_bits, num_bytes)
 	  {
 	    /* Express in bytes.  */
-	    byte_size_t num_bytes = num_bits / BITS_PER_UNIT;
 	    if (num_bytes == 1)
 	      inform (DECL_SOURCE_LOCATION (field),
 		      "padding after field %qD is uninitialized (1 byte)",
@@ -355,10 +357,10 @@ private:
       }
     else
       {
-	if (num_bits % 8 == 0)
+	concrete_byte_size_t num_bytes;
+	if (maybe_as_bytes (num_bits, num_bytes)
 	  {
 	    /* Express in bytes.  */
-	    byte_size_t num_bytes = num_bits / BITS_PER_UNIT;
 	    if (num_bytes == 1)
 	      inform (DECL_SOURCE_LOCATION (field),
 		      "field %qD is uninitialized (1 byte)", field);
diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc
index 5d581bc14f9b..13d376efc13c 100644
--- a/gcc/analyzer/region-model-manager.cc
+++ b/gcc/analyzer/region-model-manager.cc
@@ -1182,13 +1182,13 @@ region_model_manager::get_or_create_repeated_svalue (tree type,
    Return false otherwise.  */
 
 static bool
-get_bit_range_for_field (tree field, bit_range *out)
+get_bit_range_for_field (tree field, concrete_bit_range_t *out)
 {
-  bit_size_t bit_size;
+  concrete_bit_size_t bit_size;
   if (!int_size_in_bits (TREE_TYPE (field), &bit_size))
     return false;
-  int field_bit_offset = int_bit_position (field);
-  *out = bit_range (field_bit_offset, bit_size);
+  concrete_bit_offset_t field_bit_offset = int_bit_position (field);
+  *out = concrete_bit_range_t (field_bit_offset, bit_size);
   return true;
 }
 
@@ -1199,10 +1199,10 @@ get_bit_range_for_field (tree field, bit_range *out)
 static bool
 get_byte_range_for_field (tree field, byte_range *out)
 {
-  bit_range field_bits (0, 0);
+  concrete_bit_range_t field_bits;
   if (!get_bit_range_for_field (field, &field_bits))
     return false;
-  return field_bits.as_byte_range (out);
+  return maybe_as_bytes (field_bits, out);
 }
 
 /* Attempt to determine if there is a specific field within RECORD_TYPE
@@ -1219,18 +1219,18 @@ static tree
 get_field_at_byte_range (tree record_type, const byte_range &bytes,
 			 byte_range *out_range_within_field)
 {
-  bit_offset_t bit_offset = bytes.m_start_byte_offset * BITS_PER_UNIT;
+  concrete_bit_offset_t bit_offset = as_bits (bytes.m_start_offset);
 
   tree field = get_field_at_bit_offset (record_type, bit_offset);
   if (!field)
     return NULL_TREE;
 
-  byte_range field_bytes (0,0);
+  concrete_byte_range_t field_bytes;
   if (!get_byte_range_for_field (field, &field_bytes))
     return NULL_TREE;
 
   /* Is BYTES fully within field_bytes?  */
-  byte_range bytes_within_field (0,0);
+  concrete_byte_range_t bytes_within_field;
   if (!field_bytes.contains_p (bytes, &bytes_within_field))
     return NULL_TREE;
 
diff --git a/gcc/analyzer/region-model-manager.h b/gcc/analyzer/region-model-manager.h
index 9872b3be2b98..c0ca43c37208 100644
--- a/gcc/analyzer/region-model-manager.h
+++ b/gcc/analyzer/region-model-manager.h
@@ -69,7 +69,7 @@ public:
 					       const svalue *outer_size,
 					       const svalue *inner_svalue);
   const svalue *get_or_create_bits_within (tree type,
-					   const bit_range &bits,
+					   const concrete_bit_range_t &bits,
 					   const svalue *inner_svalue);
   const svalue *get_or_create_unmergeable (const svalue *arg);
   const svalue *get_or_create_widening_svalue (tree type,
@@ -142,7 +142,7 @@ public:
   const region *get_symbolic_region (const svalue *sval);
   const string_region *get_region_for_string (tree string_cst);
   const region *get_bit_range (const region *parent, tree type,
-			       const bit_range &bits);
+			       const concrete_bit_range_t &bits);
   const var_arg_region *get_var_arg_region (const frame_region *parent,
 					    unsigned idx);
 
@@ -195,7 +195,7 @@ private:
 					    const svalue *outer_size,
 					    const svalue *inner_svalue);
   const svalue *maybe_fold_bits_within_svalue (tree type,
-					       const bit_range &bits,
+					       const concrete_bit_range_t &bits,
 					       const svalue *inner_svalue);
   const svalue *maybe_undo_optimize_bit_field_compare (tree type,
 						       const compound_svalue *compound_sval,
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index fd947da65e84..6e9bd95189d6 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -402,7 +402,7 @@ class region_model
 
   const svalue *get_rvalue_for_bits (tree type,
 				     const region *reg,
-				     const bit_range &bits,
+				     const concrete_bit_range_t &bits,
 				     region_model_context *ctxt) const;
 
   void set_value (const region *lhs_reg, const svalue *rhs_sval,
@@ -517,7 +517,7 @@ class region_model
   const svalue *get_store_value (const region *reg,
 				 region_model_context *ctxt) const;
   const svalue *get_store_bytes (const region *base_reg,
-				 const byte_range &bytes,
+				 const concrete_byte_range_t &bytes,
 				 region_model_context *ctxt) const;
   const svalue *scan_for_null_terminator (const region *reg,
 					  tree expr,
diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc
index b03c79ffa72c..602f90f7df7e 100644
--- a/gcc/analyzer/region.cc
+++ b/gcc/analyzer/region.cc
@@ -51,7 +51,8 @@ region_offset::make_byte_offset (const region *base_region,
   if (tree num_bytes_cst = num_bytes_sval->maybe_get_constant ())
     {
       gcc_assert (TREE_CODE (num_bytes_cst) == INTEGER_CST);
-      bit_offset_t num_bits = wi::to_offset (num_bytes_cst) * BITS_PER_UNIT;
+      concrete_bit_offset_t num_bits
+	(wi::to_offset (num_bytes_cst) * BITS_PER_UNIT);
       return make_concrete (base_region, num_bits);
     }
   else
@@ -656,7 +657,7 @@ region::get_next_offset (region_model_manager *mgr) const
 				start_byte_offset_sval,
 				byte_size_sval);
   return region_offset::make_symbolic (start.get_base_region (),
-				       sum_sval);
+				       *sum_sval);
 }
 
 /* Base class implementation of region::get_byte_size vfunc.
diff --git a/gcc/analyzer/region.h b/gcc/analyzer/region.h
index 5c1d980017a7..9ae7106c1648 100644
--- a/gcc/analyzer/region.h
+++ b/gcc/analyzer/region.h
@@ -200,14 +200,14 @@ public:
      Otherwise return false.
      This is the accessed size, not necessarily the size that's valid to
      access.  */
-  virtual bool get_byte_size (byte_size_t *out) const;
+  virtual bool get_byte_size (concrete_byte_size_t *out) const;
 
   /* Attempt to get the size of this region as a concrete number of bits.
      If successful, return true and write the size to *OUT.
      Otherwise return false.
      This is the accessed size, not necessarily the size that's valid to
      access.  */
-  virtual bool get_bit_size (bit_size_t *out) const;
+  virtual bool get_bit_size (concrete_bit_size_t *out) const;
 
   /* Get a symbolic value describing the size of this region in bytes
      (which could be "unknown").
@@ -224,7 +224,7 @@ public:
   /* Attempt to get the offset in bits of this region relative to its parent.
      If successful, return true and write to *OUT.
      Otherwise return false.  */
-  virtual bool get_relative_concrete_offset (bit_offset_t *out) const;
+  virtual bool get_relative_concrete_offset (concrete_bit_offset_t *out) const;
 
   /* Get the offset in bytes of this region relative to its parent as a svalue.
      Might return an unknown_svalue.  */
@@ -235,12 +235,12 @@ public:
      concrete range of bytes relative to its parent.
      If successful, return true and write to *OUT.
      Otherwise return false.  */
-  bool get_relative_concrete_byte_range (byte_range *out) const;
+  bool get_relative_concrete_byte_range (concrete_byte_range_t *out) const;
 
   void
   get_subregions_for_binding (region_model_manager *mgr,
-			      bit_offset_t start_bit_offset,
-			      bit_size_t size_in_bits,
+			      concrete_bit_offset_t start_bit_offset,
+			      concrete_bit_size_t size_in_bits,
 			      tree type,
 			      auto_vec <const region *> *out) const;
 
@@ -847,7 +847,7 @@ public:
 
   tree get_field () const { return m_field; }
 
-  bool get_relative_concrete_offset (bit_offset_t *out) const final override;
+  bool get_relative_concrete_offset (concrete_bit_offset_t *out) const final override;
   const svalue *get_relative_symbolic_offset (region_model_manager *mgr)
     const final override;
 
@@ -940,7 +940,7 @@ public:
   const svalue *get_index () const { return m_index; }
 
   virtual bool
-  get_relative_concrete_offset (bit_offset_t *out) const final override;
+  get_relative_concrete_offset (concrete_bit_offset_t *out) const final override;
   const svalue *get_relative_symbolic_offset (region_model_manager *mgr)
     const final override;
 
@@ -1034,7 +1034,7 @@ public:
   const svalue *get_byte_offset () const { return m_byte_offset; }
   const svalue *get_bit_offset (region_model_manager *mgr) const;
 
-  bool get_relative_concrete_offset (bit_offset_t *out) const final override;
+  bool get_relative_concrete_offset (concrete_bit_offset_t *out) const final override;
   const svalue *get_relative_symbolic_offset (region_model_manager *mgr)
     const final override;
 
@@ -1128,8 +1128,8 @@ public:
 			    const text_art::dump_widget_info &dwi)
     const final override;
 
-  bool get_byte_size (byte_size_t *out) const final override;
-  bool get_bit_size (bit_size_t *out) const final override;
+  bool get_byte_size (concrete_byte_size_t *out) const final override;
+  bool get_bit_size (concrete_bit_size_t *out) const final override;
 
   const svalue *
   get_byte_size_sval (region_model_manager *) const final override
@@ -1217,7 +1217,7 @@ public:
   void
   print_dump_widget_label (pretty_printer *pp) const final override;
 
-  bool get_relative_concrete_offset (bit_offset_t *out) const final override;
+  bool get_relative_concrete_offset (concrete_bit_offset_t *out) const final override;
 };
 
 } // namespace ana
@@ -1318,7 +1318,7 @@ public:
   /* A support class for uniquifying instances of bit_range_region.  */
   struct key_t
   {
-    key_t (const region *parent, tree type, const bit_range &bits)
+    key_t (const region *parent, tree type, const concrete_bit_range_t &bits)
     : m_parent (parent), m_type (type), m_bits (bits)
     {
       gcc_assert (parent);
@@ -1329,8 +1329,8 @@ public:
       inchash::hash hstate;
       hstate.add_ptr (m_parent);
       hstate.add_ptr (m_type);
-      hstate.add_wide_int (m_bits.m_start_bit_offset);
-      hstate.add_wide_int (m_bits.m_size_in_bits);
+      hstate.add_wide_int (m_bits.m_start_offset.m_inner);
+      hstate.add_wide_int (m_bits.m_size.m_inner);
       return hstate.end ();
     }
 
@@ -1351,11 +1351,11 @@ public:
 
     const region *m_parent;
     tree m_type;
-    bit_range m_bits;
+    concrete_bit_range_t m_bits;
   };
 
   bit_range_region (symbol::id_t id, const region *parent, tree type,
-		    const bit_range &bits)
+		    const concrete_bit_range_t &bits)
   : region (complexity (parent), id, parent, type),
     m_bits (bits)
   {}
@@ -1368,18 +1368,18 @@ public:
   void dump_to_pp (pretty_printer *pp, bool simple) const final override;
   void print_dump_widget_label (pretty_printer *pp) const final override;
 
-  const bit_range &get_bits () const { return m_bits; }
+  const concrete_bit_range_t &get_bits () const { return m_bits; }
 
-  bool get_byte_size (byte_size_t *out) const final override;
-  bool get_bit_size (bit_size_t *out) const final override;
+  bool get_byte_size (concrete_byte_size_t *out) const final override;
+  bool get_bit_size (concrete_bit_size_t *out) const final override;
   const svalue *get_byte_size_sval (region_model_manager *mgr) const final override;
   const svalue *get_bit_size_sval (region_model_manager *mgr) const final override;
-  bool get_relative_concrete_offset (bit_offset_t *out) const final override;
+  bool get_relative_concrete_offset (concrete_bit_offset_t *out) const final override;
   const svalue *get_relative_symbolic_offset (region_model_manager *mgr)
     const final override;
 
 private:
-  bit_range m_bits;
+  concrete_bit_range_t m_bits;
 };
 
 } // namespace ana
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index d198aec9d2b8..ef410c2a6ccc 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -101,12 +101,12 @@ binding_key::make (store_manager *mgr, const region *r)
     return mgr->get_symbolic_binding (r);
   else
     {
-      bit_size_t bit_size;
+      concrete_bit_size_t bit_size;
       if (r->get_bit_size (&bit_size))
 	{
 	  /* Must be non-empty.  */
-	  gcc_assert (bit_size > 0);
-	  return mgr->get_concrete_binding (offset.get_bit_offset (),
+	  gcc_assert (bit_size.m_inner > 0);
+	  return mgr->get_concrete_binding (offset.get_concrete_bit_offset (),
 					    bit_size);
 	}
       else
@@ -177,6 +177,9 @@ binding_key::cmp (const binding_key *k1, const binding_key *k2)
     }
 }
 
+// FIXME: move all this to a quantities.cc
+
+#if 0
 /* struct bit_range.  */
 
 void
@@ -195,7 +198,9 @@ bit_range::dump_to_pp (pretty_printer *pp) const
       pp_wide_int (pp, get_next_bit_offset (), SIGNED);
     }
 }
+#endif
 
+#if 0
 /* Dump this object to stderr.  */
 
 DEBUG_FUNCTION void
@@ -205,7 +210,9 @@ bit_range::dump () const
   dump_to_pp (&pp);
   pp_newline (&pp);
 }
+#endif
 
+#if 0
 /* Generate a JSON value for this bit_range.
    This is intended for debugging the analyzer rather
    than serialization.  */
@@ -526,6 +533,7 @@ byte_range::cmp (const byte_range &br1, const byte_range &br2)
   /* ...then by size.  */
   return wi::cmpu (br1.m_size_in_bytes, br2.m_size_in_bytes);
 }
+#endif
 
 /* class concrete_binding : public binding_key.  */
 
@@ -552,9 +560,9 @@ concrete_binding::overlaps_p (const concrete_binding &other) const
    and write it to *OUT.  Otherwise return false.  */
 
 bool
-concrete_binding::get_byte_range (byte_range *out) const
+concrete_binding::get_byte_range (concrete_byte_range_t *out) const
 {
-  return m_bit_range.as_byte_range (out);
+  return maybe_as_bytes (m_bit_range, *out);
 }
 
 /* Comparator for use by vec<const concrete_binding *>::qsort.  */
@@ -565,7 +573,7 @@ concrete_binding::cmp_ptr_ptr (const void *p1, const void *p2)
   const concrete_binding *b1 = *(const concrete_binding * const *)p1;
   const concrete_binding *b2 = *(const concrete_binding * const *)p2;
 
-  return bit_range::cmp (b1->m_bit_range, b2->m_bit_range);
+  return concrete_bit_range_t::cmp (b1->m_bit_range, b2->m_bit_range);
 }
 
 /* class symbolic_binding : public binding_key.  */
@@ -631,7 +639,7 @@ concrete_binding_map::dump_to_pp (pretty_printer *pp, bool simple, bool multilin
   bool first = true;
   for (auto iter : *this)
     {
-      const bit_range &bits = iter.first;
+      const concrete_bit_range_t &bits = iter.first;
       const svalue *value = iter.second;
       if (multiline)
 	{
@@ -676,7 +684,7 @@ concrete_binding_map::add_to_tree_widget (text_art::tree_widget &parent_widget,
 {
   for (auto iter : *this)
     {
-      const bit_range &bits = iter.first;
+      const concrete_bit_range_t &bits = iter.first;
       const svalue *sval = iter.second;
 
       pretty_printer the_pp;
@@ -713,14 +721,14 @@ concrete_binding_map::validate () const
       if (next != m_map.end ())
 	{
 	  /* Verify they are in order, and do not overlap.  */
-	  const bit_range &iter_bits = iter->first;
-	  const bit_range &next_bits = next->first;
-	  gcc_assert (iter_bits.get_start_bit_offset ()
-		      < next_bits.get_start_bit_offset ());
-	  gcc_assert (iter_bits.get_last_bit_offset ()
-		      < next_bits.get_start_bit_offset ());
-	  gcc_assert (iter_bits.get_next_bit_offset ()
-		      <= next_bits.get_start_bit_offset ());
+	  const concrete_bit_range_t &iter_bits = iter->first;
+	  const concrete_bit_range_t &next_bits = next->first;
+	  gcc_assert (iter_bits.get_start_offset ()
+		      < next_bits.get_start_offset ());
+	  gcc_assert (iter_bits.get_last_offset ()
+		      < next_bits.get_start_offset ());
+	  gcc_assert (iter_bits.get_next_offset ()
+		      <= next_bits.get_start_offset ());
 	}
     }
 }
@@ -739,7 +747,7 @@ concrete_binding_map::cmp (const concrete_binding_map &map1,
   while (iter1 != map1.end ())
     {
       gcc_assert (iter2 != map2.end ());
-      if (int bit_cmp = bit_range::cmp (iter1->first, iter2->first))
+      if (int bit_cmp = concrete_bit_range_t::cmp (iter1->first, iter2->first))
 	return bit_cmp;
       if (int sval_cmp = svalue::cmp_ptr (iter1->second, iter2->second))
 	return sval_cmp;
@@ -753,7 +761,7 @@ concrete_binding_map::cmp (const concrete_binding_map &map1,
    return nullptr.  */
 
 const svalue *
-concrete_binding_map::get_any_exact_binding (const bit_range &bits) const
+concrete_binding_map::get_any_exact_binding (const concrete_bit_range_t &bits) const
 {
   auto iter = m_map.find (bits);
   if (iter == m_map.end ())
@@ -781,8 +789,8 @@ concrete_binding_map::calc_complexity () const
 void
 concrete_binding_map::
 remove_overlapping_binding (store_manager *mgr,
-			    const bit_range &bits_to_drop,
-			    const bit_range &affected_bound_bits,
+			    const concrete_bit_range_t &bits_to_drop,
+			    const concrete_bit_range_t &affected_bound_bits,
 			    const svalue &old_sval)
 {
   gcc_assert (bits_to_drop.intersects_p (affected_bound_bits));
@@ -790,14 +798,16 @@ remove_overlapping_binding (store_manager *mgr,
   /* Remove existing binding.  */
   erase (affected_bound_bits);
 
-  if (affected_bound_bits.get_start_bit_offset ()
-      < bits_to_drop.get_start_bit_offset ())
+  if (affected_bound_bits.get_start_offset ()
+      < bits_to_drop.get_start_offset ())
     {
       /* We have a truncated prefix.  */
-      bit_range prefix_bits (affected_bound_bits.get_start_bit_offset (),
-			     (bits_to_drop.get_start_bit_offset ()
-			      - affected_bound_bits.get_start_bit_offset ()));
-      bit_range rel_prefix (0, prefix_bits.m_size_in_bits);
+      concrete_bit_range_t prefix_bits
+	(affected_bound_bits.get_start_offset (),
+	 (concrete_bit_size_t (bits_to_drop.get_start_offset ()
+			       - affected_bound_bits.get_start_offset ())));
+      concrete_bit_range_t rel_prefix (concrete_bit_offset_t (0),
+				       prefix_bits.m_size);
       const svalue *prefix_sval
 	= old_sval.extract_bit_range (NULL_TREE,
 				      rel_prefix,
@@ -805,16 +815,18 @@ remove_overlapping_binding (store_manager *mgr,
       insert (prefix_bits, prefix_sval);
     }
 
-  if (affected_bound_bits.get_next_bit_offset ()
-      > bits_to_drop.get_next_bit_offset ())
+  if (affected_bound_bits.get_next_offset ()
+      > bits_to_drop.get_next_offset ())
     {
       /* We have a truncated suffix.  */
-      bit_range suffix_bits (bits_to_drop.get_next_bit_offset (),
-			     (affected_bound_bits.get_next_bit_offset ()
-			      - bits_to_drop.get_next_bit_offset ()));
-      bit_range rel_suffix (bits_to_drop.get_next_bit_offset ()
-			    - affected_bound_bits.get_start_bit_offset (),
-			    suffix_bits.m_size_in_bits);
+      concrete_bit_range_t suffix_bits
+	(bits_to_drop.get_next_offset (),
+	 concrete_bit_size_t (affected_bound_bits.get_next_offset ()
+			      - bits_to_drop.get_next_offset ()));
+      concrete_bit_range_t rel_suffix
+	(bits_to_drop.get_next_offset ()
+	 - affected_bound_bits.get_start_offset (),
+	 suffix_bits.m_size);
       const svalue *suffix_sval
 	= old_sval.extract_bit_range (NULL_TREE,
 				      rel_suffix,
@@ -826,17 +838,17 @@ remove_overlapping_binding (store_manager *mgr,
 void
 concrete_binding_map::
 remove_overlapping_bindings (store_manager *mgr,
-			     const bit_range &bits_to_drop)
+			     const concrete_bit_range_t &bits_to_drop)
 {
   auto bindings = get_overlapping_bindings (bits_to_drop);
   for (auto iter : bindings)
     remove_overlapping_binding (mgr, bits_to_drop, iter.first, iter.second);
 }
 
-std::vector<std::pair<bit_range, const svalue &>>
-concrete_binding_map::get_overlapping_bindings (const bit_range &bits)
+std::vector<std::pair<concrete_bit_range_t, const svalue &>>
+concrete_binding_map::get_overlapping_bindings (const concrete_bit_range_t &bits)
 {
-  std::vector<std::pair<bit_range, const svalue &>> result;
+  std::vector<std::pair<concrete_bit_range_t, const svalue &>> result;
   for (auto iter : m_map)
     if (iter.first.intersects_p (bits))
       {
@@ -873,7 +885,7 @@ binding_map::const_iterator::operator* ()
 {
   if (m_concrete != m_map.m_concrete.end ())
     {
-      const bit_range &bits = m_concrete->first;
+      const concrete_bit_range_t &bits = m_concrete->first;
       const svalue *sval = m_concrete->second;
       return binding_pair (m_map.m_store_mgr.get_concrete_binding (bits), sval);
     }
@@ -925,7 +937,7 @@ binding_map::iterator::operator* ()
 {
   if (m_concrete != m_map.m_concrete.end ())
     {
-      const bit_range &bits = m_concrete->first;
+      const concrete_bit_range_t &bits = m_concrete->first;
       const svalue *&sval = m_concrete->second;
       return binding_pair (m_map.m_store_mgr.get_concrete_binding (bits), sval);
     }
@@ -1033,7 +1045,7 @@ binding_map::get (const binding_key *key) const
     {
       const concrete_binding &conc_key
 	= *static_cast <const concrete_binding *> (key);
-      const bit_range &bits = conc_key.get_bit_range ();
+      const concrete_bit_range_t &bits = conc_key.get_bit_range ();
 
       concrete_bindings_t::const_iterator iter (m_concrete.find (bits));
       if (iter != m_concrete.end ())
@@ -1060,7 +1072,7 @@ binding_map::put (const binding_key *key, const svalue *sval)
     {
       const concrete_binding &conc_key
 	= *static_cast <const concrete_binding *> (key);
-      const bit_range &bits = conc_key.get_bit_range ();
+      const concrete_bit_range_t &bits = conc_key.get_bit_range ();
 
       concrete_bindings_t::iterator iter (m_concrete.find (bits));
       if (iter != m_concrete.end ())
@@ -1092,7 +1104,7 @@ binding_map::remove (const binding_key *key)
     {
       const concrete_binding &conc_key
 	= *static_cast <const concrete_binding *> (key);
-      const bit_range &bits = conc_key.get_bit_range ();
+      const concrete_bit_range_t &bits = conc_key.get_bit_range ();
       m_concrete.erase (bits);
     }
 }
@@ -1309,9 +1321,9 @@ get_subregion_within_ctor_for_ctor_pair (const region *parent_reg,
 
       if (!start_offset.concrete_p ())
 	return nullptr;
-      bit_offset_t start_bit_offset = start_offset.get_bit_offset ();
+      concrete_bit_offset_t start_bit_offset = start_offset.get_bit_offset ();
       int length = RAW_DATA_LENGTH (value);
-      bit_range bits (start_bit_offset, length * BITS_PER_UNIT);
+      concrete_bit_range_t bits (start_bit_offset, length * BITS_PER_UNIT);
 
       return mgr->get_bit_range (parent_reg, NULL_TREE, bits);
     }
@@ -1412,7 +1424,7 @@ concrete_binding_map::apply_ctor_val_to_range (const region *parent_reg,
   region_offset min_offset = min_element->get_offset (mgr);
   if (min_offset.symbolic_p ())
     return false;
-  bit_offset_t start_bit_offset = min_offset.get_bit_offset ();
+  concrete_bit_offset_t start_bit_offset = min_offset.get_bit_offset ();
   store_manager *smgr = mgr->get_store_manager ();
   if (max_element->empty_p ())
     return false;
@@ -1421,8 +1433,8 @@ concrete_binding_map::apply_ctor_val_to_range (const region *parent_reg,
     return false;
   const concrete_binding *max_element_ckey
     = max_element_key->dyn_cast_concrete_binding ();
-  bit_size_t range_size_in_bits
-    = max_element_ckey->get_next_bit_offset () - start_bit_offset;
+  concrete_bit_size_t range_size_in_bits
+    = max_element_ckey->get_next_offset () - start_bit_offset;
 
   /* Get the value.  */
   if (TREE_CODE (val) == CONSTRUCTOR)
@@ -1430,7 +1442,7 @@ concrete_binding_map::apply_ctor_val_to_range (const region *parent_reg,
   const svalue *sval = get_svalue_for_ctor_val (val, mgr);
 
   /* Bind the value to the range.  */
-  const bit_range affected_bits (start_bit_offset, range_size_in_bits);
+  const concrete_bit_range_t affected_bits (start_bit_offset, range_size_in_bits);
   insert (affected_bits, sval);
   return true;
 }
@@ -1468,7 +1480,7 @@ concrete_binding_map::apply_ctor_pair_to_child_region (const region *parent_reg,
 	  gcc_assert (sval_type);
 	  HOST_WIDE_INT sval_byte_size = int_size_in_bytes (sval_type);
 	  gcc_assert (sval_byte_size != -1);
-	  bit_size_t sval_bit_size = sval_byte_size * BITS_PER_UNIT;
+	  concrete_bit_size_t sval_bit_size = sval_byte_size * BITS_PER_UNIT;
 	  /* Get offset of child relative to base region.  */
 	  region_offset child_base_offset = child_reg->get_offset (mgr);
 	  if (child_base_offset.symbolic_p ())
@@ -1476,7 +1488,7 @@ concrete_binding_map::apply_ctor_pair_to_child_region (const region *parent_reg,
 	  /* Convert to an offset relative to the parent region.  */
 	  region_offset parent_base_offset = parent_reg->get_offset (mgr);
 	  gcc_assert (!parent_base_offset.symbolic_p ());
-	  bit_offset_t child_parent_offset
+	  concrete_bit_offset_t child_parent_offset
 	    = (child_base_offset.get_bit_offset ()
 	       - parent_base_offset.get_bit_offset ());
 	  /* Create a concrete key for the child within the parent.  */
@@ -1651,8 +1663,8 @@ binding_map::remove_overlapping_bindings (store_manager *mgr,
 	  {
 	    gcc_assert (drop_ckey->overlaps_p (*iter_ckey));
 
-	    const bit_range &drop_bits = drop_ckey->get_bit_range ();
-	    const bit_range &iter_bits = iter_ckey->get_bit_range ();
+	    const concrete_bit_range_t &drop_bits = drop_ckey->get_bit_range ();
+	    const concrete_bit_range_t &iter_bits = iter_ckey->get_bit_range ();
 	    gcc_assert (old_sval);
 	    m_concrete.remove_overlapping_binding (mgr, drop_bits, iter_bits,
 						   *old_sval);
@@ -1896,14 +1908,14 @@ binding_cluster::bind_compound_sval (store_manager *mgr,
 
   for (auto iter : *compound_sval)
     {
-      const bit_range &iter_bits = iter.first;
+      const concrete_bit_range_t &iter_bits = iter.first;
       const svalue *iter_sval = iter.second;
 
       bit_offset_t effective_start
-	= (iter_bits.get_start_bit_offset ()
+	= (iter_bits.get_start_offset ()
 	   + reg_offset.get_bit_offset ());
-      const bit_range affected_bits (effective_start,
-				     iter_bits.m_size_in_bits);
+      const concrete_bit_range_t affected_bits (effective_start,
+						iter_bits.m_size_in_bits);
       bind_key (mgr->get_concrete_binding (affected_bits), iter_sval);
     }
 }
@@ -2213,7 +2225,7 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
     = default_key->dyn_cast_concrete_binding ();
   if (!concrete_default_key)
     return nullptr;
-  const bit_range default_key_relative_to_reg
+  const concrete_bit_range_t default_key_relative_to_reg
      (0, concrete_default_key->get_size_in_bits ());
 
   default_map.insert (default_key_relative_to_reg, default_sval);
@@ -2226,14 +2238,15 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
       if (const concrete_binding *concrete_key
 	  = key->dyn_cast_concrete_binding ())
 	{
-	  const bit_range &bound_range = concrete_key->get_bit_range ();
+	  const concrete_bit_range_t &bound_range
+	    = concrete_key->get_bit_range ();
 
 	  bit_size_t reg_bit_size;
 	  if (!reg->get_bit_size (&reg_bit_size))
 	    return nullptr;
 
-	  bit_range reg_range (reg_offset.get_bit_offset (),
-			       reg_bit_size);
+	  concrete_bit_range_t reg_range (reg_offset.get_bit_offset (),
+					  reg_bit_size);
 
 	  /* Skip bindings that are outside the bit range of REG.  */
 	  if (!bound_range.intersects_p (reg_range))
@@ -2243,7 +2256,7 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
 	     handled already.  */
 	  gcc_assert (!(reg_range == bound_range));
 
-	  bit_range subrange (0, 0);
+	  concrete_bit_range_t subrange (0, 0);
 	  if (reg_range.contains_p (bound_range, &subrange))
 	    {
 	      /* We have a bound range fully within REG.
@@ -2265,8 +2278,8 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
 	  else
 	    {
 	      /* REG and the bound range partially overlap.  */
-	      bit_range reg_subrange (0, 0);
-	      bit_range bound_subrange (0, 0);
+	      concrete_bit_range_t reg_subrange (0, 0);
+	      concrete_bit_range_t bound_subrange (0, 0);
 	      reg_range.intersects_p (bound_range,
 				      &reg_subrange, &bound_subrange);
 
@@ -2295,7 +2308,7 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
   /* Merge any bindings from default_map into result_map.  */
   for (auto iter : default_map)
     {
-      const bit_range &key = iter.first;
+      const concrete_bit_range_t &key = iter.first;
       const svalue *sval = iter.second;
       result_map.insert (key, sval);
     }
@@ -2466,8 +2479,8 @@ binding_cluster::can_merge_p (const binding_cluster *cluster_a,
 	  ++next;
 	  if (next != concrete_bindings.end ())
 	    {
-	      const bit_range &iter_bits = iter->first;
-	      const bit_range &next_bits = next->first;
+	      const concrete_bit_range_t &iter_bits = iter->first;
+	      const concrete_bit_range_t &next_bits = next->first;
 	      if (iter_bits.intersects_p (next_bits))
 		return false;
 	    }
@@ -2650,7 +2663,7 @@ binding_cluster::get_representative_path_vars (const region_model *model,
 	      auto_vec <const region *> subregions;
 	      base_reg->get_subregions_for_binding
 		(model->get_manager (),
-		 ckey->get_start_bit_offset (),
+		 ckey->get_start_offset (),
 		 ckey->get_size_in_bits (),
 		 sval->get_type (),
 		 &subregions);
@@ -3991,23 +4004,23 @@ store::replay_call_summary_cluster (call_summary_replay &r,
 
 namespace selftest {
 
-/* Verify that bit_range::intersects_p works as expected.  */
+/* Verify that concrete_bit_range_t::intersects_p works as expected.  */
 
 static void
-test_bit_range_intersects_p ()
-{
-  bit_range b0 (0, 1);
-  bit_range b1 (1, 1);
-  bit_range b2 (2, 1);
-  bit_range b3 (3, 1);
-  bit_range b4 (4, 1);
-  bit_range b5 (5, 1);
-  bit_range b6 (6, 1);
-  bit_range b7 (7, 1);
-  bit_range b1_to_6 (1, 6);
-  bit_range b0_to_7 (0, 8);
-  bit_range b3_to_5 (3, 3);
-  bit_range b6_to_7 (6, 2);
+test_concrete_bit_range_intersects_p ()
+{
+  concrete_bit_range_t b0 (0, 1);
+  concrete_bit_range_t b1 (1, 1);
+  concrete_bit_range_t b2 (2, 1);
+  concrete_bit_range_t b3 (3, 1);
+  concrete_bit_range_t b4 (4, 1);
+  concrete_bit_range_t b5 (5, 1);
+  concrete_bit_range_t b6 (6, 1);
+  concrete_bit_range_t b7 (7, 1);
+  concrete_bit_range_t b1_to_6 (1, 6);
+  concrete_bit_range_t b0_to_7 (0, 8);
+  concrete_bit_range_t b3_to_5 (3, 3);
+  concrete_bit_range_t b6_to_7 (6, 2);
 
   /* self-intersection is true.  */
   ASSERT_TRUE (b0.intersects_p (b0));
@@ -4038,97 +4051,97 @@ test_bit_range_intersects_p ()
   ASSERT_FALSE (b3_to_5.intersects_p (b6_to_7));
   ASSERT_FALSE (b6_to_7.intersects_p (b3_to_5));
 
-  bit_range r1 (0,0);
-  bit_range r2 (0,0);
+  concrete_bit_range_t r1 (0,0);
+  concrete_bit_range_t r2 (0,0);
   ASSERT_TRUE (b1_to_6.intersects_p (b0_to_7, &r1, &r2));
-  ASSERT_EQ (r1.get_start_bit_offset (), 0);
+  ASSERT_EQ (r1.get_start_offset (), 0);
   ASSERT_EQ (r1.m_size_in_bits, 6);
-  ASSERT_EQ (r2.get_start_bit_offset (), 1);
+  ASSERT_EQ (r2.get_start_offset (), 1);
   ASSERT_EQ (r2.m_size_in_bits, 6);
 
   ASSERT_TRUE (b0_to_7.intersects_p (b1_to_6, &r1, &r2));
-  ASSERT_EQ (r1.get_start_bit_offset (), 1);
+  ASSERT_EQ (r1.get_start_offset (), 1);
   ASSERT_EQ (r1.m_size_in_bits, 6);
-  ASSERT_EQ (r2.get_start_bit_offset (), 0);
+  ASSERT_EQ (r2.get_start_offset (), 0);
   ASSERT_EQ (r2.m_size_in_bits, 6);
 }
 
-/* Implementation detail of ASSERT_BIT_RANGE_FROM_MASK_EQ.  */
+/* Implementation detail of ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ.  */
 
 static void
-assert_bit_range_from_mask_eq (const location &loc,
-			       unsigned HOST_WIDE_INT mask,
-			       const bit_range &expected)
+assert_concrete_bit_range_from_mask_eq (const location &loc,
+					unsigned HOST_WIDE_INT mask,
+					const concrete_bit_range_t &expected)
 {
-  bit_range actual (0, 0);
-  bool ok = bit_range::from_mask (mask, &actual);
+  concrete_bit_range_t actual (0, 0);
+  bool ok = concrete_bit_range_t::from_mask (mask, &actual);
   ASSERT_TRUE_AT (loc, ok);
   ASSERT_EQ_AT (loc, actual, expected);
 }
 
-/* Assert that bit_range::from_mask (MASK) returns true, and writes
+/* Assert that concrete_bit_range_t::from_mask (MASK) returns true, and writes
    out EXPECTED_BIT_RANGE.  */
 
-#define ASSERT_BIT_RANGE_FROM_MASK_EQ(MASK, EXPECTED_BIT_RANGE) \
+#define ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ(MASK, EXPECTED_BIT_RANGE) \
   SELFTEST_BEGIN_STMT							\
-  assert_bit_range_from_mask_eq (SELFTEST_LOCATION, MASK,		\
-				 EXPECTED_BIT_RANGE);			\
+  assert_concrete_bit_range_from_mask_eq (SELFTEST_LOCATION, MASK,		\
+					    EXPECTED_BIT_RANGE);	\
   SELFTEST_END_STMT
 
-/* Implementation detail of ASSERT_NO_BIT_RANGE_FROM_MASK.  */
+/* Implementation detail of ASSERT_NO_CONCRETE_BIT_RANGE_FROM_MASK.  */
 
 static void
-assert_no_bit_range_from_mask_eq (const location &loc,
-				  unsigned HOST_WIDE_INT mask)
+assert_no_concrete_bit_range_from_mask_eq (const location &loc,
+					   unsigned HOST_WIDE_INT mask)
 {
-  bit_range actual (0, 0);
-  bool ok = bit_range::from_mask (mask, &actual);
+  concrete_bit_range_t actual (0, 0);
+  bool ok = concrete_bit_range_t::from_mask (mask, &actual);
   ASSERT_FALSE_AT (loc, ok);
 }
 
-/* Assert that bit_range::from_mask (MASK) returns false.  */
+/* Assert that concrete_bit_range_t::from_mask (MASK) returns false.  */
 
-#define ASSERT_NO_BIT_RANGE_FROM_MASK(MASK) \
+#define ASSERT_NO_CONCRETE_BIT_RANGE_FROM_MASK(MASK) \
   SELFTEST_BEGIN_STMT							\
-  assert_no_bit_range_from_mask_eq (SELFTEST_LOCATION, MASK);		\
+  assert_no_concrete_bit_range_from_mask_eq (SELFTEST_LOCATION, MASK);		\
   SELFTEST_END_STMT
 
-/* Verify that bit_range::from_mask works as expected.  */
+/* Verify that concrete_bit_range_t::from_mask works as expected.  */
 
 static void
-test_bit_range_from_mask ()
+test_concrete_bit_range_from_mask ()
 {
   /* Should fail on zero.  */
-  ASSERT_NO_BIT_RANGE_FROM_MASK (0);
+  ASSERT_NO_CONCRETE_BIT_RANGE_FROM_MASK (0);
 
   /* Verify 1-bit masks.  */
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (1, bit_range (0, 1));
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (2, bit_range (1, 1));
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (4, bit_range (2, 1));
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (8, bit_range (3, 1));
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (16, bit_range (4, 1));
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (32, bit_range (5, 1));
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (64, bit_range (6, 1));
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (128, bit_range (7, 1));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (1, concrete_bit_range_t (0, 1));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (2, concrete_bit_range_t (1, 1));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (4, concrete_bit_range_t (2, 1));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (8, concrete_bit_range_t (3, 1));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (16, concrete_bit_range_t (4, 1));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (32, concrete_bit_range_t (5, 1));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (64, concrete_bit_range_t (6, 1));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (128, concrete_bit_range_t (7, 1));
 
   /* Verify N-bit masks starting at bit 0.  */
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (3, bit_range (0, 2));
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (7, bit_range (0, 3));
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (15, bit_range (0, 4));
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (31, bit_range (0, 5));
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (63, bit_range (0, 6));
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (127, bit_range (0, 7));
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (255, bit_range (0, 8));
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (0xffff, bit_range (0, 16));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (3, concrete_bit_range_t (0, 2));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (7, concrete_bit_range_t (0, 3));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (15, concrete_bit_range_t (0, 4));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (31, concrete_bit_range_t (0, 5));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (63, concrete_bit_range_t (0, 6));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (127, concrete_bit_range_t (0, 7));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (255, concrete_bit_range_t (0, 8));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (0xffff, concrete_bit_range_t (0, 16));
 
   /* Various other tests. */
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (0x30, bit_range (4, 2));
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (0x700, bit_range (8, 3));
-  ASSERT_BIT_RANGE_FROM_MASK_EQ (0x600, bit_range (9, 2));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (0x30, concrete_bit_range_t (4, 2));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (0x700, concrete_bit_range_t (8, 3));
+  ASSERT_CONCRETE_BIT_RANGE_FROM_MASK_EQ (0x600, concrete_bit_range_t (9, 2));
 
   /* Multiple ranges of set bits should fail.  */
-  ASSERT_NO_BIT_RANGE_FROM_MASK (0x101);
-  ASSERT_NO_BIT_RANGE_FROM_MASK (0xf0f0f0f0);
+  ASSERT_NO_CONCRETE_BIT_RANGE_FROM_MASK (0x101);
+  ASSERT_NO_CONCRETE_BIT_RANGE_FROM_MASK (0xf0f0f0f0);
 }
 
 /* Implementation detail of ASSERT_OVERLAP.  */
@@ -4237,8 +4250,10 @@ test_binding_map_ops ()
 void
 analyzer_store_cc_tests ()
 {
-  test_bit_range_intersects_p ();
-  test_bit_range_from_mask ();
+  // FIXME: as a followup, move these to a new quantities.cc:
+  test_concrete_bit_range_intersects_p ();
+  test_concrete_bit_range_from_mask ();
+
   test_binding_key_overlap ();
   test_binding_map_ops ();
 }
diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h
index 021a438222fd..0e197890248b 100644
--- a/gcc/analyzer/store.h
+++ b/gcc/analyzer/store.h
@@ -23,6 +23,10 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "text-art/tree-widget.h"
 #include "analyzer/complexity.h"
+#if 0
+#include "analyzer/concrete-bit-range.h"
+#include "analyzer/concrete-byte-range.h"
+#endif
 
 /* Implementation of the region-based ternary model described in:
      "A Memory Model for Static Analysis of C Programs"
@@ -199,7 +203,6 @@ private:
   hash_set<const svalue *> m_mutable_at_unknown_call_svals;
 };
 
-class byte_range;
 class concrete_binding;
 class symbolic_binding;
 
@@ -228,167 +231,6 @@ public:
   { return nullptr; }
 };
 
-/* A concrete range of bits.  */
-
-struct bit_range
-{
-  bit_range (bit_offset_t start_bit_offset, bit_size_t size_in_bits)
-  : m_start_bit_offset (start_bit_offset),
-    m_size_in_bits (size_in_bits)
-  {}
-
-  void dump_to_pp (pretty_printer *pp) const;
-  void dump () const;
-
-  std::unique_ptr<json::object> to_json () const;
-
-  bool empty_p () const
-  {
-    return m_size_in_bits == 0;
-  }
-
-  bit_offset_t get_start_bit_offset () const
-  {
-    return m_start_bit_offset;
-  }
-  bit_offset_t get_next_bit_offset () const
-  {
-    return m_start_bit_offset + m_size_in_bits;
-  }
-  bit_offset_t get_last_bit_offset () const
-  {
-    gcc_assert (!empty_p ());
-    return get_next_bit_offset () - 1;
-  }
-
-  bool contains_p (bit_offset_t offset) const
-  {
-    return (offset >= get_start_bit_offset ()
-	    && offset < get_next_bit_offset ());
-  }
-
-  bool contains_p (const bit_range &other, bit_range *out) const;
-
-  bool operator== (const bit_range &other) const
-  {
-    return (m_start_bit_offset == other.m_start_bit_offset
-	    && m_size_in_bits == other.m_size_in_bits);
-  }
-
-  bool intersects_p (const bit_range &other) const
-  {
-    return (get_start_bit_offset () < other.get_next_bit_offset ()
-	    && other.get_start_bit_offset () < get_next_bit_offset ());
-  }
-  bool intersects_p (const bit_range &other,
-		     bit_size_t *out_num_overlap_bits) const;
-  bool intersects_p (const bit_range &other,
-		     bit_range *out_this,
-		     bit_range *out_other) const;
-
-  bool exceeds_p (const bit_range &other,
-		  bit_range *out_overhanging_bit_range) const;
-
-  bool falls_short_of_p (bit_offset_t offset,
-			 bit_range *out_fall_short_bits) const;
-
-  static int cmp (const bit_range &br1, const bit_range &br2);
-
-  bit_range operator- (bit_offset_t offset) const;
-
-  static bool from_mask (unsigned HOST_WIDE_INT mask, bit_range *out);
-
-  bool as_byte_range (byte_range *out) const;
-
-  bool
-  operator< (const bit_range &other) const
-  {
-    if (m_start_bit_offset < other.m_start_bit_offset)
-      return true;
-    if (m_start_bit_offset > other.m_start_bit_offset)
-      return false;
-    return (m_size_in_bits < other.m_size_in_bits);
-  }
-
-  hashval_t hash () const
-  {
-    inchash::hash hstate;
-    hstate.add_wide_int (m_start_bit_offset);
-    hstate.add_wide_int (m_size_in_bits);
-    return hstate.end ();
-  }
-
-  bit_offset_t m_start_bit_offset;
-  bit_size_t m_size_in_bits;
-};
-
-/* A concrete range of bytes.  */
-
-struct byte_range
-{
-  byte_range (byte_offset_t start_byte_offset, byte_size_t size_in_bytes)
-  : m_start_byte_offset (start_byte_offset),
-    m_size_in_bytes (size_in_bytes)
-  {}
-
-  void dump_to_pp (pretty_printer *pp) const;
-  void dump () const;
-
-  std::unique_ptr<json::object> to_json () const;
-
-  bool empty_p () const
-  {
-    return m_size_in_bytes == 0;
-  }
-
-  bool contains_p (byte_offset_t offset) const
-  {
-    return (offset >= get_start_byte_offset ()
-	    && offset < get_next_byte_offset ());
-  }
-  bool contains_p (const byte_range &other, byte_range *out) const;
-
-  bool operator== (const byte_range &other) const
-  {
-    return (m_start_byte_offset == other.m_start_byte_offset
-	    && m_size_in_bytes == other.m_size_in_bytes);
-  }
-
-  byte_offset_t get_start_byte_offset () const
-  {
-    return m_start_byte_offset;
-  }
-  byte_offset_t get_next_byte_offset () const
-  {
-    return m_start_byte_offset + m_size_in_bytes;
-  }
-  byte_offset_t get_last_byte_offset () const
-  {
-    gcc_assert (!empty_p ());
-    return m_start_byte_offset + m_size_in_bytes - 1;
-  }
-
-  bit_range as_bit_range () const
-  {
-    return bit_range (m_start_byte_offset * BITS_PER_UNIT,
-		      m_size_in_bytes * BITS_PER_UNIT);
-  }
-
-  bit_offset_t get_start_bit_offset () const
-  {
-    return m_start_byte_offset * BITS_PER_UNIT;
-  }
-  bit_offset_t get_next_bit_offset () const
-  {
-    return get_next_byte_offset () * BITS_PER_UNIT;
-  }
-
-  static int cmp (const byte_range &br1, const byte_range &br2);
-
-  byte_offset_t m_start_byte_offset;
-  byte_size_t m_size_in_bytes;
-};
-
 /* Concrete subclass of binding_key, for describing a non-empty
    concrete range of bits within the binding_map (e.g. "bits 8-15").  */
 
@@ -398,10 +240,10 @@ public:
   /* This class is its own key for the purposes of consolidation.  */
   typedef concrete_binding key_t;
 
-  concrete_binding (bit_offset_t start_bit_offset, bit_size_t size_in_bits)
-  : m_bit_range (start_bit_offset, size_in_bits)
+  concrete_binding (const concrete_range_t<bits> &bit_range)
+  : m_bit_range (bit_range)
   {
-    gcc_assert (m_bit_range.m_size_in_bits > 0);
+    gcc_assert (m_bit_range.m_size.m_inner > 0);
   }
   bool concrete_p () const final override { return true; }
 
@@ -413,37 +255,49 @@ public:
 
   void dump_to_pp (pretty_printer *pp, bool simple) const final override;
 
-  const concrete_binding *dyn_cast_concrete_binding () const final override
-  { return this; }
+  const concrete_binding *
+  dyn_cast_concrete_binding () const final override
+  {
+    return this;
+  }
 
-  const bit_range &get_bit_range () const { return m_bit_range; }
-  bool get_byte_range (byte_range *out) const;
+  const concrete_bit_range_t &
+  get_concrete_bit_range () const
+  {
+    return m_bit_range;
+  }
+
+  bool
+  get_byte_range (concrete_byte_range_t *out) const;
 
-  bit_offset_t get_start_bit_offset () const
+  concrete_bit_offset_t
+  get_start_bit_offset () const
   {
-    return m_bit_range.m_start_bit_offset;
+    return m_bit_range.m_start_offset;
   }
-  bit_size_t get_size_in_bits () const
+  concrete_bit_size_t
+  get_size_in_bits () const
   {
-    return m_bit_range.m_size_in_bits;
+    return m_bit_range.m_size;
   }
   /* Return the next bit offset after the end of this binding.  */
-  bit_offset_t get_next_bit_offset () const
+  concrete_bit_offset_t
+  get_next_bit_offset () const
   {
-    return m_bit_range.get_next_bit_offset ();
+    return m_bit_range.get_next_offset ();
   }
 
   bool overlaps_p (const concrete_binding &other) const;
 
   static int cmp_ptr_ptr (const void *, const void *);
 
-  void mark_deleted () { m_bit_range.m_size_in_bits = -1; }
-  void mark_empty () { m_bit_range.m_size_in_bits = -2; }
-  bool is_deleted () const { return m_bit_range.m_size_in_bits == -1; }
-  bool is_empty () const { return m_bit_range.m_size_in_bits == -2; }
+  void mark_deleted () { m_bit_range.m_size = concrete_bit_size_t (-1); }
+  void mark_empty () { m_bit_range.m_size = concrete_bit_size_t (-2); }
+  bool is_deleted () const { return m_bit_range.m_size.m_inner == -1; }
+  bool is_empty () const { return m_bit_range.m_size.m_inner == -2; }
 
 private:
-  bit_range m_bit_range;
+  concrete_bit_range_t m_bit_range;
 };
 
 } // namespace ana
@@ -523,7 +377,7 @@ namespace ana {
 class concrete_binding_map
 {
 public:
-  using map_t = std::map<bit_range, const svalue *>;
+  using map_t = std::map<concrete_bit_range_t, const svalue *>;
   using const_iterator = map_t::const_iterator;
   using iterator = map_t::iterator;
 
@@ -561,33 +415,33 @@ public:
        const concrete_binding_map &map2);
 
   void
-  insert (const bit_range &bits, const svalue *sval)
+  insert (const concrete_bit_range_t &bits, const svalue *sval)
   {
     m_map.insert ({bits, sval});
   }
 
   void
-  insert (const byte_range &bytes, const svalue *sval)
+  insert (const concrete_byte_range_t &bytes, const svalue *sval)
   {
-    m_map.insert ({bytes.as_bit_range (), sval});
+    m_map.insert ({as_bits (bytes), sval});
   }
 
   void
-  erase (const bit_range &bits)
+  erase (const concrete_bit_range_t &bits)
   {
     m_map.erase (bits);
   }
 
   const svalue *
-  get_any_exact_binding (const bit_range &bits) const;
+  get_any_exact_binding (const concrete_bit_range_t &bits) const;
 
   const_iterator
-  find (const bit_range &bits) const
+  find (const concrete_bit_range_t &bits) const
   {
     return m_map.find (bits);
   }
   iterator
-  find (const bit_range &bits)
+  find (const concrete_bit_range_t &bits)
   {
     return m_map.find (bits);
   }
@@ -598,16 +452,16 @@ public:
 			     region_model_manager *mgr);
 
   void remove_overlapping_binding (store_manager *mgr,
-				   const bit_range &bits_to_drop,
-				   const bit_range &affected_bound_bits,
+				   const concrete_bit_range_t &bits_to_drop,
+				   const concrete_bit_range_t &affected_bound_bits,
 				   const svalue &old_sval);
 
   void remove_overlapping_bindings (store_manager *mgr,
-				    const bit_range &bits);
+				    const concrete_bit_range_t &bits);
 
 private:
-  std::vector<std::pair<bit_range, const svalue &>>
-  get_overlapping_bindings (const bit_range &bits);
+  std::vector<std::pair<concrete_bit_range_t, const svalue &>>
+  get_overlapping_bindings (const concrete_bit_range_t &bits);
 
   bool apply_ctor_val_to_range (const region *parent_reg,
 				region_model_manager *mgr,
@@ -1047,19 +901,18 @@ public:
 
   /* binding consolidation.  */
   const concrete_binding *
-  get_concrete_binding (bit_offset_t start_bit_offset,
-			bit_offset_t size_in_bits);
+  get_concrete_binding (concrete_bit_offset_t start_bit_offset,
+			concrete_bit_size_t size_in_bits);
   const concrete_binding *
-  get_concrete_binding (const bit_range &bits)
+  get_concrete_binding (const concrete_bit_range_t &bits)
   {
-    return get_concrete_binding (bits.get_start_bit_offset (),
-				 bits.m_size_in_bits);
+    return get_concrete_binding (bits.get_start_offset (),
+				 bits.m_size);
   }
   const concrete_binding *
-  get_concrete_binding (const byte_range &bytes)
+  get_concrete_binding (const concrete_byte_range_t &bytes)
   {
-    bit_range bits = bytes.as_bit_range ();
-    return get_concrete_binding (bits);
+    return get_concrete_binding (as_bits (bytes));
   }
   const symbolic_binding *
   get_symbolic_binding (const region *region);
diff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc
index 45e6898be1a7..b64b2f96b8a2 100644
--- a/gcc/analyzer/svalue.cc
+++ b/gcc/analyzer/svalue.cc
@@ -649,8 +649,9 @@ svalue::cmp_ptr (const svalue *sval1, const svalue *sval2)
 	  = (const bits_within_svalue *)sval1;
 	const bits_within_svalue *bits_within_sval2
 	  = (const bits_within_svalue *)sval2;
-	if (int cmp = bit_range::cmp (bits_within_sval1->get_bits (),
-				       bits_within_sval2->get_bits ()))
+	if (int cmp
+	      = concrete_bit_range_t::cmp (bits_within_sval1->get_bits (),
+					   bits_within_sval2->get_bits ()))
 	  return cmp;
 	return svalue::cmp_ptr (bits_within_sval1->get_inner_svalue (),
 				bits_within_sval2->get_inner_svalue ());
@@ -818,7 +819,7 @@ svalue::involves_p (const svalue *other) const
 
 const svalue *
 svalue::extract_bit_range (tree type,
-			   const bit_range &subrange,
+			   const concrete_bit_range_t &subrange,
 			   region_model_manager *mgr) const
 {
   return mgr->get_or_create_bits_within (type, subrange, this);
@@ -828,7 +829,7 @@ svalue::extract_bit_range (tree type,
 
 const svalue *
 svalue::maybe_fold_bits_within (tree,
-				const bit_range &,
+				const concrete_bit_range_t &,
 				region_model_manager *) const
 {
   /* By default, don't fold.  */
@@ -1192,7 +1193,7 @@ constant_svalue::eval_condition (const constant_svalue *lhs,
 
 const svalue *
 constant_svalue::maybe_fold_bits_within (tree type,
-					 const bit_range &bits,
+					 const concrete_bit_range_t &bits,
 					 region_model_manager *mgr) const
 {
   /* Bits within an all-zero value are also all zero.  */
@@ -1205,13 +1206,13 @@ constant_svalue::maybe_fold_bits_within (tree type,
     }
 
   /* Handle the case of extracting a single bit. */
-  if (bits.m_size_in_bits == 1
+  if (bits.m_size.m_inner == 1
       && TREE_CODE (m_cst_expr) == INTEGER_CST
       && type
       && INTEGRAL_TYPE_P (type)
       && tree_fits_uhwi_p (m_cst_expr))
     {
-      unsigned HOST_WIDE_INT bit = bits.m_start_bit_offset.to_uhwi ();
+      unsigned HOST_WIDE_INT bit = bits.m_start_offset.m_inner.to_uhwi ();
       unsigned HOST_WIDE_INT mask = (1 << bit);
       unsigned HOST_WIDE_INT val_as_hwi = tree_to_uhwi (m_cst_expr);
       unsigned HOST_WIDE_INT masked_val = val_as_hwi & mask;
@@ -1303,7 +1304,7 @@ unknown_svalue::accept (visitor *v) const
 
 const svalue *
 unknown_svalue::maybe_fold_bits_within (tree type,
-					const bit_range &,
+					const concrete_bit_range_t &,
 					region_model_manager *mgr) const
 {
   /* Bits within an unknown_svalue are themselves unknown.  */
@@ -1392,7 +1393,7 @@ poisoned_svalue::accept (visitor *v) const
 
 const svalue *
 poisoned_svalue::maybe_fold_bits_within (tree type,
-					 const bit_range &,
+					 const concrete_bit_range_t &,
 					 region_model_manager *mgr) const
 {
   /* Bits within a poisoned value are also poisoned.  */
@@ -1596,7 +1597,7 @@ unaryop_svalue::implicitly_live_p (const svalue_set *live_svalues,
 
 const svalue *
 unaryop_svalue::maybe_fold_bits_within (tree type,
-					const bit_range &,
+					const concrete_bit_range_t &,
 					region_model_manager *mgr) const
 {
   switch (m_op)
@@ -1991,7 +1992,7 @@ repeated_svalue::all_zeroes_p () const
 
 const svalue *
 repeated_svalue::maybe_fold_bits_within (tree type,
-					 const bit_range &bits,
+					 const concrete_bit_range_t &bits,
 					 region_model_manager *mgr) const
 {
   const svalue *innermost_sval = m_inner_svalue;
@@ -2001,7 +2002,7 @@ repeated_svalue::maybe_fold_bits_within (tree type,
        REPEATED_SVALUE (ZERO).  */
   if (all_zeroes_p ())
     {
-      byte_range bytes (0,0);
+      concrete_byte_range_t bytes (0,0);
       if (bits.as_byte_range (&bytes))
 	{
 	  const svalue *byte_size
@@ -2033,7 +2034,7 @@ repeated_svalue::maybe_fold_bits_within (tree type,
 	    {
 	      bit_offset_t start_of_element
 		= start_idx * element_bit_size;
-	      bit_range range_within_element
+	      concrete_bit_range_t range_within_element
 		(bits.m_start_bit_offset - start_of_element,
 		 bits.m_size_in_bits);
 	      return mgr->get_or_create_bits_within (type,
@@ -2064,7 +2065,7 @@ bits_within_svalue::key_t::operator< (const key_t &other) const
 
 bits_within_svalue::bits_within_svalue (symbol::id_t id,
 					tree type,
-					const bit_range &bits,
+					const concrete_bit_range_t &bits,
 					const svalue *inner_svalue)
 : svalue (complexity (inner_svalue), id, type),
   m_bits (bits),
@@ -2132,16 +2133,17 @@ add_dump_widget_children (text_art::tree_widget &w,
 
 const svalue *
 bits_within_svalue::maybe_fold_bits_within (tree type,
-					    const bit_range &bits,
+					    const concrete_bit_range_t &bits,
 					    region_model_manager *mgr) const
 {
   /* Fold:
        BITS_WITHIN (range1, BITS_WITHIN (range2, VAL))
      to:
        BITS_WITHIN (range1 in range 2, VAL).  */
-  bit_range offset_bits (m_bits.get_start_bit_offset ()
-			 + bits.m_start_bit_offset,
-			 bits.m_size_in_bits);
+  concrete_bit_range_t offset_bits
+    (m_bits.get_start_bit_offset ()
+     + bits.m_start_bit_offset,
+     bits.m_size_in_bits);
   return mgr->get_or_create_bits_within (type, offset_bits, m_inner_svalue);
 }
 
@@ -2564,13 +2566,13 @@ compound_svalue::accept (visitor *v) const
 
 const svalue *
 compound_svalue::maybe_fold_bits_within (tree type,
-					 const bit_range &bits,
+					 const concrete_bit_range_t &bits,
 					 region_model_manager *mgr) const
 {
   concrete_binding_map result_map;
   for (auto iter : m_map)
     {
-      const bit_range &iter_bits = iter.first;
+      const concrete_bit_range_t &iter_bits = iter.first;
 
       /* Ignore concrete bindings outside BITS.  */
       if (!iter_bits.intersects_p (bits))
@@ -2578,9 +2580,10 @@ compound_svalue::maybe_fold_bits_within (tree type,
 
       const svalue *sval = iter.second;
       /* Get the position of iter_bits relative to BITS.  */
-      bit_range result_location (iter_bits.get_start_bit_offset ()
-				 - bits.get_start_bit_offset (),
-				 iter_bits.m_size_in_bits);
+      concrete_bit_range_t result_location
+	(iter_bits.get_start_bit_offset ()
+	 - bits.get_start_bit_offset (),
+	 iter_bits.m_size_in_bits);
       /* If iter_bits starts after BITS, trim off leading bits
 	 from the svalue and adjust binding location.  */
       if (result_location.m_start_bit_offset < 0)
diff --git a/gcc/analyzer/svalue.h b/gcc/analyzer/svalue.h
index 0ec3a79f2ede..134459a42cf1 100644
--- a/gcc/analyzer/svalue.h
+++ b/gcc/analyzer/svalue.h
@@ -167,12 +167,12 @@ public:
 
   const svalue *
   extract_bit_range (tree type,
-		     const bit_range &subrange,
+		     const concrete_bit_range_t &subrange,
 		     region_model_manager *mgr) const;
 
   virtual const svalue *
   maybe_fold_bits_within (tree type,
-			  const bit_range &subrange,
+			  const concrete_bit_range_t &subrange,
 			  region_model_manager *mgr) const;
 
   virtual bool all_zeroes_p () const;
@@ -347,7 +347,7 @@ public:
 
   const svalue *
   maybe_fold_bits_within (tree type,
-			  const bit_range &subrange,
+			  const concrete_bit_range_t &subrange,
 			  region_model_manager *mgr) const final override;
 
   bool all_zeroes_p () const final override;
@@ -396,7 +396,7 @@ public:
 
   const svalue *
   maybe_fold_bits_within (tree type,
-			  const bit_range &subrange,
+			  const concrete_bit_range_t &subrange,
 			  region_model_manager *mgr) const final override;
 
   bool maybe_get_value_range_1 (value_range &out) const final override;
@@ -474,7 +474,7 @@ public:
 
   const svalue *
   maybe_fold_bits_within (tree type,
-			  const bit_range &subrange,
+			  const concrete_bit_range_t &subrange,
 			  region_model_manager *mgr) const final override;
 
   enum poison_kind get_poison_kind () const { return m_kind; }
@@ -696,7 +696,7 @@ public:
 
   const svalue *
   maybe_fold_bits_within (tree type,
-			  const bit_range &subrange,
+			  const concrete_bit_range_t &subrange,
 			  region_model_manager *mgr) const final override;
 
   bool maybe_get_value_range_1 (value_range &out) const final override;
@@ -924,7 +924,7 @@ public:
 
   const svalue *
   maybe_fold_bits_within (tree type,
-			  const bit_range &subrange,
+			  const concrete_bit_range_t &subrange,
 			  region_model_manager *mgr) const final override;
 
  private:
@@ -956,7 +956,7 @@ public:
   struct key_t
   {
     key_t (tree type,
-	   const bit_range &bits,
+	   const concrete_bit_range_t &bits,
 	   const svalue *inner_svalue)
     : m_type (type), m_bits (bits), m_inner_svalue (inner_svalue)
     {}
@@ -970,12 +970,12 @@ public:
     }
 
     tree m_type;
-    bit_range m_bits;
+    concrete_bit_range_t m_bits;
     const svalue *m_inner_svalue;
   };
   bits_within_svalue (symbol::id_t id,
 		      tree type,
-		      const bit_range &bits,
+		      const concrete_bit_range_t &bits,
 		      const svalue *inner_svalue);
 
   enum svalue_kind get_kind () const final override { return SK_BITS_WITHIN; }
@@ -997,16 +997,16 @@ public:
   bool implicitly_live_p (const svalue_set *,
 			  const region_model *) const final override;
 
-  const bit_range &get_bits () const { return m_bits; }
+  const concrete_bit_range_t &get_bits () const { return m_bits; }
   const svalue *get_inner_svalue () const { return m_inner_svalue; }
 
   const svalue *
   maybe_fold_bits_within (tree type,
-			  const bit_range &subrange,
+			  const concrete_bit_range_t &subrange,
 			  region_model_manager *mgr) const final override;
 
  private:
-  const bit_range m_bits;
+  const concrete_bit_range_t m_bits;
   const svalue *m_inner_svalue;
 };
 
@@ -1290,7 +1290,7 @@ public:
 
   const svalue *
   maybe_fold_bits_within (tree type,
-			  const bit_range &subrange,
+			  const concrete_bit_range_t &subrange,
 			  region_model_manager *mgr) const final override;
 
  private:
-- 
2.49.0

