]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/analyzer/region.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / analyzer / region.cc
index 6d97590a83a0548aea2bc83273ce365d17bbadde..249852a7da8b648492f3bee3976d8c92bbc9b36a 100644 (file)
@@ -1,5 +1,5 @@
 /* Regions of memory.
-   Copyright (C) 2019-2022 Free Software Foundation, Inc.
+   Copyright (C) 2019-2024 Free Software Foundation, Inc.
    Contributed by David Malcolm <dmalcolm@redhat.com>.
 
 This file is part of GCC.
@@ -40,7 +40,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "fold-const.h"
 #include "tree-pretty-print.h"
 #include "diagnostic-color.h"
-#include "diagnostic-metadata.h"
 #include "bitmap.h"
 #include "analyzer/analyzer.h"
 #include "analyzer/analyzer-logging.h"
@@ -63,21 +62,339 @@ along with GCC; see the file COPYING3.  If not see
 
 namespace ana {
 
-/* class region and its various subclasses.  */
+region_offset
+region_offset::make_byte_offset (const region *base_region,
+                                const svalue *num_bytes_sval)
+{
+  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;
+      return make_concrete (base_region, num_bits);
+    }
+  else
+    {
+      return make_symbolic (base_region, num_bytes_sval);
+    }
+}
 
-/* class region.  */
+tree
+region_offset::calc_symbolic_bit_offset (const region_model &model) const
+{
+  if (symbolic_p ())
+    {
+      tree num_bytes_expr = model.get_representative_tree (m_sym_offset);
+      if (!num_bytes_expr)
+       return NULL_TREE;
+      tree bytes_to_bits_scale = build_int_cst (size_type_node, BITS_PER_UNIT);
+      return fold_build2 (MULT_EXPR, size_type_node,
+                         num_bytes_expr, bytes_to_bits_scale);
+    }
+  else
+    {
+      tree cst = wide_int_to_tree (size_type_node, m_offset);
+      return cst;
+    }
+}
 
-region::~region ()
+const svalue *
+region_offset::calc_symbolic_byte_offset (region_model_manager *mgr) const
 {
-  delete m_cached_offset;
+  if (symbolic_p ())
+    return m_sym_offset;
+  else
+    {
+      byte_offset_t concrete_byte_offset;
+      if (get_concrete_byte_offset (&concrete_byte_offset))
+       return mgr->get_or_create_int_cst (size_type_node,
+                                          concrete_byte_offset);
+      else
+       /* Can't handle bitfields; return UNKNOWN.  */
+       return mgr->get_or_create_unknown_svalue (size_type_node);
+    }
 }
 
-/* Compare REG1 and REG2 by id.  */
+void
+region_offset::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+  if (symbolic_p ())
+    {
+      /* We don't bother showing the base region.  */
+      pp_string (pp, "byte ");
+      m_sym_offset->dump_to_pp (pp, simple);
+    }
+  else
+    {
+      if (m_offset % BITS_PER_UNIT == 0)
+       {
+         pp_string (pp, "byte ");
+         pp_wide_int (pp, m_offset / BITS_PER_UNIT, SIGNED);
+       }
+      else
+       {
+         pp_string (pp, "bit ");
+         pp_wide_int (pp, m_offset, SIGNED);
+       }
+    }
+}
 
-int
-region::cmp_ids (const region *reg1, const region *reg2)
+DEBUG_FUNCTION void
+region_offset::dump (bool simple) const
 {
-  return (long)reg1->get_id () - (long)reg2->get_id ();
+  pretty_printer pp;
+  pp_format_decoder (&pp) = default_tree_printer;
+  pp_show_color (&pp) = pp_show_color (global_dc->printer);
+  pp.buffer->stream = stderr;
+  dump_to_pp (&pp, simple);
+  pp_newline (&pp);
+  pp_flush (&pp);
+}
+
+/* An svalue that matches the pattern (BASE * FACTOR) + OFFSET
+   where FACTOR or OFFSET could be the identity (represented as NULL).  */
+
+struct linear_op
+{
+  linear_op (const svalue *base,
+            const svalue *factor,
+            const svalue *offset)
+  : m_base (base), m_factor (factor), m_offset (offset)
+  {
+  }
+
+  bool maybe_get_cst_factor (bit_offset_t *out) const
+  {
+    if (m_factor == nullptr)
+      {
+       *out = 1;
+       return true;
+      }
+    if (tree cst_factor = m_factor->maybe_get_constant ())
+      {
+       *out = wi::to_offset (cst_factor);
+       return true;
+      }
+    return false;
+  }
+
+  bool maybe_get_cst_offset (bit_offset_t *out) const
+  {
+    if (m_offset == nullptr)
+      {
+       *out = 0;
+       return true;
+      }
+    if (tree cst_offset = m_offset->maybe_get_constant ())
+      {
+       *out = wi::to_offset (cst_offset);
+       return true;
+      }
+    return false;
+  }
+
+  static tristate
+  less (const linear_op &a, const linear_op &b)
+  {
+    /* Same base.  */
+    if (a.m_base == b.m_base)
+      {
+       bit_offset_t a_wi_factor;
+       bit_offset_t b_wi_factor;
+       if (a.maybe_get_cst_factor (&a_wi_factor)
+           && b.maybe_get_cst_factor (&b_wi_factor))
+         {
+           if (a_wi_factor != b_wi_factor)
+             return tristate (a_wi_factor < b_wi_factor);
+           else
+             {
+               bit_offset_t a_wi_offset;
+               bit_offset_t b_wi_offset;
+               if (a.maybe_get_cst_offset (&a_wi_offset)
+                   && b.maybe_get_cst_offset (&b_wi_offset))
+                 return tristate (a_wi_offset < b_wi_offset);
+             }
+         }
+      }
+    return tristate::unknown ();
+  }
+
+  static tristate
+  le (const linear_op &a, const linear_op &b)
+  {
+    /* Same base.  */
+    if (a.m_base == b.m_base)
+      {
+       bit_offset_t a_wi_factor;
+       bit_offset_t b_wi_factor;
+       if (a.maybe_get_cst_factor (&a_wi_factor)
+           && b.maybe_get_cst_factor (&b_wi_factor))
+         {
+           if (a_wi_factor != b_wi_factor)
+             return tristate (a_wi_factor <= b_wi_factor);
+           else
+             {
+               bit_offset_t a_wi_offset;
+               bit_offset_t b_wi_offset;
+               if (a.maybe_get_cst_offset (&a_wi_offset)
+                   && b.maybe_get_cst_offset (&b_wi_offset))
+                 return tristate (a_wi_offset <= b_wi_offset);
+             }
+         }
+      }
+    return tristate::unknown ();
+  }
+
+  static bool
+  from_svalue (const svalue &sval, linear_op *out)
+  {
+    switch (sval.get_kind ())
+      {
+      default:
+       break;
+      case SK_BINOP:
+       {
+         const binop_svalue &binop_sval ((const binop_svalue &)sval);
+         if (binop_sval.get_op () == MULT_EXPR)
+           {
+             *out = linear_op (binop_sval.get_arg0 (),
+                               binop_sval.get_arg1 (),
+                               NULL);
+             return true;
+           }
+         else if (binop_sval.get_op () == PLUS_EXPR)
+           {
+             if (binop_sval.get_arg0 ()->get_kind () == SK_BINOP)
+               {
+                 const binop_svalue &inner_binop_sval
+                   ((const binop_svalue &)*binop_sval.get_arg0 ());
+                 if (inner_binop_sval.get_op () == MULT_EXPR)
+                   {
+                     *out = linear_op (inner_binop_sval.get_arg0 (),
+                                       inner_binop_sval.get_arg1 (),
+                                       binop_sval.get_arg1 ());
+                     return true;
+                   }
+               }
+
+             *out = linear_op (binop_sval.get_arg0 (),
+                               NULL,
+                               binop_sval.get_arg1 ());
+             return true;
+           }
+       }
+       break;
+      }
+    return false;
+  }
+
+  const svalue *m_base;
+  const svalue *m_factor;
+  const svalue *m_offset;
+};
+
+bool
+operator< (const region_offset &a, const region_offset &b)
+{
+  if (a.symbolic_p ())
+    {
+      if (b.symbolic_p ())
+       {
+         /* Symbolic vs symbolic.  */
+         const svalue &a_sval = *a.get_symbolic_byte_offset ();
+         const svalue &b_sval = *b.get_symbolic_byte_offset ();
+
+         linear_op op_a (NULL, NULL, NULL);
+         linear_op op_b (NULL, NULL, NULL);
+         if (linear_op::from_svalue (a_sval, &op_a)
+             && linear_op::from_svalue (b_sval, &op_b))
+           {
+             tristate ts = linear_op::less (op_a, op_b);
+             if (ts.is_true ())
+               return true;
+             else if (ts.is_false ())
+               return false;
+           }
+         /* Use svalue's deterministic order, for now.  */
+         return (svalue::cmp_ptr (a.get_symbolic_byte_offset (),
+                                  b.get_symbolic_byte_offset ())
+                 < 0);
+       }
+      else
+       /* Symbolic vs concrete: put all symbolic after all concrete.  */
+       return false;
+    }
+  else
+    {
+      if (b.symbolic_p ())
+       /* Concrete vs symbolic: put all concrete before all symbolic.  */
+       return true;
+      else
+       /* Concrete vs concrete.  */
+       return a.get_bit_offset () < b.get_bit_offset ();
+    }
+}
+
+bool
+operator<= (const region_offset &a, const region_offset &b)
+{
+  if (a.symbolic_p ())
+    {
+      if (b.symbolic_p ())
+       {
+         /* Symbolic vs symbolic.  */
+         const svalue &a_sval = *a.get_symbolic_byte_offset ();
+         const svalue &b_sval = *b.get_symbolic_byte_offset ();
+
+         linear_op op_a (NULL, NULL, NULL);
+         linear_op op_b (NULL, NULL, NULL);
+         if (linear_op::from_svalue (a_sval, &op_a)
+             && linear_op::from_svalue (b_sval, &op_b))
+           {
+             tristate ts = linear_op::le (op_a, op_b);
+             if (ts.is_true ())
+               return true;
+             else if (ts.is_false ())
+               return false;
+           }
+         /* Use svalue's deterministic order, for now.  */
+         return (svalue::cmp_ptr (a.get_symbolic_byte_offset (),
+                                  b.get_symbolic_byte_offset ())
+                 <= 0);
+       }
+      else
+       /* Symbolic vs concrete: put all symbolic after all concrete.  */
+       return false;
+    }
+  else
+    {
+      if (b.symbolic_p ())
+       /* Concrete vs symbolic: put all concrete before all symbolic.  */
+       return true;
+      else
+       /* Concrete vs concrete.  */
+       return a.get_bit_offset () <= b.get_bit_offset ();
+    }
+}
+
+bool
+operator> (const region_offset &a, const region_offset &b)
+{
+  return b < a;
+}
+
+bool
+operator>= (const region_offset &a, const region_offset &b)
+{
+  return b <= a;
+}
+
+/* class region and its various subclasses.  */
+
+/* class region.  */
+
+region::~region ()
+{
+  delete m_cached_offset;
 }
 
 /* Determine the base region for this region: when considering bindings
@@ -196,6 +513,8 @@ region::get_memory_space () const
          return MEMSPACE_HEAP;
        case RK_STRING:
          return MEMSPACE_READONLY_DATA;
+       case RK_PRIVATE:
+         return MEMSPACE_PRIVATE;
        }
       if (iter->get_kind () == RK_CAST)
        iter = iter->dyn_cast_cast_region ()->get_original_region ();
@@ -225,6 +544,7 @@ region::can_have_initial_svalue_p () const
     case MEMSPACE_CODE:
     case MEMSPACE_GLOBALS:
     case MEMSPACE_READONLY_DATA:
+    case MEMSPACE_PRIVATE:
       /* Such regions have initial_svalues.  */
       return true;
 
@@ -272,6 +592,51 @@ region::can_have_initial_svalue_p () const
     }
 }
 
+/* For regions within a global decl, get the svalue for the initial
+   value of this region when the program starts, caching the result.  */
+
+const svalue *
+region::get_initial_value_at_main (region_model_manager *mgr) const
+{
+  if (!m_cached_init_sval_at_main)
+    m_cached_init_sval_at_main = calc_initial_value_at_main (mgr);
+  return m_cached_init_sval_at_main;
+}
+
+/* Implementation of region::get_initial_value_at_main.  */
+
+const svalue *
+region::calc_initial_value_at_main (region_model_manager *mgr) const
+{
+  const decl_region *base_reg = get_base_region ()->dyn_cast_decl_region ();
+  gcc_assert (base_reg);
+
+  /* Attempt to get the initializer value for base_reg.  */
+  if (const svalue *base_reg_init
+      = base_reg->get_svalue_for_initializer (mgr))
+    {
+      if (this == base_reg)
+       return base_reg_init;
+      else
+       {
+         /* Get the value for REG within base_reg_init.  */
+         binding_cluster c (base_reg);
+         c.bind (mgr->get_store_manager (), base_reg, base_reg_init);
+         const svalue *sval
+           = c.get_any_binding (mgr->get_store_manager (), this);
+         if (sval)
+           {
+             if (get_type ())
+               sval = mgr->get_or_create_cast (get_type (), sval);
+             return sval;
+           }
+       }
+    }
+
+  /* Otherwise, return INIT_VAL(REG).  */
+  return mgr->get_or_create_initial_value (this);
+}
+
 /* If this region is a decl_region, return the decl.
    Otherwise return NULL.  */
 
@@ -294,6 +659,35 @@ region::get_offset (region_model_manager *mgr) const
   return *m_cached_offset;
 }
 
+/* Get the region_offset for immediately beyond this region.  */
+
+region_offset
+region::get_next_offset (region_model_manager *mgr) const
+{
+  region_offset start = get_offset (mgr);
+
+  bit_size_t bit_size;
+  if (get_bit_size (&bit_size))
+    {
+      if (start.concrete_p ())
+       {
+         bit_offset_t next_bit_offset = start.get_bit_offset () + bit_size;
+         return region_offset::make_concrete (start.get_base_region (),
+                                              next_bit_offset);
+       }
+    }
+
+  const svalue *start_byte_offset_sval = start.calc_symbolic_byte_offset (mgr);
+  const svalue *byte_size_sval = get_byte_size_sval (mgr);
+  const svalue *sum_sval
+    = mgr->get_or_create_binop (size_type_node,
+                               PLUS_EXPR,
+                               start_byte_offset_sval,
+                               byte_size_sval);
+  return region_offset::make_symbolic (start.get_base_region (),
+                                      sum_sval);
+}
+
 /* Base class implementation of region::get_byte_size vfunc.
    If the size of this region (in bytes) is known statically, write it to *OUT
    and return true.
@@ -350,7 +744,11 @@ int_size_in_bits (const_tree type, bit_size_t *out)
     }
 
   tree sz = TYPE_SIZE (type);
-  if (sz && tree_fits_uhwi_p (sz))
+  if (sz
+      && tree_fits_uhwi_p (sz)
+      /* If the size is zero, then we may have a zero-sized
+        array; handle such cases by returning false.  */
+      && !integer_zerop (sz))
     {
       *out = TREE_INT_CST_LOW (sz);
       return true;
@@ -359,6 +757,24 @@ int_size_in_bits (const_tree type, bit_size_t *out)
     return false;
 }
 
+/* Base implementation of region::get_bit_size_sval vfunc.  */
+
+const svalue *
+region::get_bit_size_sval (region_model_manager *mgr) const
+{
+  tree type = get_type ();
+
+  /* Bail out e.g. for heap-allocated regions.  */
+  if (!type)
+    return mgr->get_or_create_unknown_svalue (size_type_node);
+
+  bit_size_t bits;
+  if (!int_size_in_bits (type, &bits))
+    return mgr->get_or_create_unknown_svalue (size_type_node);
+
+  return mgr->get_or_create_int_cst (size_type_node, bits);
+}
+
 /* If the size of this region (in bits) is known statically, write it to *OUT
    and return true.
    Otherwise return false.  */
@@ -572,7 +988,7 @@ region::get_relative_concrete_offset (bit_offset_t *) const
 const svalue *
 region::get_relative_symbolic_offset (region_model_manager *mgr) const
 {
-  return mgr->get_or_create_unknown_svalue (integer_type_node);
+  return mgr->get_or_create_unknown_svalue (ptrdiff_type_node);
 }
 
 /* Attempt to get the position and size of this region expressed as a
@@ -671,6 +1087,18 @@ region::symbolic_p () const
   return get_kind () == RK_SYMBOLIC;
 }
 
+/* Return true if this region is known to be zero bits in size.  */
+
+bool
+region::empty_p () const
+{
+  bit_size_t num_bits;
+  if (get_bit_size (&num_bits))
+    if (num_bits == 0)
+      return true;
+  return false;
+}
+
 /* Return true if this is a region for a decl with name DECL_NAME.
    Intended for use when debugging (for assertions and conditional
    breakpoints).  */
@@ -687,9 +1115,10 @@ region::is_named_decl_p (const char *decl_name) const
 
 /* region's ctor.  */
 
-region::region (complexity c, unsigned id, const region *parent, tree type)
-: m_complexity (c), m_id (id), m_parent (parent), m_type (type),
-  m_cached_offset (NULL)
+region::region (complexity c, symbol::id_t id, const region *parent, tree type)
+: symbol (c, id),
+  m_parent (parent), m_type (type),
+  m_cached_offset (NULL), m_cached_init_sval_at_main (NULL)
 {
   gcc_assert (type == NULL_TREE || TYPE_P (type));
 }
@@ -935,7 +1364,7 @@ frame_region::get_region_for_local (region_model_manager *mgr,
   if (decl_region **slot = mutable_locals.get (expr))
     return *slot;
   decl_region *reg
-    = new decl_region (mgr->alloc_region_id (), this, expr);
+    = new decl_region (mgr->alloc_symbol_id (), this, expr);
   mutable_locals.put (expr, reg);
   return reg;
 }
@@ -1034,7 +1463,7 @@ heap_region::dump_to_pp (pretty_printer *pp, bool simple) const
 
 /* root_region's ctor.  */
 
-root_region::root_region (unsigned id)
+root_region::root_region (symbol::id_t id)
 : region (complexity (1, 1), id, NULL, NULL_TREE)
 {
 }
@@ -1065,7 +1494,7 @@ thread_local_region::dump_to_pp (pretty_printer *pp, bool simple) const
 
 /* symbolic_region's ctor.  */
 
-symbolic_region::symbolic_region (unsigned id, region *parent,
+symbolic_region::symbolic_region (symbol::id_t id, region *parent,
                                  const svalue *sval_ptr)
 : region (complexity::from_pair (parent, sval_ptr), id, parent,
          (sval_ptr->get_type ()
@@ -1150,7 +1579,7 @@ decl_region::get_stack_depth () const
 const svalue *
 decl_region::maybe_get_constant_value (region_model_manager *mgr) const
 {
-  if (TREE_CODE (m_decl) == VAR_DECL
+  if (VAR_P (m_decl)
       && DECL_IN_CONSTANT_POOL (m_decl)
       && DECL_INITIAL (m_decl)
       && TREE_CODE (DECL_INITIAL (m_decl)) == CONSTRUCTOR)
@@ -1158,14 +1587,13 @@ decl_region::maybe_get_constant_value (region_model_manager *mgr) const
   return NULL;
 }
 
-/* Get an svalue for CTOR, a CONSTRUCTOR for this region's decl.  */
+/* Implementation of decl_region::get_svalue_for_constructor
+   for when the cached value hasn't yet been calculated.  */
 
 const svalue *
-decl_region::get_svalue_for_constructor (tree ctor,
-                                        region_model_manager *mgr) const
+decl_region::calc_svalue_for_constructor (tree ctor,
+                                         region_model_manager *mgr) const
 {
-  gcc_assert (!TREE_CLOBBER_P (ctor));
-
   /* Create a binding map, applying ctor to it, using this
      decl_region as the base region when building child regions
      for offset calculations.  */
@@ -1177,6 +1605,21 @@ decl_region::get_svalue_for_constructor (tree ctor,
   return mgr->get_or_create_compound_svalue (get_type (), map);
 }
 
+/* Get an svalue for CTOR, a CONSTRUCTOR for this region's decl.  */
+
+const svalue *
+decl_region::get_svalue_for_constructor (tree ctor,
+                                        region_model_manager *mgr) const
+{
+  gcc_assert (!TREE_CLOBBER_P (ctor));
+  gcc_assert (ctor == DECL_INITIAL (m_decl));
+
+  if (!m_ctor_svalue)
+    m_ctor_svalue = calc_svalue_for_constructor (ctor, mgr);
+
+  return m_ctor_svalue;
+}
+
 /* For use on decl_regions for global variables.
 
    Get an svalue for the initial value of this region at entry to
@@ -1196,6 +1639,9 @@ decl_region::get_svalue_for_initializer (region_model_manager *mgr) const
       if (DECL_EXTERNAL (m_decl))
        return NULL;
 
+      if (empty_p ())
+       return NULL;
+
       /* Implicit initialization to zero; use a compound_svalue for it.
         Doing so requires that we have a concrete binding for this region,
         which can fail if we have a region with unknown size
@@ -1374,10 +1820,10 @@ field_region::get_relative_symbolic_offset (region_model_manager *mgr) const
   if (get_relative_concrete_offset (&out))
     {
       tree cst_tree
-       = wide_int_to_tree (integer_type_node, out / BITS_PER_UNIT);
+       = wide_int_to_tree (ptrdiff_type_node, out / BITS_PER_UNIT);
       return mgr->get_or_create_constant_svalue (cst_tree);
     }
-  return mgr->get_or_create_unknown_svalue (integer_type_node);
+  return mgr->get_or_create_unknown_svalue (ptrdiff_type_node);
 }
 
 /* class element_region : public region.  */
@@ -1459,14 +1905,14 @@ element_region::get_relative_symbolic_offset (region_model_manager *mgr) const
   HOST_WIDE_INT hwi_byte_size = int_size_in_bytes (elem_type);
   if (hwi_byte_size > 0)
          {
-      tree byte_size_tree = wide_int_to_tree (integer_type_node,
+      tree byte_size_tree = wide_int_to_tree (ptrdiff_type_node,
                                              hwi_byte_size);
       const svalue *byte_size_sval
        = mgr->get_or_create_constant_svalue (byte_size_tree);
-      return mgr->get_or_create_binop (integer_type_node, MULT_EXPR,
+      return mgr->get_or_create_binop (ptrdiff_type_node, MULT_EXPR,
                                       m_index, byte_size_sval);
     }
-  return mgr->get_or_create_unknown_svalue (integer_type_node);
+  return mgr->get_or_create_unknown_svalue (ptrdiff_type_node);
 }
 
 /* class offset_region : public region.  */
@@ -1505,6 +1951,15 @@ offset_region::dump_to_pp (pretty_printer *pp, bool simple) const
     }
 }
 
+const svalue *
+offset_region::get_bit_offset (region_model_manager *mgr) const
+{
+  const svalue *bits_per_byte_sval
+    = mgr->get_or_create_int_cst (size_type_node, BITS_PER_UNIT);
+  return mgr->get_or_create_binop (size_type_node, MULT_EXPR,
+                                  m_byte_offset, bits_per_byte_sval);
+}
+
 /* Implementation of region::get_relative_concrete_offset vfunc
    for offset_region.  */
 
@@ -1559,6 +2014,30 @@ offset_region::get_byte_size_sval (region_model_manager *mgr) const
   return region::get_byte_size_sval (mgr);
 }
 
+/* Implementation of region::get_bit_size_sval vfunc for offset_region.  */
+
+const svalue *
+offset_region::get_bit_size_sval (region_model_manager *mgr) const
+{
+  tree offset_cst = get_bit_offset (mgr)->maybe_get_constant ();
+  bit_size_t bit_size;
+  /* If the offset points in the middle of the region,
+     return the remaining bits.  */
+  if (get_bit_size (&bit_size) && offset_cst)
+    {
+      bit_size_t offset = wi::to_offset (offset_cst);
+      bit_range r (0, bit_size);
+      if (r.contains_p (offset))
+       {
+         tree remaining_bit_size = wide_int_to_tree (size_type_node,
+                                                      bit_size - offset);
+         return mgr->get_or_create_constant_svalue (remaining_bit_size);
+       }
+    }
+
+  return region::get_bit_size_sval (mgr);
+}
+
 /* class sized_region : public region.  */
 
 /* Implementation of region::accept vfunc for sized_region.  */
@@ -1619,6 +2098,17 @@ sized_region::get_bit_size (bit_size_t *out) const
   return true;
 }
 
+/* Implementation of region::get_bit_size_sval vfunc for sized_region.  */
+
+const svalue *
+sized_region::get_bit_size_sval (region_model_manager *mgr) const
+{
+  const svalue *bits_per_byte_sval
+    = mgr->get_or_create_int_cst (size_type_node, BITS_PER_UNIT);
+  return mgr->get_or_create_binop (size_type_node, MULT_EXPR,
+                                  m_byte_size_sval, bits_per_byte_sval);
+}
+
 /* class cast_region : public region.  */
 
 /* Implementation of region::accept vfunc for cast_region.  */
@@ -1770,6 +2260,15 @@ bit_range_region::get_byte_size_sval (region_model_manager *mgr) const
   return mgr->get_or_create_int_cst (size_type_node, num_bytes);
 }
 
+/* Implementation of region::get_bit_size_sval vfunc for bit_range_region.  */
+
+const svalue *
+bit_range_region::get_bit_size_sval (region_model_manager *mgr) const
+{
+  return mgr->get_or_create_int_cst (size_type_node,
+                                    m_bits.m_size_in_bits);
+}
+
 /* Implementation of region::get_relative_concrete_offset vfunc for
    bit_range_region.  */
 
@@ -1790,7 +2289,7 @@ bit_range_region::get_relative_symbolic_offset (region_model_manager *mgr)
   const
 {
   byte_offset_t start_byte = m_bits.get_start_bit_offset () / BITS_PER_UNIT;
-  tree start_bit_tree = wide_int_to_tree (integer_type_node, start_byte);
+  tree start_bit_tree = wide_int_to_tree (ptrdiff_type_node, start_byte);
   return mgr->get_or_create_constant_svalue (start_bit_tree);
 }
 
@@ -1833,6 +2332,17 @@ errno_region::dump_to_pp (pretty_printer *pp, bool simple) const
     pp_string (pp, "errno_region()");
 }
 
+/* class private_region : public region.  */
+
+void
+private_region::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+  if (simple)
+    pp_printf (pp, "PRIVATE_REG(%qs)", m_desc);
+  else
+    pp_printf (pp, "private_region(%qs)", m_desc);
+}
+
 /* class unknown_region : public region.  */
 
 /* Implementation of region::dump_to_pp vfunc for unknown_region.  */