LCOV - code coverage report
Current view: top level - gcc/analyzer - region-model.cc (source / functions) Hit Total Coverage
Test: gcc.info Lines: 3440 3816 90.1 %
Date: 2020-03-28 11:57:23 Functions: 295 330 89.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /* Classes for modeling the state of memory.
       2                 :            :    Copyright (C) 2019-2020 Free Software Foundation, Inc.
       3                 :            :    Contributed by David Malcolm <dmalcolm@redhat.com>.
       4                 :            : 
       5                 :            : This file is part of GCC.
       6                 :            : 
       7                 :            : GCC is free software; you can redistribute it and/or modify it
       8                 :            : under the terms of the GNU General Public License as published by
       9                 :            : the Free Software Foundation; either version 3, or (at your option)
      10                 :            : any later version.
      11                 :            : 
      12                 :            : GCC is distributed in the hope that it will be useful, but
      13                 :            : WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :            : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15                 :            : General Public License for more details.
      16                 :            : 
      17                 :            : You should have received a copy of the GNU General Public License
      18                 :            : along with GCC; see the file COPYING3.  If not see
      19                 :            : <http://www.gnu.org/licenses/>.  */
      20                 :            : 
      21                 :            : #include "config.h"
      22                 :            : #include "system.h"
      23                 :            : #include "coretypes.h"
      24                 :            : #include "tree.h"
      25                 :            : #include "function.h"
      26                 :            : #include "basic-block.h"
      27                 :            : #include "gimple.h"
      28                 :            : #include "gimple-iterator.h"
      29                 :            : #include "diagnostic-core.h"
      30                 :            : #include "graphviz.h"
      31                 :            : #include "options.h"
      32                 :            : #include "cgraph.h"
      33                 :            : #include "tree-dfa.h"
      34                 :            : #include "stringpool.h"
      35                 :            : #include "convert.h"
      36                 :            : #include "target.h"
      37                 :            : #include "fold-const.h"
      38                 :            : #include "tree-pretty-print.h"
      39                 :            : #include "diagnostic-color.h"
      40                 :            : #include "diagnostic-metadata.h"
      41                 :            : #include "tristate.h"
      42                 :            : #include "bitmap.h"
      43                 :            : #include "selftest.h"
      44                 :            : #include "function.h"
      45                 :            : #include "analyzer/analyzer.h"
      46                 :            : #include "analyzer/analyzer-logging.h"
      47                 :            : #include "ordered-hash-map.h"
      48                 :            : #include "options.h"
      49                 :            : #include "cgraph.h"
      50                 :            : #include "cfg.h"
      51                 :            : #include "digraph.h"
      52                 :            : #include "analyzer/supergraph.h"
      53                 :            : #include "sbitmap.h"
      54                 :            : #include "analyzer/region-model.h"
      55                 :            : #include "analyzer/constraint-manager.h"
      56                 :            : #include "diagnostic-event-id.h"
      57                 :            : #include "analyzer/sm.h"
      58                 :            : #include "diagnostic-event-id.h"
      59                 :            : #include "analyzer/sm.h"
      60                 :            : #include "analyzer/pending-diagnostic.h"
      61                 :            : #include "analyzer/analyzer-selftests.h"
      62                 :            : #include "stor-layout.h"
      63                 :            : 
      64                 :            : #if ENABLE_ANALYZER
      65                 :            : 
      66                 :            : namespace ana {
      67                 :            : 
      68                 :            : /* Dump T to PP in language-independent form, for debugging/logging/dumping
      69                 :            :    purposes.  */
      70                 :            : 
      71                 :            : static void
      72                 :        656 : dump_tree (pretty_printer *pp, tree t)
      73                 :            : {
      74                 :         34 :   dump_generic_node (pp, t, 0, TDF_SLIM, 0);
      75                 :         83 : }
      76                 :            : 
      77                 :            : /* Dump T to PP in language-independent form in quotes, for
      78                 :            :    debugging/logging/dumping purposes.  */
      79                 :            : 
      80                 :            : void
      81                 :        108 : dump_quoted_tree (pretty_printer *pp, tree t)
      82                 :            : {
      83                 :        108 :   pp_begin_quote (pp, pp_show_color (pp));
      84                 :        108 :   dump_tree (pp, t);
      85                 :        108 :   pp_end_quote (pp, pp_show_color (pp));
      86                 :        108 : }
      87                 :            : 
      88                 :            : /* Equivalent to pp_printf (pp, "%qT", t), to avoid nesting pp_printf
      89                 :            :    calls within other pp_printf calls.
      90                 :            : 
      91                 :            :    default_tree_printer handles 'T' and some other codes by calling
      92                 :            :      dump_generic_node (pp, t, 0, TDF_SLIM, 0);
      93                 :            :    dump_generic_node calls pp_printf in various places, leading to
      94                 :            :    garbled output.
      95                 :            : 
      96                 :            :    Ideally pp_printf could be made to be reentrant, but in the meantime
      97                 :            :    this function provides a workaround.  */
      98                 :            : 
      99                 :            : static void
     100                 :         66 : print_quoted_type (pretty_printer *pp, tree t)
     101                 :            : {
     102                 :         66 :   pp_begin_quote (pp, pp_show_color (pp));
     103                 :         66 :   dump_generic_node (pp, t, 0, TDF_SLIM, 0);
     104                 :         66 :   pp_end_quote (pp, pp_show_color (pp));
     105                 :         66 : }
     106                 :            : 
     107                 :            : /* Dump this path_var to PP (which must support %E for trees).
     108                 :            : 
     109                 :            :    Express the stack depth using an "@DEPTH" suffix, so e.g. given
     110                 :            :      void foo (int j);
     111                 :            :      void bar (int i)
     112                 :            :      {
     113                 :            :        foo (i);
     114                 :            :      }
     115                 :            :    then:
     116                 :            :    - the "i" in "bar" would be "(i @ 0)"
     117                 :            :    - the "j" in "foo" would be "(j @ 1)".  */
     118                 :            : 
     119                 :            : void
     120                 :          0 : path_var::dump (pretty_printer *pp) const
     121                 :            : {
     122                 :          0 :   if (m_tree == NULL_TREE)
     123                 :          0 :     pp_string (pp, "NULL");
     124                 :          0 :   if (CONSTANT_CLASS_P (m_tree))
     125                 :          0 :     pp_printf (pp, "%qE", m_tree);
     126                 :            :   else
     127                 :          0 :     pp_printf (pp, "(%qE @ %i)", m_tree, m_stack_depth);
     128                 :          0 : }
     129                 :            : 
     130                 :            : /* For use in printing a comma-separated list.  */
     131                 :            : 
     132                 :            : static void
     133                 :        220 : dump_separator (pretty_printer *pp, bool *is_first)
     134                 :            : {
     135                 :          0 :   if (!*is_first)
     136                 :        138 :     pp_string (pp, ", ");
     137                 :        220 :   *is_first = false;
     138                 :          0 : }
     139                 :            : 
     140                 :            : /* Concrete subclass of constraint_manager that wires it up to a region_model
     141                 :            :    (whilst allowing the constraint_manager and region_model to be somewhat
     142                 :            :    at arms length).
     143                 :            :    TODO: revisit this; maybe put the region_model * into the constraint_manager
     144                 :            :    base class.  */
     145                 :            : 
     146                 :            : class impl_constraint_manager : public constraint_manager
     147                 :            : {
     148                 :            :  public:
     149                 :     175497 :   impl_constraint_manager (region_model *model)
     150                 :     175497 :   : constraint_manager (),
     151                 :     175497 :     m_model (model)
     152                 :            :   {}
     153                 :            : 
     154                 :     162761 :   impl_constraint_manager (const impl_constraint_manager &other,
     155                 :            :                            region_model *model)
     156                 :     162761 :   : constraint_manager (other),
     157                 :     325522 :     m_model (model)
     158                 :            :   {}
     159                 :            : 
     160                 :     162761 :   constraint_manager *clone (region_model *model) const
     161                 :            :   {
     162                 :     162761 :     return new impl_constraint_manager (*this, model);
     163                 :            :   }
     164                 :            : 
     165                 :     289157 :   tree maybe_get_constant (svalue_id sid) const FINAL OVERRIDE
     166                 :            :   {
     167                 :     289157 :     svalue *svalue = m_model->get_svalue (sid);
     168                 :     289157 :     return svalue->maybe_get_constant ();
     169                 :            :   }
     170                 :            : 
     171                 :     736324 :   svalue_id get_sid_for_constant (tree cst) const FINAL OVERRIDE
     172                 :            :   {
     173                 :     736324 :     gcc_assert (CONSTANT_CLASS_P (cst));
     174                 :     736324 :     return m_model->get_rvalue (cst, NULL);
     175                 :            :   }
     176                 :            : 
     177                 :    1558720 :   int get_num_svalues () const FINAL OVERRIDE
     178                 :            :   {
     179                 :    1558720 :     return m_model->get_num_svalues ();
     180                 :            :   }
     181                 :            : 
     182                 :            :  private:
     183                 :            :   region_model *m_model;
     184                 :            : };
     185                 :            : 
     186                 :            : /* class svalue_id.  */
     187                 :            : 
     188                 :            : /* Print this svalue_id to PP.  */
     189                 :            : 
     190                 :            : void
     191                 :        173 : svalue_id::print (pretty_printer *pp) const
     192                 :            : {
     193                 :        173 :   if (null_p ())
     194                 :         28 :     pp_printf (pp, "null");
     195                 :            :   else
     196                 :        145 :     pp_printf (pp, "sv%i", m_idx);
     197                 :        173 : }
     198                 :            : 
     199                 :            : /* Print this svalue_id in .dot format to PP.  */
     200                 :            : 
     201                 :            : void
     202                 :          0 : svalue_id::dump_node_name_to_pp (pretty_printer *pp) const
     203                 :            : {
     204                 :          0 :   gcc_assert (!null_p ());
     205                 :          0 :   pp_printf (pp, "svalue_%i", m_idx);
     206                 :          0 : }
     207                 :            : 
     208                 :            : /* Assert that this object is valid (w.r.t. MODEL).  */
     209                 :            : 
     210                 :            : void
     211                 :    5167650 : svalue_id::validate (const region_model &model) const
     212                 :            : {
     213                 :    8014080 :   gcc_assert (null_p () || m_idx < (int)model.get_num_svalues ());
     214                 :    5167650 : }
     215                 :            : 
     216                 :            : /* class region_id.  */
     217                 :            : 
     218                 :            : /* Print this region_id to PP.  */
     219                 :            : 
     220                 :            : void
     221                 :        181 : region_id::print (pretty_printer *pp) const
     222                 :            : {
     223                 :        181 :   if (null_p ())
     224                 :         10 :     pp_printf (pp, "null");
     225                 :            :   else
     226                 :        171 :     pp_printf (pp, "r%i", m_idx);
     227                 :        181 : }
     228                 :            : 
     229                 :            : /* Print this region_id in .dot format to PP.  */
     230                 :            : 
     231                 :            : void
     232                 :          0 : region_id::dump_node_name_to_pp (pretty_printer *pp) const
     233                 :            : {
     234                 :          0 :   gcc_assert (!null_p ());
     235                 :          0 :   pp_printf (pp, "region_%i", m_idx);
     236                 :          0 : }
     237                 :            : 
     238                 :            : /* Assert that this object is valid (w.r.t. MODEL).  */
     239                 :            : 
     240                 :            : void
     241                 :   15267300 : region_id::validate (const region_model &model) const
     242                 :            : {
     243                 :   24448100 :   gcc_assert (null_p () || m_idx < (int)model.get_num_regions ());
     244                 :   15267300 : }
     245                 :            : 
     246                 :            : /* class id_set.  */
     247                 :            : 
     248                 :            : /* id_set<region_id>'s ctor.  */
     249                 :            : 
     250                 :            : template<>
     251                 :      32288 : id_set<region_id>::id_set (const region_model *model)
     252                 :      64576 : : m_bitmap (model->get_num_regions ())
     253                 :            : {
     254                 :      32288 :   bitmap_clear (m_bitmap);
     255                 :      32288 : }
     256                 :            : 
     257                 :            : /* class svalue and its various subclasses.  */
     258                 :            : 
     259                 :            : /* class svalue.  */
     260                 :            : 
     261                 :            : /* svalue's equality operator.  Most of the work is done by the
     262                 :            :    a "compare_fields" implementation on each subclass.  */
     263                 :            : 
     264                 :            : bool
     265                 :     271867 : svalue::operator== (const svalue &other) const
     266                 :            : {
     267                 :     271867 :   enum svalue_kind this_kind = get_kind ();
     268                 :     271867 :   enum svalue_kind other_kind = other.get_kind ();
     269                 :     271867 :   if (this_kind != other_kind)
     270                 :            :     return false;
     271                 :            : 
     272                 :     271814 :   if (m_type != other.m_type)
     273                 :            :     return false;
     274                 :            : 
     275                 :     271759 :   switch (this_kind)
     276                 :            :     {
     277                 :          0 :     default:
     278                 :          0 :       gcc_unreachable ();
     279                 :      31910 :     case SK_REGION:
     280                 :      31910 :       {
     281                 :      31910 :         const region_svalue &this_sub
     282                 :            :           = (const region_svalue &)*this;
     283                 :      31910 :         const region_svalue &other_sub
     284                 :            :           = (const region_svalue &)other;
     285                 :      31910 :         return this_sub.compare_fields (other_sub);
     286                 :            :       }
     287                 :      78568 :       break;
     288                 :      78568 :     case SK_CONSTANT:
     289                 :      78568 :       {
     290                 :      78568 :         const constant_svalue &this_sub
     291                 :            :           = (const constant_svalue &)*this;
     292                 :      78568 :         const constant_svalue &other_sub
     293                 :            :           = (const constant_svalue &)other;
     294                 :      78568 :         return this_sub.compare_fields (other_sub);
     295                 :            :       }
     296                 :     101506 :       break;
     297                 :     101506 :     case SK_UNKNOWN:
     298                 :     101506 :       {
     299                 :     101506 :         const unknown_svalue &this_sub
     300                 :            :           = (const unknown_svalue &)*this;
     301                 :     101506 :         const unknown_svalue &other_sub
     302                 :            :           = (const unknown_svalue &)other;
     303                 :     101506 :         return this_sub.compare_fields (other_sub);
     304                 :            :       }
     305                 :      59540 :       break;
     306                 :      59540 :     case SK_POISONED:
     307                 :      59540 :       {
     308                 :      59540 :         const poisoned_svalue &this_sub
     309                 :            :           = (const poisoned_svalue &)*this;
     310                 :      59540 :         const poisoned_svalue &other_sub
     311                 :            :           = (const poisoned_svalue &)other;
     312                 :      59540 :         return this_sub.compare_fields (other_sub);
     313                 :            :       }
     314                 :        235 :       break;
     315                 :        235 :     case SK_SETJMP:
     316                 :        235 :       {
     317                 :        235 :         const setjmp_svalue &this_sub
     318                 :            :           = (const setjmp_svalue &)*this;
     319                 :        235 :         const setjmp_svalue &other_sub
     320                 :            :           = (const setjmp_svalue &)other;
     321                 :        235 :         return this_sub.compare_fields (other_sub);
     322                 :            :       }
     323                 :            :       break;
     324                 :            :     }
     325                 :            : }
     326                 :            : 
     327                 :            : /* Generate a hash value for this svalue.  Most of the work is done by the
     328                 :            :    add_to_hash vfunc.  */
     329                 :            : 
     330                 :            : hashval_t
     331                 :     808205 : svalue::hash () const
     332                 :            : {
     333                 :     808205 :   inchash::hash hstate;
     334                 :     808205 :   if (m_type)
     335                 :     652578 :     hstate.add_int (TYPE_UID (m_type));
     336                 :     808205 :   add_to_hash (hstate);
     337                 :     808205 :   return hstate.end ();
     338                 :            : }
     339                 :            : 
     340                 :            : /* Print this svalue and its ID to PP.  */
     341                 :            : 
     342                 :            : void
     343                 :         42 : svalue::print (const region_model &model,
     344                 :            :                svalue_id this_sid,
     345                 :            :                pretty_printer *pp) const
     346                 :            : {
     347                 :         42 :   this_sid.print (pp);
     348                 :         42 :   pp_string (pp, ": {");
     349                 :            : 
     350                 :         42 :   if (m_type)
     351                 :            :     {
     352                 :         30 :       gcc_assert (TYPE_P (m_type));
     353                 :         30 :       pp_string (pp, "type: ");
     354                 :         30 :       print_quoted_type (pp, m_type);
     355                 :         30 :       pp_string (pp, ", ");
     356                 :            :     }
     357                 :            : 
     358                 :            :   /* vfunc.  */
     359                 :         42 :   print_details (model, this_sid, pp);
     360                 :            : 
     361                 :         42 :   pp_string (pp, "}");
     362                 :         42 : }
     363                 :            : 
     364                 :            : /* Dump this svalue in the form of a .dot record to PP.  */
     365                 :            : 
     366                 :            : void
     367                 :          0 : svalue::dump_dot_to_pp (const region_model &model,
     368                 :            :                         svalue_id this_sid,
     369                 :            :                         pretty_printer *pp) const
     370                 :            : {
     371                 :          0 :   this_sid.dump_node_name_to_pp (pp);
     372                 :          0 :   pp_printf (pp, " [label=\"");
     373                 :          0 :   pp_write_text_to_stream (pp);
     374                 :          0 :   this_sid.print (pp);
     375                 :          0 :   pp_string (pp, ": {");
     376                 :          0 :   print (model, this_sid, pp);
     377                 :          0 :   pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
     378                 :          0 :   pp_string (pp, "}\"];");
     379                 :          0 :   pp_newline (pp);
     380                 :          0 : }
     381                 :            : 
     382                 :            : /* Base implementation of svalue::remap_region_ids vfunc.  */
     383                 :            : 
     384                 :            : void
     385                 :     704538 : svalue::remap_region_ids (const region_id_map &)
     386                 :            : {
     387                 :            :   /* Empty.  */
     388                 :     704538 : }
     389                 :            : 
     390                 :            : /* Base implementation of svalue::walk_for_canonicalization vfunc.  */
     391                 :            : 
     392                 :            : void
     393                 :     457850 : svalue::walk_for_canonicalization (canonicalization *) const
     394                 :            : {
     395                 :            :   /* Empty.  */
     396                 :     457850 : }
     397                 :            : 
     398                 :            : /* Base implementation of svalue::get_child_sid vfunc.  */
     399                 :            : 
     400                 :            : svalue_id
     401                 :       5461 : svalue::get_child_sid (region *parent ATTRIBUTE_UNUSED,
     402                 :            :                        region *child,
     403                 :            :                        region_model &model,
     404                 :            :                        region_model_context *ctxt ATTRIBUTE_UNUSED)
     405                 :            : {
     406                 :       5461 :   svalue *new_child_value = clone ();
     407                 :       5461 :   if (child->get_type ())
     408                 :       3851 :     new_child_value->m_type = child->get_type ();
     409                 :       5461 :   svalue_id new_child_sid = model.add_svalue (new_child_value);
     410                 :       5461 :   return new_child_sid;
     411                 :            : }
     412                 :            : 
     413                 :            : /* If this svalue is a constant_svalue, return the underlying tree constant.
     414                 :            :    Otherwise return NULL_TREE.  */
     415                 :            : 
     416                 :            : tree
     417                 :    6778570 : svalue::maybe_get_constant () const
     418                 :            : {
     419                 :    6778570 :   if (const constant_svalue *cst_sval = dyn_cast_constant_svalue ())
     420                 :    2173640 :     return cst_sval->get_constant ();
     421                 :            :   else
     422                 :            :     return NULL_TREE;
     423                 :            : }
     424                 :            : 
     425                 :            : /* class region_svalue : public svalue.  */
     426                 :            : 
     427                 :            : /* Compare the fields of this region_svalue with OTHER, returning true
     428                 :            :    if they are equal.
     429                 :            :    For use by svalue::operator==.  */
     430                 :            : 
     431                 :            : bool
     432                 :      31910 : region_svalue::compare_fields (const region_svalue &other) const
     433                 :            : {
     434                 :      31910 :   return m_rid == other.m_rid;
     435                 :            : }
     436                 :            : 
     437                 :            : /* Implementation of svalue::add_to_hash vfunc for region_svalue.  */
     438                 :            : 
     439                 :            : void
     440                 :      88869 : region_svalue::add_to_hash (inchash::hash &hstate) const
     441                 :            : {
     442                 :      88869 :   inchash::add (m_rid, hstate);
     443                 :      88869 : }
     444                 :            : 
     445                 :            : /* Implementation of svalue::print_details vfunc for region_svalue.  */
     446                 :            : 
     447                 :            : void
     448                 :         10 : region_svalue::print_details (const region_model &model ATTRIBUTE_UNUSED,
     449                 :            :                               svalue_id this_sid ATTRIBUTE_UNUSED,
     450                 :            :                               pretty_printer *pp) const
     451                 :            : {
     452                 :         10 :   if (m_rid.null_p ())
     453                 :          0 :     pp_string (pp, "NULL");
     454                 :            :   else
     455                 :            :     {
     456                 :         10 :       pp_string (pp, "&");
     457                 :         10 :       m_rid.print (pp);
     458                 :            :     }
     459                 :         10 : }
     460                 :            : 
     461                 :            : /* Implementation of svalue::dump_dot_to_pp for region_svalue.  */
     462                 :            : 
     463                 :            : void
     464                 :          0 : region_svalue::dump_dot_to_pp (const region_model &model,
     465                 :            :                                svalue_id this_sid,
     466                 :            :                                pretty_printer *pp) const
     467                 :            : {
     468                 :          0 :   svalue::dump_dot_to_pp (model, this_sid, pp);
     469                 :            : 
     470                 :            :   /* If non-NULL, add an edge to the pointed-to region.  */
     471                 :          0 :   if (!m_rid.null_p ())
     472                 :            :     {
     473                 :          0 :       this_sid.dump_node_name_to_pp (pp);
     474                 :          0 :       pp_string (pp, " -> ");
     475                 :          0 :       m_rid.dump_node_name_to_pp (pp);
     476                 :          0 :       pp_string (pp, ";");
     477                 :          0 :       pp_newline (pp);
     478                 :            :   }
     479                 :          0 : }
     480                 :            : 
     481                 :            : /* Implementation of svalue::remap_region_ids vfunc for region_svalue.  */
     482                 :            : 
     483                 :            : void
     484                 :      86864 : region_svalue::remap_region_ids (const region_id_map &map)
     485                 :            : {
     486                 :      86864 :   map.update (&m_rid);
     487                 :      86864 : }
     488                 :            : 
     489                 :            : /* Merge REGION_SVAL_A and REGION_SVAL_B using MERGER, writing the result
     490                 :            :    into *MERGED_SID.  */
     491                 :            : 
     492                 :            : void
     493                 :     176878 : region_svalue::merge_values (const region_svalue &region_sval_a,
     494                 :            :                              const region_svalue &region_sval_b,
     495                 :            :                              svalue_id *merged_sid,
     496                 :            :                              tree type,
     497                 :            :                              model_merger *merger)
     498                 :            : {
     499                 :     176878 :   region_id a_rid = region_sval_a.get_pointee ();
     500                 :     176878 :   region_id b_rid = region_sval_b.get_pointee ();
     501                 :            : 
     502                 :            :   /* Both are non-NULL. */
     503                 :     176878 :   gcc_assert (!a_rid.null_p () && !b_rid.null_p ());
     504                 :            : 
     505                 :            :   /* Have these ptr-values already been merged?  */
     506                 :            : 
     507                 :     176878 :   region_id a_rid_in_m
     508                 :     176878 :     = merger->m_map_regions_from_a_to_m.get_dst_for_src (a_rid);
     509                 :     176878 :   region_id b_rid_in_m
     510                 :     176878 :     = merger->m_map_regions_from_b_to_m.get_dst_for_src (b_rid);
     511                 :            : 
     512                 :            :   /* "null_p" here means "we haven't seen this ptr-value before".
     513                 :            :      If we've seen one but not the other, or we have different
     514                 :            :      regions, then the merged ptr has to be "unknown".  */
     515                 :     176878 :   if (a_rid_in_m != b_rid_in_m)
     516                 :            :     {
     517                 :         33 :       svalue *merged_sval = new unknown_svalue (type);
     518                 :         33 :       *merged_sid = merger->m_merged_model->add_svalue (merged_sval);
     519                 :         33 :       return;
     520                 :            :     }
     521                 :            : 
     522                 :            :   /* Have we seen this yet?  If so, reuse the value.  */
     523                 :     176845 :   if (!a_rid_in_m.null_p ())
     524                 :            :     {
     525                 :          0 :       *merged_sid
     526                 :          0 :         = merger->m_merged_model->get_or_create_ptr_svalue (type, a_rid_in_m);
     527                 :          0 :       return;
     528                 :            :     }
     529                 :            : 
     530                 :            :   /* Otherwise we have A/B regions that haven't been referenced yet.  */
     531                 :            : 
     532                 :            :   /* Are the regions the "same", when seen from the tree point-of-view.
     533                 :            :      If so, create a merged pointer to it.  */
     534                 :     176845 :   path_var pv_a = merger->m_model_a->get_representative_path_var (a_rid);
     535                 :     176845 :   path_var pv_b = merger->m_model_b->get_representative_path_var (b_rid);
     536                 :     176845 :   if (pv_a.m_tree
     537                 :     176845 :       && pv_a == pv_b)
     538                 :            :     {
     539                 :       1088 :       region_id merged_pointee_rid
     540                 :       1088 :         = merger->m_merged_model->get_lvalue (pv_a, NULL);
     541                 :       1088 :       *merged_sid
     542                 :       1088 :         = merger->m_merged_model->get_or_create_ptr_svalue (type,
     543                 :       1088 :                                                             merged_pointee_rid);
     544                 :       1088 :       merger->record_regions (a_rid, b_rid, merged_pointee_rid);
     545                 :       1088 :       return;
     546                 :            :     }
     547                 :            : 
     548                 :            :   /* Handle an A/B pair of ptrs that both point at heap regions.
     549                 :            :      If they both have a heap region in the merger model, merge them.  */
     550                 :     175757 :   region *region_a = merger->m_model_a->get_region (a_rid);
     551                 :     175757 :   region *region_b = merger->m_model_b->get_region (b_rid);
     552                 :     175757 :   region_id a_parent_rid = region_a->get_parent ();
     553                 :     175757 :   region_id b_parent_rid = region_b->get_parent ();
     554                 :     175757 :   region *parent_region_a = merger->m_model_a->get_region (a_parent_rid);
     555                 :     175757 :   region *parent_region_b = merger->m_model_b->get_region (b_parent_rid);
     556                 :     175757 :   if (parent_region_a
     557                 :     175757 :       && parent_region_b
     558                 :     175757 :       && parent_region_a->get_kind () == RK_HEAP
     559                 :     330201 :       && parent_region_b->get_kind () == RK_HEAP)
     560                 :            :     {
     561                 :            :         /* We have an A/B pair of ptrs that both point at heap regions.  */
     562                 :            :         /* presumably we want to see if each A/B heap region already
     563                 :            :            has a merged region, and, if so, is it the same one.  */
     564                 :            :         // This check is above
     565                 :            : 
     566                 :     153748 :         region_id merged_pointee_rid
     567                 :     153748 :           = merger->m_merged_model->add_new_malloc_region ();
     568                 :     153748 :         *merged_sid
     569                 :     153748 :           = merger->m_merged_model->get_or_create_ptr_svalue
     570                 :     153748 :              (type, merged_pointee_rid);
     571                 :     153748 :         merger->record_regions (a_rid, b_rid, merged_pointee_rid);
     572                 :     153748 :         return;
     573                 :            :     }
     574                 :            : 
     575                 :            :   /* Two different non-NULL pointers?  Merge to unknown.  */
     576                 :      22009 :   svalue *merged_sval = new unknown_svalue (type);
     577                 :      22009 :   *merged_sid = merger->m_merged_model->add_svalue (merged_sval);
     578                 :      22009 :   return;
     579                 :            : }
     580                 :            : 
     581                 :            : /* Implementation of svalue::walk_for_canonicalization vfunc for
     582                 :            :    region_svalue.  */
     583                 :            : 
     584                 :            : void
     585                 :      54732 : region_svalue::walk_for_canonicalization (canonicalization *c) const
     586                 :            : {
     587                 :      54732 :   c->walk_rid (m_rid);
     588                 :      54732 : }
     589                 :            : 
     590                 :            : /* Evaluate the condition LHS OP RHS.
     591                 :            :    Subroutine of region_model::eval_condition for when we have a pair of
     592                 :            :    pointers.  */
     593                 :            : 
     594                 :            : tristate
     595                 :       1199 : region_svalue::eval_condition (region_svalue *lhs,
     596                 :            :                                enum tree_code op,
     597                 :            :                                region_svalue *rhs)
     598                 :            : {
     599                 :            :   /* See if they point to the same region.  */
     600                 :            :   /* TODO: what about child regions where the child is the first child
     601                 :            :      (or descendent)?  */
     602                 :       1199 :   region_id lhs_rid = lhs->get_pointee ();
     603                 :       1199 :   region_id rhs_rid = rhs->get_pointee ();
     604                 :       1199 :   switch (op)
     605                 :            :     {
     606                 :          0 :     default:
     607                 :          0 :       gcc_unreachable ();
     608                 :            : 
     609                 :       1168 :     case EQ_EXPR:
     610                 :       1168 :       if (lhs_rid == rhs_rid)
     611                 :         98 :         return tristate::TS_TRUE;
     612                 :            :       else
     613                 :       1070 :         return tristate::TS_FALSE;
     614                 :          9 :       break;
     615                 :            : 
     616                 :          9 :     case NE_EXPR:
     617                 :          9 :       if (lhs_rid != rhs_rid)
     618                 :          4 :         return tristate::TS_TRUE;
     619                 :            :       else
     620                 :          5 :         return tristate::TS_FALSE;
     621                 :         11 :       break;
     622                 :            : 
     623                 :         11 :     case GE_EXPR:
     624                 :         11 :     case LE_EXPR:
     625                 :         11 :       if (lhs_rid == rhs_rid)
     626                 :          0 :         return tristate::TS_TRUE;
     627                 :            :       break;
     628                 :            : 
     629                 :         11 :     case GT_EXPR:
     630                 :         11 :     case LT_EXPR:
     631                 :         11 :       if (lhs_rid == rhs_rid)
     632                 :          0 :         return tristate::TS_FALSE;
     633                 :            :       break;
     634                 :            :     }
     635                 :            : 
     636                 :         22 :   return tristate::TS_UNKNOWN;
     637                 :            : }
     638                 :            : 
     639                 :            : /* class constant_svalue : public svalue.  */
     640                 :            : 
     641                 :            : /* Compare the fields of this constant_svalue with OTHER, returning true
     642                 :            :    if they are equal.
     643                 :            :    For use by svalue::operator==.  */
     644                 :            : 
     645                 :            : bool
     646                 :      78568 : constant_svalue::compare_fields (const constant_svalue &other) const
     647                 :            : {
     648                 :      78568 :   return m_cst_expr == other.m_cst_expr;
     649                 :            : }
     650                 :            : 
     651                 :            : /* Implementation of svalue::add_to_hash vfunc for constant_svalue.  */
     652                 :            : 
     653                 :            : void
     654                 :     226400 : constant_svalue::add_to_hash (inchash::hash &hstate) const
     655                 :            : {
     656                 :     226400 :   inchash::add_expr (m_cst_expr, hstate);
     657                 :     226400 : }
     658                 :            : 
     659                 :            : /* Merge the CST_SVAL_A and CST_SVAL_B using MERGER, writing the id of
     660                 :            :    the resulting svalue into *MERGED_SID.  */
     661                 :            : 
     662                 :            : void
     663                 :      12955 : constant_svalue::merge_values (const constant_svalue &cst_sval_a,
     664                 :            :                                const constant_svalue &cst_sval_b,
     665                 :            :                                svalue_id *merged_sid,
     666                 :            :                                model_merger *merger)
     667                 :            : {
     668                 :      12955 :   tree cst_a = cst_sval_a.get_constant ();
     669                 :      12955 :   tree cst_b = cst_sval_b.get_constant ();
     670                 :      12955 :   svalue *merged_sval;
     671                 :      12955 :   if (cst_a == cst_b)
     672                 :            :     {
     673                 :            :       /* If they are the same constant, merge as that constant value.  */
     674                 :      12056 :       merged_sval = new constant_svalue (cst_a);
     675                 :            :     }
     676                 :            :   else
     677                 :            :     {
     678                 :            :       /* Otherwise, we have two different constant values.
     679                 :            :          Merge as an unknown value.
     680                 :            :          TODO: impose constraints on the value?
     681                 :            :          (maybe just based on A, to avoid infinite chains)  */
     682                 :        899 :       merged_sval = new unknown_svalue (TREE_TYPE (cst_a));
     683                 :            :     }
     684                 :      12955 :   *merged_sid = merger->m_merged_model->add_svalue (merged_sval);
     685                 :      12955 : }
     686                 :            : 
     687                 :            : /* Evaluate the condition LHS OP RHS.
     688                 :            :    Subroutine of region_model::eval_condition for when we have a pair of
     689                 :            :    constants.  */
     690                 :            : 
     691                 :            : tristate
     692                 :        898 : constant_svalue::eval_condition (constant_svalue *lhs,
     693                 :            :                                  enum tree_code op,
     694                 :            :                                  constant_svalue *rhs)
     695                 :            : {
     696                 :        898 :   tree lhs_const = lhs->get_constant ();
     697                 :        898 :   tree rhs_const = rhs->get_constant ();
     698                 :            : 
     699                 :        898 :   gcc_assert (CONSTANT_CLASS_P (lhs_const));
     700                 :        898 :   gcc_assert (CONSTANT_CLASS_P (rhs_const));
     701                 :            : 
     702                 :            :   /* Check for comparable types.  */
     703                 :        898 :   if (types_compatible_p (TREE_TYPE (lhs_const), TREE_TYPE (rhs_const)))
     704                 :            :     {
     705                 :        622 :       tree comparison
     706                 :        622 :         = fold_binary (op, boolean_type_node, lhs_const, rhs_const);
     707                 :        622 :       if (comparison == boolean_true_node)
     708                 :        423 :         return tristate (tristate::TS_TRUE);
     709                 :        199 :       if (comparison == boolean_false_node)
     710                 :        199 :         return tristate (tristate::TS_FALSE);
     711                 :            :     }
     712                 :        276 :   return tristate::TS_UNKNOWN;
     713                 :            : }
     714                 :            : 
     715                 :            : /* Implementation of svalue::print_details vfunc for constant_svalue.  */
     716                 :            : 
     717                 :            : void
     718                 :         20 : constant_svalue::print_details (const region_model &model ATTRIBUTE_UNUSED,
     719                 :            :                                 svalue_id this_sid ATTRIBUTE_UNUSED,
     720                 :            :                                 pretty_printer *pp) const
     721                 :            : {
     722                 :         20 :   pp_printf (pp, "%qE", m_cst_expr);
     723                 :         20 : }
     724                 :            : 
     725                 :            : /* Implementation of svalue::get_child_sid vfunc for constant_svalue.  */
     726                 :            : 
     727                 :            : svalue_id
     728                 :         85 : constant_svalue::get_child_sid (region *parent ATTRIBUTE_UNUSED,
     729                 :            :                                 region *child,
     730                 :            :                                 region_model &model,
     731                 :            :                                 region_model_context *ctxt ATTRIBUTE_UNUSED)
     732                 :            : {
     733                 :            :   /* TODO: handle the all-zeroes case by returning an all-zeroes of the
     734                 :            :      child type.  */
     735                 :            : 
     736                 :            :   /* Otherwise, we don't have a good way to get a child value out of a
     737                 :            :      constant.
     738                 :            : 
     739                 :            :      Handle this case by using an unknown value.  */
     740                 :         85 :   svalue *unknown_sval = new unknown_svalue (child->get_type ());
     741                 :         85 :   return model.add_svalue (unknown_sval);
     742                 :            : }
     743                 :            : 
     744                 :            : /* class unknown_svalue : public svalue.  */
     745                 :            : 
     746                 :            : /* Compare the fields of this unknown_svalue with OTHER, returning true
     747                 :            :    if they are equal.
     748                 :            :    For use by svalue::operator==.  */
     749                 :            : 
     750                 :            : bool
     751                 :     101506 : unknown_svalue::compare_fields (const unknown_svalue &) const
     752                 :            : {
     753                 :            :   /* I *think* we want to return true here, in that when comparing
     754                 :            :      two region models, we want two peer unknown_svalue instances
     755                 :            :      to be the "same".  */
     756                 :     101506 :   return true;
     757                 :            : }
     758                 :            : 
     759                 :            : /* Implementation of svalue::add_to_hash vfunc for unknown_svalue.  */
     760                 :            : 
     761                 :            : void
     762                 :     319201 : unknown_svalue::add_to_hash (inchash::hash &) const
     763                 :            : {
     764                 :            :   /* Empty.  */
     765                 :     319201 : }
     766                 :            : 
     767                 :            : /* Implementation of svalue::print_details vfunc for unknown_svalue.  */
     768                 :            : 
     769                 :            : void
     770                 :          0 : unknown_svalue::print_details (const region_model &model ATTRIBUTE_UNUSED,
     771                 :            :                                svalue_id this_sid ATTRIBUTE_UNUSED,
     772                 :            :                                pretty_printer *pp) const
     773                 :            : {
     774                 :          0 :   pp_string (pp, "unknown");
     775                 :          0 : }
     776                 :            : 
     777                 :            : /* Get a string for KIND for use in debug dumps.  */
     778                 :            : 
     779                 :            : const char *
     780                 :         12 : poison_kind_to_str (enum poison_kind kind)
     781                 :            : {
     782                 :         12 :   switch (kind)
     783                 :            :     {
     784                 :          0 :     default:
     785                 :          0 :       gcc_unreachable ();
     786                 :            :     case POISON_KIND_UNINIT:
     787                 :            :       return "uninit";
     788                 :          0 :     case POISON_KIND_FREED:
     789                 :          0 :       return "freed";
     790                 :          0 :     case POISON_KIND_POPPED_STACK:
     791                 :          0 :       return "popped stack";
     792                 :            :     }
     793                 :            : }
     794                 :            : 
     795                 :            : /* class poisoned_svalue : public svalue.  */
     796                 :            : 
     797                 :            : /* Compare the fields of this poisoned_svalue with OTHER, returning true
     798                 :            :    if they are equal.
     799                 :            :    For use by svalue::operator==.  */
     800                 :            : 
     801                 :            : bool
     802                 :      59540 : poisoned_svalue::compare_fields (const poisoned_svalue &other) const
     803                 :            : {
     804                 :      59540 :   return m_kind == other.m_kind;
     805                 :            : }
     806                 :            : 
     807                 :            : /* Implementation of svalue::add_to_hash vfunc for poisoned_svalue.  */
     808                 :            : 
     809                 :            : void
     810                 :     173036 : poisoned_svalue::add_to_hash (inchash::hash &hstate) const
     811                 :            : {
     812                 :     173036 :   hstate.add_int (m_kind);
     813                 :     173036 : }
     814                 :            : 
     815                 :            : /* Implementation of svalue::print_details vfunc for poisoned_svalue.  */
     816                 :            : 
     817                 :            : void
     818                 :         12 : poisoned_svalue::print_details (const region_model &model ATTRIBUTE_UNUSED,
     819                 :            :                                 svalue_id this_sid ATTRIBUTE_UNUSED,
     820                 :            :                                 pretty_printer *pp) const
     821                 :            : {
     822                 :         12 :   pp_printf (pp, "poisoned: %s", poison_kind_to_str (m_kind));
     823                 :         12 : }
     824                 :            : 
     825                 :            : /* class setjmp_svalue's implementation is in engine.cc, so that it can use
     826                 :            :    the declaration of exploded_node.  */
     827                 :            : 
     828                 :            : /* class region and its various subclasses.  */
     829                 :            : 
     830                 :            : /* Get a string for KIND for use in debug dumps.  */
     831                 :            : 
     832                 :            : const char *
     833                 :         46 : region_kind_to_str (enum region_kind kind)
     834                 :            : {
     835                 :         46 :   switch (kind)
     836                 :            :     {
     837                 :          0 :     default:
     838                 :          0 :       gcc_unreachable ();
     839                 :            :     case RK_PRIMITIVE:
     840                 :            :       return "primitive";
     841                 :          2 :     case RK_STRUCT:
     842                 :          2 :       return "struct";
     843                 :          0 :     case RK_UNION:
     844                 :          0 :       return "union";
     845                 :          4 :     case RK_ARRAY:
     846                 :          4 :       return "array";
     847                 :          0 :     case RK_FRAME:
     848                 :          0 :       return "frame";
     849                 :         10 :     case RK_GLOBALS:
     850                 :         10 :       return "globals";
     851                 :          0 :     case RK_CODE:
     852                 :          0 :       return "code";
     853                 :          0 :     case RK_FUNCTION:
     854                 :          0 :       return "function";
     855                 :          2 :     case RK_STACK:
     856                 :          2 :       return "stack";
     857                 :          4 :     case RK_HEAP:
     858                 :          4 :       return "heap";
     859                 :         10 :     case RK_ROOT:
     860                 :         10 :       return "root";
     861                 :          2 :     case RK_SYMBOLIC:
     862                 :          2 :       return "symbolic";
     863                 :            :     }
     864                 :            : }
     865                 :            : 
     866                 :            : /* class region.  */
     867                 :            : 
     868                 :            : /* Equality operator for region.
     869                 :            :    After comparing base class fields and kind, the rest of the
     870                 :            :    comparison is handled off to a "compare_fields" member function
     871                 :            :    specific to the appropriate subclass.  */
     872                 :            : 
     873                 :            : bool
     874                 :     440693 : region::operator== (const region &other) const
     875                 :            : {
     876                 :     440693 :   if (m_parent_rid != other.m_parent_rid)
     877                 :            :     return false;
     878                 :     440691 :   if (m_sval_id != other.m_sval_id)
     879                 :            :     return false;
     880                 :     440689 :   if (m_type != other.m_type)
     881                 :            :     return false;
     882                 :            : 
     883                 :     440689 :   enum region_kind this_kind = get_kind ();
     884                 :     440689 :   enum region_kind other_kind = other.get_kind ();
     885                 :     440689 :   if (this_kind != other_kind)
     886                 :            :     return false;
     887                 :            : 
     888                 :            :   /* Compare views.  */
     889                 :     480943 :   if (m_view_rids.length () != other.m_view_rids.length ())
     890                 :            :     return false;
     891                 :            :   int i;
     892                 :            :   region_id *rid;
     893                 :     464670 :   FOR_EACH_VEC_ELT (m_view_rids, i, rid)
     894                 :      23981 :     if (! (*rid == other.m_view_rids[i]))
     895                 :            :       return false;
     896                 :            : 
     897                 :     440689 :   switch (this_kind)
     898                 :            :     {
     899                 :          0 :     default:
     900                 :          0 :       gcc_unreachable ();
     901                 :            :     case RK_PRIMITIVE:
     902                 :            :       {
     903                 :            : #if 1
     904                 :            :         return true;
     905                 :            : #else
     906                 :            :         const primitive_region &this_sub
     907                 :            :           = (const primitive_region &)*this;
     908                 :            :         const primitive_region &other_sub
     909                 :            :           = (const primitive_region &)other;
     910                 :            :         return this_sub.compare_fields (other_sub);
     911                 :            : #endif
     912                 :            :       }
     913                 :      16707 :     case RK_STRUCT:
     914                 :      16707 :       {
     915                 :      16707 :         const struct_region &this_sub
     916                 :            :           = (const struct_region &)*this;
     917                 :      16707 :         const struct_region &other_sub
     918                 :            :           = (const struct_region &)other;
     919                 :      16707 :         return this_sub.compare_fields (other_sub);
     920                 :            :       }
     921                 :         74 :     case RK_UNION:
     922                 :         74 :       {
     923                 :         74 :         const union_region &this_sub
     924                 :            :           = (const union_region &)*this;
     925                 :         74 :         const union_region &other_sub
     926                 :            :           = (const union_region &)other;
     927                 :         74 :         return this_sub.compare_fields (other_sub);
     928                 :            :       }
     929                 :      30028 :     case RK_ARRAY:
     930                 :      30028 :       {
     931                 :      30028 :         const array_region &this_sub
     932                 :            :           = (const array_region &)*this;
     933                 :      30028 :         const array_region &other_sub
     934                 :            :           = (const array_region &)other;
     935                 :      30028 :         return this_sub.compare_fields (other_sub);
     936                 :            :       }
     937                 :      42003 :     case RK_FRAME:
     938                 :      42003 :       {
     939                 :      42003 :         const frame_region &this_sub
     940                 :            :           = (const frame_region &)*this;
     941                 :      42003 :         const frame_region &other_sub
     942                 :            :           = (const frame_region &)other;
     943                 :      42003 :         return this_sub.compare_fields (other_sub);
     944                 :            :       }
     945                 :       4674 :     case RK_GLOBALS:
     946                 :       4674 :       {
     947                 :       4674 :         const globals_region &this_sub
     948                 :            :           = (const globals_region &)*this;
     949                 :       4674 :         const globals_region &other_sub
     950                 :            :           = (const globals_region &)other;
     951                 :       4674 :         return this_sub.compare_fields (other_sub);
     952                 :            :       }
     953                 :      20419 :     case RK_CODE:
     954                 :      20419 :       {
     955                 :      20419 :         const code_region &this_sub
     956                 :            :           = (const code_region &)*this;
     957                 :      20419 :         const code_region &other_sub
     958                 :            :           = (const code_region &)other;
     959                 :      20419 :         return this_sub.compare_fields (other_sub);
     960                 :            :       }
     961                 :      51809 :     case RK_FUNCTION:
     962                 :      51809 :       {
     963                 :      51809 :         const function_region &this_sub
     964                 :            :           = (const function_region &)*this;
     965                 :      51809 :         const function_region &other_sub
     966                 :            :           = (const function_region &)other;
     967                 :      51809 :         return this_sub.compare_fields (other_sub);
     968                 :            :       }
     969                 :      31398 :     case RK_STACK:
     970                 :      31398 :       {
     971                 :      31398 :         const stack_region &this_sub
     972                 :            :           = (const stack_region &)*this;
     973                 :      31398 :         const stack_region &other_sub
     974                 :            :           = (const stack_region &)other;
     975                 :      31398 :         return this_sub.compare_fields (other_sub);
     976                 :            :       }
     977                 :      31894 :     case RK_ROOT:
     978                 :      31894 :       {
     979                 :      31894 :         const root_region &this_sub
     980                 :            :           = (const root_region &)*this;
     981                 :      31894 :         const root_region &other_sub
     982                 :            :           = (const root_region &)other;
     983                 :      31894 :         return this_sub.compare_fields (other_sub);
     984                 :            :       }
     985                 :      24312 :     case RK_SYMBOLIC:
     986                 :      24312 :       {
     987                 :      24312 :         const symbolic_region &this_sub
     988                 :            :           = (const symbolic_region &)*this;
     989                 :      24312 :         const symbolic_region &other_sub
     990                 :            :           = (const symbolic_region &)other;
     991                 :      24312 :         return this_sub.compare_fields (other_sub);
     992                 :            :       }
     993                 :       7108 :     case RK_HEAP:
     994                 :       7108 :       {
     995                 :       7108 :         const heap_region &this_sub
     996                 :            :           = (const heap_region &)*this;
     997                 :       7108 :         const heap_region &other_sub
     998                 :            :           = (const heap_region &)other;
     999                 :       7108 :         return this_sub.compare_fields (other_sub);
    1000                 :            :       }
    1001                 :            :     }
    1002                 :            : }
    1003                 :            : 
    1004                 :            : /* Get the parent region of this region.  */
    1005                 :            : 
    1006                 :            : region *
    1007                 :          0 : region::get_parent_region (const region_model &model) const
    1008                 :            : {
    1009                 :          0 :   return model.get_region (m_parent_rid);
    1010                 :            : }
    1011                 :            : 
    1012                 :            : /* Set this region's value to RHS_SID (or potentially a variant of it,
    1013                 :            :    for some kinds of casts).  */
    1014                 :            : 
    1015                 :            : void
    1016                 :     826334 : region::set_value (region_model &model, region_id this_rid, svalue_id rhs_sid,
    1017                 :            :                    region_model_context *ctxt)
    1018                 :            : {
    1019                 :            :   /* Handle some kinds of casting.  */
    1020                 :     826334 :   if (m_type)
    1021                 :            :     {
    1022                 :     825971 :       svalue *sval = model.get_svalue (rhs_sid);
    1023                 :     825971 :       if (sval->get_type ())
    1024                 :     825971 :         rhs_sid = model.maybe_cast (m_type, rhs_sid, ctxt);
    1025                 :            : 
    1026                 :     825971 :       sval = model.get_svalue (rhs_sid);
    1027                 :     825971 :       if (sval->get_type ())
    1028                 :     825971 :         gcc_assert (m_type == sval->get_type ());
    1029                 :            :     }
    1030                 :            : 
    1031                 :     826334 :   m_sval_id = rhs_sid;
    1032                 :            : 
    1033                 :            :   /* Update views.
    1034                 :            :      If this is a view, it becomes its parent's active view.
    1035                 :            :      If there was already an active views, invalidate its value; otherwise
    1036                 :            :      if the parent itself had a value, invalidate it.
    1037                 :            :      If it's not a view, then deactivate any view that is active on this
    1038                 :            :      region.  */
    1039                 :     826334 :   {
    1040                 :     826334 :     if (m_is_view)
    1041                 :        526 :       become_active_view (model, this_rid);
    1042                 :            :     else
    1043                 :            :       {
    1044                 :     825808 :         deactivate_any_active_view (model);
    1045                 :     825808 :         gcc_assert (m_active_view_rid.null_p ());
    1046                 :            :       }
    1047                 :            :   }
    1048                 :     826334 : }
    1049                 :            : 
    1050                 :            : /* Make this region (with id THIS_RID) the "active" view of its parent.
    1051                 :            :    Any other active view has its value set to "unknown" and descendent values
    1052                 :            :    cleared.
    1053                 :            :    If there wasn't an active view, then set the parent's value to unknown, and
    1054                 :            :    clear its descendent values (apart from this view).  */
    1055                 :            : 
    1056                 :            : void
    1057                 :        526 : region::become_active_view (region_model &model, region_id this_rid)
    1058                 :            : {
    1059                 :        526 :   gcc_assert (m_is_view);
    1060                 :            : 
    1061                 :        526 :   region *parent_reg = model.get_region (m_parent_rid);
    1062                 :        526 :   gcc_assert (parent_reg);
    1063                 :            : 
    1064                 :        526 :   region_id old_active_view_rid = parent_reg->m_active_view_rid;
    1065                 :            : 
    1066                 :        526 :   if (old_active_view_rid == this_rid)
    1067                 :            :     {
    1068                 :            :       /* Already the active view: do nothing.  */
    1069                 :        526 :       return;
    1070                 :            :     }
    1071                 :            : 
    1072                 :            :   /* We have a change of active view.  */
    1073                 :        451 :   parent_reg->m_active_view_rid = this_rid;
    1074                 :            : 
    1075                 :        451 :   if (old_active_view_rid.null_p ())
    1076                 :            :     {
    1077                 :            :       /* No previous active view, but the parent and its other children
    1078                 :            :          might have values.
    1079                 :            :          If so, invalidate those values - but not that of the new view.  */
    1080                 :        858 :       region_id_set below_region (&model);
    1081                 :        429 :       model.get_descendents (m_parent_rid, &below_region, this_rid);
    1082                 :      24552 :       for (unsigned i = 0; i < model.get_num_regions (); i++)
    1083                 :            :         {
    1084                 :      11847 :           region_id rid (region_id::from_int (i));
    1085                 :      11847 :           if (below_region.region_p (rid))
    1086                 :            :             {
    1087                 :        642 :               region *other_reg = model.get_region (rid);
    1088                 :        642 :               other_reg->m_sval_id = svalue_id::null ();
    1089                 :            :             }
    1090                 :            :         }
    1091                 :        429 :       region *parent = model.get_region (m_parent_rid);
    1092                 :        429 :       parent->m_sval_id
    1093                 :        429 :         = model.add_svalue (new unknown_svalue (parent->get_type ()));
    1094                 :            :     }
    1095                 :            :   else
    1096                 :            :     {
    1097                 :            :       /* If there was an active view, invalidate it.  */
    1098                 :         22 :       region *old_active_view = model.get_region (old_active_view_rid);
    1099                 :         22 :       old_active_view->deactivate_view (model, old_active_view_rid);
    1100                 :            :     }
    1101                 :            : }
    1102                 :            : 
    1103                 :            : /* If this region (with id THIS_RID) has an active view, deactivate it,
    1104                 :            :    clearing m_active_view_rid.  */
    1105                 :            : 
    1106                 :            : void
    1107                 :     825808 : region::deactivate_any_active_view (region_model &model)
    1108                 :            : {
    1109                 :     825808 :   if (m_active_view_rid.null_p ())
    1110                 :            :     return;
    1111                 :         45 :   region *view = model.get_region (m_active_view_rid);
    1112                 :         45 :   view->deactivate_view (model, m_active_view_rid);
    1113                 :         45 :   m_active_view_rid = region_id::null ();
    1114                 :            : }
    1115                 :            : 
    1116                 :            : /* Clear any values for regions below THIS_RID.
    1117                 :            :    Set the view's value to unknown.  */
    1118                 :            : 
    1119                 :            : void
    1120                 :         67 : region::deactivate_view (region_model &model, region_id this_view_rid)
    1121                 :            : {
    1122                 :         67 :   gcc_assert (is_view_p ());
    1123                 :            : 
    1124                 :            :   /* Purge values from old_active_this_view_rid and all its
    1125                 :            :      descendents.  Potentially we could use a poison value
    1126                 :            :      for this, but let's use unknown for now.  */
    1127                 :         67 :   region_id_set below_view (&model);
    1128                 :         67 :   model.get_descendents (this_view_rid, &below_view, region_id::null ());
    1129                 :            : 
    1130                 :       5030 :   for (unsigned i = 0; i < model.get_num_regions (); i++)
    1131                 :            :     {
    1132                 :       2448 :       region_id rid (region_id::from_int (i));
    1133                 :       2448 :       if (below_view.region_p (rid))
    1134                 :            :         {
    1135                 :        121 :           region *other_reg = model.get_region (rid);
    1136                 :        121 :           other_reg->m_sval_id = svalue_id::null ();
    1137                 :            :         }
    1138                 :            :     }
    1139                 :            : 
    1140                 :         67 :   m_sval_id = model.add_svalue (new unknown_svalue (get_type ()));
    1141                 :         67 : }
    1142                 :            : 
    1143                 :            : /* Get a value for this region, either its value if it has one,
    1144                 :            :    or, failing that, "inherit" a value from first ancestor with a
    1145                 :            :    non-null value.
    1146                 :            : 
    1147                 :            :    For example, when getting the value for a local variable within
    1148                 :            :    a stack frame that doesn't have one, the frame doesn't have a value
    1149                 :            :    either, but the stack as a whole will have an "uninitialized" poison
    1150                 :            :    value, so inherit that.  */
    1151                 :            : 
    1152                 :            : svalue_id
    1153                 :      64790 : region::get_value (region_model &model, bool non_null,
    1154                 :            :                    region_model_context *ctxt)
    1155                 :            : {
    1156                 :            :   /* If this region has a value, use it. */
    1157                 :      64790 :   if (!m_sval_id.null_p ())
    1158                 :      60337 :     return m_sval_id;
    1159                 :            : 
    1160                 :            :   /* Otherwise, "inherit" value from first ancestor with a
    1161                 :            :      non-null value. */
    1162                 :            : 
    1163                 :       4453 :   region *parent = model.get_region (m_parent_rid);
    1164                 :       4453 :   if (parent)
    1165                 :            :     {
    1166                 :       4453 :       svalue_id inherited_sid
    1167                 :       4453 :         = parent->get_inherited_child_sid (this, model, ctxt);
    1168                 :       4453 :       if (!inherited_sid.null_p ())
    1169                 :       3567 :         return inherited_sid;
    1170                 :            :     }
    1171                 :            : 
    1172                 :            :   /* If a non-null value has been requested, then generate
    1173                 :            :      a new unknown value.  Store it, so that repeated reads from this
    1174                 :            :      region will yield the same unknown value.  */
    1175                 :        886 :   if (non_null)
    1176                 :            :     {
    1177                 :        882 :       svalue_id unknown_sid = model.add_svalue (new unknown_svalue (m_type));
    1178                 :        882 :       m_sval_id = unknown_sid;
    1179                 :        882 :       return unknown_sid;
    1180                 :            :     }
    1181                 :            : 
    1182                 :          4 :   return svalue_id::null ();
    1183                 :            : }
    1184                 :            : 
    1185                 :            : /* Get a value for CHILD, inheriting from this region.
    1186                 :            : 
    1187                 :            :    Recurse, so this region will inherit a value if it doesn't already
    1188                 :            :    have one.  */
    1189                 :            : 
    1190                 :            : svalue_id
    1191                 :       7647 : region::get_inherited_child_sid (region *child,
    1192                 :            :                                  region_model &model,
    1193                 :            :                                  region_model_context *ctxt)
    1194                 :            : {
    1195                 :       7647 :   if (m_sval_id.null_p ())
    1196                 :            :     {
    1197                 :            :       /* Recurse.  */
    1198                 :       4080 :       if (!m_parent_rid.null_p ())
    1199                 :            :         {
    1200                 :       3194 :           region *parent = model.get_region (m_parent_rid);
    1201                 :       3194 :           m_sval_id = parent->get_inherited_child_sid (this, model, ctxt);
    1202                 :            :         }
    1203                 :            :     }
    1204                 :            : 
    1205                 :       7647 :   if (!m_sval_id.null_p ())
    1206                 :            :     {
    1207                 :            :       /* Clone the parent's value, so that attempts to update it
    1208                 :            :          (e.g giving a specific value to an inherited "uninitialized"
    1209                 :            :          value) touch the child, and not the parent.  */
    1210                 :       5546 :       svalue *this_value = model.get_svalue (m_sval_id);
    1211                 :       5546 :       svalue_id new_child_sid
    1212                 :       5546 :         = this_value->get_child_sid (this, child, model, ctxt);
    1213                 :       5546 :       if (ctxt)
    1214                 :       4127 :         ctxt->on_inherited_svalue (m_sval_id, new_child_sid);
    1215                 :       5546 :       child->m_sval_id = new_child_sid;
    1216                 :       5546 :       return new_child_sid;
    1217                 :            :     }
    1218                 :            : 
    1219                 :       2101 :   return svalue_id::null ();
    1220                 :            : }
    1221                 :            : 
    1222                 :            : /* Generate a hash value for this region.  The work is done by the
    1223                 :            :    add_to_hash vfunc.  */
    1224                 :            : 
    1225                 :            : hashval_t
    1226                 :    1402550 : region::hash () const
    1227                 :            : {
    1228                 :    1402550 :   inchash::hash hstate;
    1229                 :    1402550 :   add_to_hash (hstate);
    1230                 :    1402550 :   return hstate.end ();
    1231                 :            : }
    1232                 :            : 
    1233                 :            : /* Print a one-liner representation of this region to PP, assuming
    1234                 :            :    that this region is within MODEL and its id is THIS_RID.  */
    1235                 :            : 
    1236                 :            : void
    1237                 :         46 : region::print (const region_model &model,
    1238                 :            :                region_id this_rid,
    1239                 :            :                pretty_printer *pp) const
    1240                 :            : {
    1241                 :         46 :   this_rid.print (pp);
    1242                 :         46 :   pp_string (pp, ": {");
    1243                 :            : 
    1244                 :            :   /* vfunc.  */
    1245                 :         46 :   print_fields (model, this_rid, pp);
    1246                 :            : 
    1247                 :         46 :   pp_string (pp, "}");
    1248                 :         46 : }
    1249                 :            : 
    1250                 :            : /* Base class implementation of region::dump_dot_to_pp vfunc.  */
    1251                 :            : 
    1252                 :            : void
    1253                 :          0 : region::dump_dot_to_pp (const region_model &model,
    1254                 :            :                         region_id this_rid,
    1255                 :            :                         pretty_printer *pp) const
    1256                 :            : {
    1257                 :          0 :   this_rid.dump_node_name_to_pp (pp);
    1258                 :          0 :   pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=\"",
    1259                 :            :              "lightgrey");
    1260                 :          0 :   pp_write_text_to_stream (pp);
    1261                 :          0 :   print (model, this_rid, pp);
    1262                 :          0 :   pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
    1263                 :          0 :   pp_string (pp, "\"];");
    1264                 :          0 :   pp_newline (pp);
    1265                 :            : 
    1266                 :            :   /* Add edge to svalue.  */
    1267                 :          0 :   if (!m_sval_id.null_p ())
    1268                 :            :     {
    1269                 :          0 :       this_rid.dump_node_name_to_pp (pp);
    1270                 :          0 :       pp_string (pp, " -> ");
    1271                 :          0 :       m_sval_id.dump_node_name_to_pp (pp);
    1272                 :          0 :       pp_string (pp, ";");
    1273                 :          0 :       pp_newline (pp);
    1274                 :            :     }
    1275                 :            : 
    1276                 :            :   /* Add edge to parent.  */
    1277                 :          0 :   if (!m_parent_rid.null_p ())
    1278                 :            :     {
    1279                 :          0 :       this_rid.dump_node_name_to_pp (pp);
    1280                 :          0 :       pp_string (pp, " -> ");
    1281                 :          0 :       m_parent_rid.dump_node_name_to_pp (pp);
    1282                 :          0 :       pp_string (pp, ";");
    1283                 :          0 :       pp_newline (pp);
    1284                 :            :     }
    1285                 :          0 : }
    1286                 :            : 
    1287                 :            : /* Dump a tree-like ASCII-art representation of this region to PP.  */
    1288                 :            : 
    1289                 :            : void
    1290                 :         46 : region::dump_to_pp (const region_model &model,
    1291                 :            :                     region_id this_rid,
    1292                 :            :                     pretty_printer *pp,
    1293                 :            :                     const char *prefix,
    1294                 :            :                     bool is_last_child) const
    1295                 :            : {
    1296                 :         46 :   print (model, this_rid, pp);
    1297                 :         46 :   pp_newline (pp);
    1298                 :            : 
    1299                 :         46 :   const char *new_prefix;
    1300                 :         46 :   if (!m_parent_rid.null_p ())
    1301                 :         46 :     new_prefix = ACONCAT ((prefix, is_last_child ? "  " : "|  ", NULL));
    1302                 :            :   else
    1303                 :            :     new_prefix = prefix;
    1304                 :            : 
    1305                 :         46 :   const char *begin_color = colorize_start (pp_show_color (pp), "note");
    1306                 :         46 :   const char *end_color = colorize_stop (pp_show_color (pp));
    1307                 :         46 :   char *field_prefix
    1308                 :         46 :     = ACONCAT ((begin_color, new_prefix, "|:", end_color, NULL));
    1309                 :            : 
    1310                 :         46 :   if (!m_sval_id.null_p ())
    1311                 :            :     {
    1312                 :         18 :       pp_printf (pp, "%s sval: ", field_prefix);
    1313                 :         18 :       model.get_svalue (m_sval_id)->print (model, m_sval_id, pp);
    1314                 :         18 :       pp_newline (pp);
    1315                 :            :     }
    1316                 :         46 :   if (m_type)
    1317                 :            :     {
    1318                 :         18 :       pp_printf (pp, "%s type: ", field_prefix);
    1319                 :         18 :       print_quoted_type (pp, m_type);
    1320                 :         18 :       pp_newline (pp);
    1321                 :            :     }
    1322                 :            : 
    1323                 :            :   /* Find the children.  */
    1324                 :            : 
    1325                 :         46 :   auto_vec<region_id> child_rids;
    1326                 :         46 :   unsigned i;
    1327                 :        520 :   for (unsigned i = 0; i < model.get_num_regions (); ++i)
    1328                 :            :     {
    1329                 :        214 :       region_id rid = region_id::from_int (i);
    1330                 :        214 :       region *child = model.get_region (rid);
    1331                 :        214 :       if (child->m_parent_rid == this_rid)
    1332                 :         36 :         child_rids.safe_push (rid);
    1333                 :            :     }
    1334                 :            : 
    1335                 :            :   /* Print the children, using dump_child_label to label them.  */
    1336                 :            : 
    1337                 :            :   region_id *child_rid;
    1338                 :        108 :   FOR_EACH_VEC_ELT (child_rids, i, child_rid)
    1339                 :            :     {
    1340                 :         36 :       is_last_child = (i == child_rids.length () - 1);
    1341                 :         36 :       if (!this_rid.null_p ())
    1342                 :            :         {
    1343                 :         36 :           const char *tail = is_last_child ? "`-" : "|-";
    1344                 :         36 :           pp_printf (pp, "%r%s%s%R", "note", new_prefix, tail);
    1345                 :            :         }
    1346                 :         36 :       dump_child_label (model, this_rid, *child_rid, pp);
    1347                 :         36 :       model.get_region (*child_rid)->dump_to_pp (model, *child_rid, pp,
    1348                 :            :                                                  new_prefix,
    1349                 :            :                                                  is_last_child);
    1350                 :            :     }
    1351                 :         46 : }
    1352                 :            : 
    1353                 :            : /* Base implementation of region::dump_child_label vfunc.  */
    1354                 :            : 
    1355                 :            : void
    1356                 :         18 : region::dump_child_label (const region_model &model,
    1357                 :            :                           region_id this_rid ATTRIBUTE_UNUSED,
    1358                 :            :                           region_id child_rid,
    1359                 :            :                           pretty_printer *pp) const
    1360                 :            : {
    1361                 :         18 :   region *child = model.get_region (child_rid);
    1362                 :         18 :   if (child->m_is_view)
    1363                 :            :     {
    1364                 :          0 :       gcc_assert (TYPE_P (child->get_type ()));
    1365                 :          0 :       if (m_active_view_rid == child_rid)
    1366                 :          0 :         pp_string (pp, "active ");
    1367                 :            :       else
    1368                 :          0 :         pp_string (pp, "inactive ");
    1369                 :          0 :       pp_string (pp, "view as ");
    1370                 :          0 :       print_quoted_type (pp, child->get_type ());
    1371                 :          0 :       pp_string (pp, ": ");
    1372                 :            :     }
    1373                 :         18 : }
    1374                 :            : 
    1375                 :            : /* Base implementation of region::validate vfunc.
    1376                 :            :    Assert that the fields of "region" are valid; subclasses should
    1377                 :            :    chain up their implementation to this one.  */
    1378                 :            : 
    1379                 :            : void
    1380                 :    5166160 : region::validate (const region_model &model) const
    1381                 :            : {
    1382                 :    5166160 :   m_parent_rid.validate (model);
    1383                 :    5166160 :   m_sval_id.validate (model);
    1384                 :    5166160 :   unsigned i;
    1385                 :    5166160 :   region_id *view_rid;
    1386                 :    5346360 :   FOR_EACH_VEC_ELT (m_view_rids, i, view_rid)
    1387                 :            :     {
    1388                 :     180199 :       gcc_assert (!view_rid->null_p ());
    1389                 :     180199 :       view_rid->validate (model);
    1390                 :            :     }
    1391                 :    5166160 :   m_active_view_rid.validate (model);
    1392                 :    5166160 : }
    1393                 :            : 
    1394                 :            : /* Apply MAP to svalue_ids to this region.  This updates the value
    1395                 :            :    for the region (if any).  */
    1396                 :            : 
    1397                 :            : void
    1398                 :    1363620 : region::remap_svalue_ids (const svalue_id_map &map)
    1399                 :            : {
    1400                 :    1363620 :   map.update (&m_sval_id);
    1401                 :    1363620 : }
    1402                 :            : 
    1403                 :            : /* Base implementation of region::remap_region_ids vfunc; subclasses should
    1404                 :            :    chain up to this, updating any region_id data.  */
    1405                 :            : 
    1406                 :            : void
    1407                 :    1294510 : region::remap_region_ids (const region_id_map &map)
    1408                 :            : {
    1409                 :    1294510 :   map.update (&m_parent_rid);
    1410                 :    1294510 :   unsigned i;
    1411                 :    1294510 :   region_id *view_rid;
    1412                 :    1371170 :   FOR_EACH_VEC_ELT (m_view_rids, i, view_rid)
    1413                 :      76657 :     map.update (view_rid);
    1414                 :    1294510 :   map.update (&m_active_view_rid);
    1415                 :    1294510 : }
    1416                 :            : 
    1417                 :            : /* Add a new region with id VIEW_RID as a view of this region.  */
    1418                 :            : 
    1419                 :            : void
    1420                 :       1277 : region::add_view (region_id view_rid, region_model *model)
    1421                 :            : {
    1422                 :       1277 :   gcc_assert (!view_rid.null_p ());
    1423                 :       1277 :   region *new_view = model->get_region (view_rid);
    1424                 :       1277 :   new_view->m_is_view = true;
    1425                 :       1277 :   gcc_assert (!new_view->m_parent_rid.null_p ());
    1426                 :       1277 :   gcc_assert (new_view->m_sval_id.null_p ());
    1427                 :            : 
    1428                 :            :   //gcc_assert (new_view->get_type () != NULL_TREE);
    1429                 :            :   // TODO: this can sometimes be NULL, when viewing through a (void *)
    1430                 :            : 
    1431                 :            :   // TODO: the type ought to not be present yet
    1432                 :            : 
    1433                 :       1277 :   m_view_rids.safe_push (view_rid);
    1434                 :       1277 : }
    1435                 :            : 
    1436                 :            : /* Look for a view of type TYPE of this region, returning its id if found,
    1437                 :            :    or null otherwise.  */
    1438                 :            : 
    1439                 :            : region_id
    1440                 :       2287 : region::get_view (tree type, region_model *model) const
    1441                 :            : {
    1442                 :       2287 :   unsigned i;
    1443                 :       2287 :   region_id *view_rid;
    1444                 :       2661 :   FOR_EACH_VEC_ELT (m_view_rids, i, view_rid)
    1445                 :            :     {
    1446                 :       1384 :       region *view = model->get_region (*view_rid);
    1447                 :       1384 :       gcc_assert (view->m_is_view);
    1448                 :       1384 :       if (view->get_type () == type)
    1449                 :       1010 :         return *view_rid;
    1450                 :            :     }
    1451                 :       1277 :   return region_id::null ();
    1452                 :            : }
    1453                 :            : 
    1454                 :            : /* region's ctor.  */
    1455                 :            : 
    1456                 :    2208960 : region::region (region_id parent_rid, svalue_id sval_id, tree type)
    1457                 :            : : m_parent_rid (parent_rid), m_sval_id (sval_id), m_type (type),
    1458                 :    2208960 :   m_view_rids (), m_is_view (false), m_active_view_rid (region_id::null ())
    1459                 :            : {
    1460                 :    2208960 :   gcc_assert (type == NULL_TREE || TYPE_P (type));
    1461                 :    2208960 : }
    1462                 :            : 
    1463                 :            : /* region's copy ctor.  */
    1464                 :            : 
    1465                 :    2573760 : region::region (const region &other)
    1466                 :            : : m_parent_rid (other.m_parent_rid), m_sval_id (other.m_sval_id),
    1467                 :    2573760 :   m_type (other.m_type), m_view_rids (other.m_view_rids.length ()),
    1468                 :    2573760 :   m_is_view (other.m_is_view), m_active_view_rid (other.m_active_view_rid)
    1469                 :            : {
    1470                 :    2573760 :   int i;
    1471                 :    2573760 :   region_id *rid;
    1472                 :    2719520 :   FOR_EACH_VEC_ELT (other.m_view_rids, i, rid)
    1473                 :     145762 :     m_view_rids.quick_push (*rid);
    1474                 :    2573760 : }
    1475                 :            : 
    1476                 :            : /* Base implementation of region::add_to_hash vfunc; subclasses should
    1477                 :            :    chain up to this.  */
    1478                 :            : 
    1479                 :            : void
    1480                 :    1402550 : region::add_to_hash (inchash::hash &hstate) const
    1481                 :            : {
    1482                 :    1402550 :   inchash::add (m_parent_rid, hstate);
    1483                 :    1402550 :   inchash::add (m_sval_id, hstate);
    1484                 :    1402550 :   hstate.add_ptr (m_type);
    1485                 :            :   // TODO: views
    1486                 :    1402550 : }
    1487                 :            : 
    1488                 :            : /* Base implementation of region::print_fields vfunc.  */
    1489                 :            : 
    1490                 :            : void
    1491                 :         46 : region::print_fields (const region_model &model ATTRIBUTE_UNUSED,
    1492                 :            :                       region_id this_rid ATTRIBUTE_UNUSED,
    1493                 :            :                       pretty_printer *pp) const
    1494                 :            : {
    1495                 :         46 :   pp_printf (pp, "kind: %qs", region_kind_to_str (get_kind ()));
    1496                 :            : 
    1497                 :         46 :   pp_string (pp, ", parent: ");
    1498                 :         46 :   m_parent_rid.print (pp);
    1499                 :            : 
    1500                 :         46 :   pp_printf (pp, ", sval: ");
    1501                 :         46 :   m_sval_id.print (pp);
    1502                 :            : 
    1503                 :         46 :   if (m_type)
    1504                 :            :     {
    1505                 :         18 :       pp_printf (pp, ", type: ");
    1506                 :         18 :       print_quoted_type (pp, m_type);
    1507                 :            :     }
    1508                 :         46 : }
    1509                 :            : 
    1510                 :            : /* Determine if a pointer to this region must be non-NULL.
    1511                 :            : 
    1512                 :            :    Generally, pointers to regions must be non-NULL, but pointers
    1513                 :            :    to symbolic_regions might, in fact, be NULL.
    1514                 :            : 
    1515                 :            :    This allows us to simulate functions like malloc and calloc with:
    1516                 :            :    - only one "outcome" from each statement,
    1517                 :            :    - the idea that the pointer is on the heap if non-NULL
    1518                 :            :    - the possibility that the pointer could be NULL
    1519                 :            :    - the idea that successive values returned from malloc are non-equal
    1520                 :            :    - to be able to zero-fill for calloc.  */
    1521                 :            : 
    1522                 :            : bool
    1523                 :        872 : region::non_null_p (const region_model &model) const
    1524                 :            : {
    1525                 :            :   /* Look through views to get at the underlying region.  */
    1526                 :        904 :   if (is_view_p ())
    1527                 :         32 :     return model.get_region (m_parent_rid)->non_null_p (model);
    1528                 :            : 
    1529                 :            :   /* Are we within a symbolic_region?  If so, it could be NULL.  */
    1530                 :        872 :   if (const symbolic_region *sym_reg = dyn_cast_symbolic_region ())
    1531                 :            :     {
    1532                 :        553 :       if (sym_reg->m_possibly_null)
    1533                 :        334 :         return false;
    1534                 :            :     }
    1535                 :            : 
    1536                 :            :   return true;
    1537                 :            : }
    1538                 :            : 
    1539                 :            : /* class primitive_region : public region.  */
    1540                 :            : 
    1541                 :            : /* Implementation of region::clone vfunc for primitive_region.  */
    1542                 :            : 
    1543                 :            : region *
    1544                 :    1128550 : primitive_region::clone () const
    1545                 :            : {
    1546                 :    1128550 :   return new primitive_region (*this);
    1547                 :            : }
    1548                 :            : 
    1549                 :            : /* Implementation of region::walk_for_canonicalization vfunc for
    1550                 :            :    primitive_region.  */
    1551                 :            : 
    1552                 :            : void
    1553                 :     380832 : primitive_region::walk_for_canonicalization (canonicalization *) const
    1554                 :            : {
    1555                 :            :   /* Empty.  */
    1556                 :     380832 : }
    1557                 :            : 
    1558                 :            : /* class map_region : public region.  */
    1559                 :            : 
    1560                 :            : /* map_region's copy ctor.  */
    1561                 :            : 
    1562                 :     765363 : map_region::map_region (const map_region &other)
    1563                 :            : : region (other),
    1564                 :     765363 :   m_map (other.m_map)
    1565                 :            : {
    1566                 :     765363 : }
    1567                 :            : 
    1568                 :            : /* Compare the fields of this map_region with OTHER, returning true
    1569                 :            :    if they are equal.
    1570                 :            :    For use by region::operator==.  */
    1571                 :            : 
    1572                 :            : bool
    1573                 :     135686 : map_region::compare_fields (const map_region &other) const
    1574                 :            : {
    1575                 :     135686 :   if (m_map.elements () != other.m_map.elements ())
    1576                 :            :     return false;
    1577                 :            : 
    1578                 :     366115 :   for (map_t::iterator iter = m_map.begin ();
    1579                 :     366115 :        iter != m_map.end ();
    1580                 :     366115 :        ++iter)
    1581                 :            :     {
    1582                 :     233481 :       tree key = (*iter).first;
    1583                 :     233481 :       region_id e = (*iter).second;
    1584                 :     233481 :       region_id *other_slot = const_cast <map_t &> (other.m_map).get (key);
    1585                 :     231182 :       if (other_slot == NULL)
    1586                 :       3052 :         return false;
    1587                 :     231182 :       if (e != *other_slot)
    1588                 :            :         return false;
    1589                 :            :     }
    1590                 :     132634 :   return true;
    1591                 :            : }
    1592                 :            : 
    1593                 :            : /* Implementation of region::print_fields vfunc for map_region.  */
    1594                 :            : 
    1595                 :            : void
    1596                 :         12 : map_region::print_fields (const region_model &model,
    1597                 :            :                           region_id this_rid,
    1598                 :            :                           pretty_printer *pp) const
    1599                 :            : {
    1600                 :         12 :   region::print_fields (model, this_rid, pp);
    1601                 :         12 :   pp_string (pp, ", map: {");
    1602                 :         24 :   for (map_t::iterator iter = m_map.begin ();
    1603                 :         24 :        iter != m_map.end ();
    1604                 :         24 :        ++iter)
    1605                 :            :     {
    1606                 :         12 :       if (iter != m_map.begin ())
    1607                 :          2 :         pp_string (pp, ", ");
    1608                 :         12 :       tree expr = (*iter).first;
    1609                 :         12 :       region_id child_rid = (*iter).second;
    1610                 :         12 :       dump_quoted_tree (pp, expr);
    1611                 :         12 :       pp_string (pp, ": ");
    1612                 :         12 :       child_rid.print (pp);
    1613                 :            :     }
    1614                 :         12 :   pp_string (pp, "}");
    1615                 :         12 : }
    1616                 :            : 
    1617                 :            : /* Implementation of region::validate vfunc for map_region.  */
    1618                 :            : 
    1619                 :            : void
    1620                 :    1664030 : map_region::validate (const region_model &model) const
    1621                 :            : {
    1622                 :    1664030 :   region::validate (model);
    1623                 :    4417810 :   for (map_t::iterator iter = m_map.begin ();
    1624                 :    4417810 :        iter != m_map.end ();
    1625                 :    4417810 :        ++iter)
    1626                 :            :     {
    1627                 :    2753780 :       region_id child_rid = (*iter).second;
    1628                 :    2753780 :       child_rid.validate (model);
    1629                 :            :     }
    1630                 :    1664030 : }
    1631                 :            : 
    1632                 :            : /* Implementation of region::dump_dot_to_pp vfunc for map_region.  */
    1633                 :            : 
    1634                 :            : void
    1635                 :          0 : map_region::dump_dot_to_pp (const region_model &model,
    1636                 :            :                             region_id this_rid,
    1637                 :            :                             pretty_printer *pp) const
    1638                 :            : {
    1639                 :          0 :   region::dump_dot_to_pp (model, this_rid, pp);
    1640                 :          0 :   for (map_t::iterator iter = m_map.begin ();
    1641                 :          0 :        iter != m_map.end ();
    1642                 :          0 :        ++iter)
    1643                 :            :     {
    1644                 :            :       // TODO: add nodes/edges to label things
    1645                 :            : 
    1646                 :          0 :       tree expr = (*iter).first;
    1647                 :          0 :       region_id child_rid = (*iter).second;
    1648                 :            : 
    1649                 :          0 :       pp_printf (pp, "rid_label_%i [label=\"", child_rid.as_int ());
    1650                 :          0 :       pp_write_text_to_stream (pp);
    1651                 :          0 :       pp_printf (pp, "%qE", expr);
    1652                 :          0 :       pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
    1653                 :          0 :       pp_string (pp, "\"];");
    1654                 :          0 :       pp_newline (pp);
    1655                 :            : 
    1656                 :          0 :       pp_printf (pp, "rid_label_%i", child_rid.as_int ());
    1657                 :          0 :       pp_string (pp, " -> ");
    1658                 :          0 :       child_rid.dump_node_name_to_pp (pp);
    1659                 :          0 :       pp_string (pp, ";");
    1660                 :          0 :       pp_newline (pp);
    1661                 :            :     }
    1662                 :          0 : }
    1663                 :            : 
    1664                 :            : /* Implementation of region::dump_child_label vfunc for map_region.  */
    1665                 :            : 
    1666                 :            : void
    1667                 :         12 : map_region::dump_child_label (const region_model &model,
    1668                 :            :                               region_id this_rid,
    1669                 :            :                               region_id child_rid,
    1670                 :            :                               pretty_printer *pp) const
    1671                 :            : {
    1672                 :         12 :   region::dump_child_label (model, this_rid, child_rid, pp);
    1673                 :            : 
    1674                 :         28 :   for (map_t::iterator iter = m_map.begin ();
    1675                 :         28 :        iter != m_map.end ();
    1676                 :         28 :        ++iter)
    1677                 :            :     {
    1678                 :         16 :       if (child_rid == (*iter).second)
    1679                 :            :         {
    1680                 :         12 :           tree key = (*iter).first;
    1681                 :         12 :           dump_quoted_tree (pp, key);
    1682                 :         12 :           pp_string (pp, ": ");
    1683                 :            :         }
    1684                 :            :     }
    1685                 :         12 : }
    1686                 :            : 
    1687                 :            : /* Look for a child region for KEY within this map_region.
    1688                 :            :    If it doesn't already exist, create a child map_region, using TYPE for
    1689                 :            :    its type.
    1690                 :            :    Return the region_id of the child (whether pre-existing, or
    1691                 :            :    newly-created).
    1692                 :            :    Notify CTXT if we don't know how to handle TYPE.  */
    1693                 :            : 
    1694                 :            : region_id
    1695                 :    1319320 : map_region::get_or_create (region_model *model,
    1696                 :            :                            region_id this_rid,
    1697                 :            :                            tree key,
    1698                 :            :                            tree type,
    1699                 :            :                            region_model_context *ctxt)
    1700                 :            : {
    1701                 :    1319320 :   gcc_assert (key);
    1702                 :    1319320 :   gcc_assert (valid_key_p (key));
    1703                 :    1319320 :   region_id *slot = m_map.get (key);
    1704                 :     102885 :   if (slot)
    1705                 :     102885 :     return *slot;
    1706                 :    1216430 :   region_id child_rid = model->add_region_for_type (this_rid, type, ctxt);
    1707                 :    1216430 :   m_map.put (key, child_rid);
    1708                 :    1216430 :   return child_rid;
    1709                 :            : }
    1710                 :            : 
    1711                 :            : /* Get the region_id for the child region for KEY within this
    1712                 :            :    MAP_REGION, or NULL if there is no such child region.  */
    1713                 :            : 
    1714                 :            : region_id *
    1715                 :          0 : map_region::get (tree key)
    1716                 :            : {
    1717                 :          0 :   gcc_assert (key);
    1718                 :          0 :   gcc_assert (valid_key_p (key));
    1719                 :          0 :   region_id *slot = m_map.get (key);
    1720                 :          0 :   return slot;
    1721                 :            : }
    1722                 :            : 
    1723                 :            : /* Implementation of region::add_to_hash vfunc for map_region.  */
    1724                 :            : 
    1725                 :            : void
    1726                 :     431200 : map_region::add_to_hash (inchash::hash &hstate) const
    1727                 :            : {
    1728                 :     431200 :   region::add_to_hash (hstate);
    1729                 :            :   // TODO
    1730                 :     431200 : }
    1731                 :            : 
    1732                 :            : /* Implementation of region::remap_region_ids vfunc for map_region.  */
    1733                 :            : 
    1734                 :            : void
    1735                 :     419412 : map_region::remap_region_ids (const region_id_map &map)
    1736                 :            : {
    1737                 :     419412 :   region::remap_region_ids (map);
    1738                 :            : 
    1739                 :            :   /* Remap the region ids within the map entries.  */
    1740                 :     419412 :   for (map_t::iterator iter = m_map.begin ();
    1741                 :    2120470 :        iter != m_map.end (); ++iter)
    1742                 :    1817170 :     map.update (&(*iter).second);
    1743                 :     419412 : }
    1744                 :            : 
    1745                 :            : /* Remove the binding of KEY to its child region (but not the
    1746                 :            :    child region itself).
    1747                 :            :    For use when purging unneeded SSA names.  */
    1748                 :            : 
    1749                 :            : void
    1750                 :      17895 : map_region::unbind (tree key)
    1751                 :            : {
    1752                 :      17895 :   gcc_assert (key);
    1753                 :      17895 :   gcc_assert (valid_key_p (key));
    1754                 :      17895 :   m_map.remove (key);
    1755                 :      17895 : }
    1756                 :            : 
    1757                 :            : /* Look for a child region with id CHILD_RID within this map_region.
    1758                 :            :    If one is found, return its tree key, otherwise return NULL_TREE.  */
    1759                 :            : 
    1760                 :            : tree
    1761                 :      47462 : map_region::get_tree_for_child_region (region_id child_rid) const
    1762                 :            : {
    1763                 :            :   // TODO: do we want to store an inverse map?
    1764                 :     120911 :   for (map_t::iterator iter = m_map.begin ();
    1765                 :     109653 :        iter != m_map.end ();
    1766                 :     109653 :        ++iter)
    1767                 :            :     {
    1768                 :     109626 :       tree key = (*iter).first;
    1769                 :     109626 :       region_id r = (*iter).second;
    1770                 :     109626 :       if (r == child_rid)
    1771                 :      47435 :         return key;
    1772                 :            :     }
    1773                 :            : 
    1774                 :         27 :   return NULL_TREE;
    1775                 :            : }
    1776                 :            : 
    1777                 :            : /* Look for a child region CHILD within this map_region.
    1778                 :            :    If one is found, return its tree key, otherwise return NULL_TREE.  */
    1779                 :            : 
    1780                 :            : tree
    1781                 :          0 : map_region::get_tree_for_child_region (region *child,
    1782                 :            :                                        const region_model &model) const
    1783                 :            : {
    1784                 :            :   // TODO: do we want to store an inverse map?
    1785                 :          0 :   for (map_t::iterator iter = m_map.begin ();
    1786                 :          0 :        iter != m_map.end ();
    1787                 :          0 :        ++iter)
    1788                 :            :     {
    1789                 :          0 :       tree key = (*iter).first;
    1790                 :          0 :       region_id r = (*iter).second;
    1791                 :          0 :       if (model.get_region (r) == child)
    1792                 :          0 :         return key;
    1793                 :            :     }
    1794                 :            : 
    1795                 :          0 :   return NULL_TREE;
    1796                 :            : }
    1797                 :            : 
    1798                 :            : /* Comparator for trees to impose a deterministic ordering on
    1799                 :            :    T1 and T2.  */
    1800                 :            : 
    1801                 :            : static int
    1802                 :    6632970 : tree_cmp (const_tree t1, const_tree t2)
    1803                 :            : {
    1804                 :    6632970 :   gcc_assert (t1);
    1805                 :    6632970 :   gcc_assert (t2);
    1806                 :            : 
    1807                 :            :   /* Test tree codes first.  */
    1808                 :    6632970 :   if (TREE_CODE (t1) != TREE_CODE (t2))
    1809                 :    2043820 :     return TREE_CODE (t1) - TREE_CODE (t2);
    1810                 :            : 
    1811                 :            :   /* From this point on, we know T1 and T2 have the same tree code.  */
    1812                 :            : 
    1813                 :    4589150 :   if (DECL_P (t1))
    1814                 :            :     {
    1815                 :    4360740 :       if (DECL_NAME (t1) && DECL_NAME (t2))
    1816                 :    2173190 :         return strcmp (IDENTIFIER_POINTER (DECL_NAME (t1)),
    1817                 :    2173190 :                        IDENTIFIER_POINTER (DECL_NAME (t2)));
    1818                 :            :       else
    1819                 :            :         {
    1820                 :      10390 :           if (DECL_NAME (t1))
    1821                 :            :             return -1;
    1822                 :       6430 :           else if (DECL_NAME (t2))
    1823                 :            :             return 1;
    1824                 :            :           else
    1825                 :       1274 :             return DECL_UID (t1) - DECL_UID (t2);
    1826                 :            :         }
    1827                 :            :     }
    1828                 :            : 
    1829                 :    2405570 :   switch (TREE_CODE (t1))
    1830                 :            :     {
    1831                 :    1610000 :     case SSA_NAME:
    1832                 :    1610000 :       {
    1833                 :    1610000 :         if (SSA_NAME_VAR (t1) && SSA_NAME_VAR (t2))
    1834                 :            :           {
    1835                 :    1309870 :             int var_cmp = tree_cmp (SSA_NAME_VAR (t1), SSA_NAME_VAR (t2));
    1836                 :    1309870 :             if (var_cmp)
    1837                 :            :               return var_cmp;
    1838                 :      45413 :             return SSA_NAME_VERSION (t1) - SSA_NAME_VERSION (t2);
    1839                 :            :           }
    1840                 :            :         else
    1841                 :            :           {
    1842                 :     300130 :             if (SSA_NAME_VAR (t1))
    1843                 :            :               return -1;
    1844                 :     198419 :             else if (SSA_NAME_VAR (t2))
    1845                 :            :               return 1;
    1846                 :            :             else
    1847                 :      94777 :               return SSA_NAME_VERSION (t1) - SSA_NAME_VERSION (t2);
    1848                 :            :           }
    1849                 :            :       }
    1850                 :     725663 :       break;
    1851                 :            : 
    1852                 :     725663 :     case INTEGER_CST:
    1853                 :     725663 :       return tree_int_cst_compare (t1, t2);
    1854                 :            : 
    1855                 :      18092 :     case REAL_CST:
    1856                 :      18092 :       {
    1857                 :      18092 :         const real_value *rv1 = TREE_REAL_CST_PTR (t1);
    1858                 :      18092 :         const real_value *rv2 = TREE_REAL_CST_PTR (t2);
    1859                 :      18092 :         if (real_compare (UNORDERED_EXPR, rv1, rv2))
    1860                 :            :           {
    1861                 :            :             /* Impose an arbitrary order on NaNs relative to other NaNs
    1862                 :            :                and to non-NaNs.  */
    1863                 :      12836 :             if (int cmp_isnan = real_isnan (rv1) - real_isnan (rv2))
    1864                 :            :               return cmp_isnan;
    1865                 :       8476 :             if (int cmp_issignaling_nan
    1866                 :       4238 :                   = real_issignaling_nan (rv1) - real_issignaling_nan (rv2))
    1867                 :            :               return cmp_issignaling_nan;
    1868                 :       2024 :             return real_isneg (rv1) - real_isneg (rv2);
    1869                 :            :           }
    1870                 :       5256 :         if (real_compare (LT_EXPR, rv1, rv2))
    1871                 :            :           return -1;
    1872                 :       3460 :         if (real_compare (GT_EXPR, rv1, rv2))
    1873                 :       1274 :           return 1;
    1874                 :            :         return 0;
    1875                 :            :       }
    1876                 :            : 
    1877                 :      51810 :     case STRING_CST:
    1878                 :      51810 :       return strcmp (TREE_STRING_POINTER (t1),
    1879                 :      51810 :                      TREE_STRING_POINTER (t2));
    1880                 :            : 
    1881                 :          0 :     default:
    1882                 :          0 :       gcc_unreachable ();
    1883                 :            :       break;
    1884                 :            :     }
    1885                 :            : 
    1886                 :            :   gcc_unreachable ();
    1887                 :            : 
    1888                 :            :   return 0;
    1889                 :            : }
    1890                 :            : 
    1891                 :            : /* qsort comparator for trees to impose a deterministic ordering on
    1892                 :            :    P1 and P2.  */
    1893                 :            : 
    1894                 :            : static int
    1895                 :    4492280 : tree_cmp (const void *p1, const void *p2)
    1896                 :            : {
    1897                 :    4492280 :   const_tree t1 = *(const_tree const *)p1;
    1898                 :    4492280 :   const_tree t2 = *(const_tree const *)p2;
    1899                 :            : 
    1900                 :    4492280 :   return tree_cmp (t1, t2);
    1901                 :            : }
    1902                 :            : 
    1903                 :            : /* Attempt to merge MAP_REGION_A and MAP_REGION_B into MERGED_MAP_REGION,
    1904                 :            :    which has region_id MERGED_RID, using MERGER.
    1905                 :            :    Return true if the merger is possible, false otherwise.  */
    1906                 :            : 
    1907                 :            : bool
    1908                 :     715612 : map_region::can_merge_p (const map_region *map_region_a,
    1909                 :            :                          const map_region *map_region_b,
    1910                 :            :                          map_region *merged_map_region,
    1911                 :            :                          region_id merged_rid,
    1912                 :            :                          model_merger *merger)
    1913                 :            : {
    1914                 :     715612 :   for (map_t::iterator iter = map_region_a->m_map.begin ();
    1915                 :    2175620 :        iter != map_region_a->m_map.end ();
    1916                 :    2175620 :        ++iter)
    1917                 :            :     {
    1918                 :    1469230 :       tree key_a = (*iter).first;
    1919                 :    1469230 :       region_id rid_a = (*iter).second;
    1920                 :            : 
    1921                 :    1469230 :       if (const region_id *slot_b
    1922                 :    2929240 :           = const_cast<map_region *>(map_region_b)->m_map.get (key_a))
    1923                 :            :         {
    1924                 :    1195280 :           region_id rid_b = *slot_b;
    1925                 :            : 
    1926                 :    1195280 :           region *child_region_a = merger->get_region_a <region> (rid_a);
    1927                 :    1195280 :           region *child_region_b = merger->get_region_b <region> (rid_b);
    1928                 :            : 
    1929                 :    1195280 :           gcc_assert (child_region_a->get_type ()
    1930                 :            :                       == child_region_b->get_type ());
    1931                 :            : 
    1932                 :    1195280 :           gcc_assert (child_region_a->get_kind ()
    1933                 :            :                       == child_region_b->get_kind ());
    1934                 :            : 
    1935                 :    1195280 :           region_id child_merged_rid
    1936                 :            :             = merged_map_region->get_or_create (merger->m_merged_model,
    1937                 :            :                                                 merged_rid,
    1938                 :            :                                                 key_a,
    1939                 :            :                                                 child_region_a->get_type (),
    1940                 :    1195280 :                                                 NULL);
    1941                 :            : 
    1942                 :    1195280 :           region *child_merged_region
    1943                 :    1195280 :             = merger->m_merged_model->get_region (child_merged_rid);
    1944                 :            : 
    1945                 :            :           /* Consider values.  */
    1946                 :    1195280 :           svalue_id child_a_sid = child_region_a->get_value_direct ();
    1947                 :    1195280 :           svalue_id child_b_sid = child_region_b->get_value_direct ();
    1948                 :    1195280 :           svalue_id child_merged_sid;
    1949                 :    1195280 :           if (!merger->can_merge_values_p (child_a_sid, child_b_sid,
    1950                 :            :                                            &child_merged_sid))
    1951                 :       9221 :             return false;
    1952                 :    1187170 :           if (!child_merged_sid.null_p ())
    1953                 :     806657 :             child_merged_region->set_value (*merger->m_merged_model,
    1954                 :            :                                             child_merged_rid,
    1955                 :            :                                             child_merged_sid,
    1956                 :            :                                             NULL);
    1957                 :            : 
    1958                 :    1187170 :           if (map_region *map_region_a = child_region_a->dyn_cast_map_region ())
    1959                 :            :             {
    1960                 :            :               /* Recurse.  */
    1961                 :     747476 :               if (!can_merge_p (map_region_a,
    1962                 :     373738 :                                 as_a <map_region *> (child_region_b),
    1963                 :            :                                 as_a <map_region *> (child_merged_region),
    1964                 :            :                                 child_merged_rid,
    1965                 :            :                                 merger))
    1966                 :            :                 return false;
    1967                 :            :             }
    1968                 :            : 
    1969                 :            :         }
    1970                 :            :       else
    1971                 :            :         {
    1972                 :            :           /* TODO: region is present in A, but absent in B.  */
    1973                 :            :         }
    1974                 :            :     }
    1975                 :            : 
    1976                 :            :   /* TODO: check for keys in B that aren't in A.  */
    1977                 :            : 
    1978                 :     706391 :   return true;
    1979                 :            : }
    1980                 :            : 
    1981                 :            : 
    1982                 :            : /* Implementation of region::walk_for_canonicalization vfunc for
    1983                 :            :    map_region.  */
    1984                 :            : 
    1985                 :            : void
    1986                 :     277580 : map_region::walk_for_canonicalization (canonicalization *c) const
    1987                 :            : {
    1988                 :     277580 :   auto_vec<tree> keys (m_map.elements ());
    1989                 :     277580 :   for (map_t::iterator iter = m_map.begin ();
    1990                 :     763239 :        iter != m_map.end ();
    1991                 :     763239 :        ++iter)
    1992                 :            :     {
    1993                 :     485659 :       tree key_a = (*iter).first;
    1994                 :     485659 :       keys.quick_push (key_a);
    1995                 :            :     }
    1996                 :     277580 :   keys.qsort (tree_cmp);
    1997                 :            : 
    1998                 :            :   unsigned i;
    1999                 :            :   tree key;
    2000                 :     922295 :   FOR_EACH_VEC_ELT (keys, i, key)
    2001                 :            :     {
    2002                 :     485659 :       region_id rid = *const_cast<map_region *>(this)->m_map.get (key);
    2003                 :     485659 :       c->walk_rid (rid);
    2004                 :            :     }
    2005                 :     277580 : }
    2006                 :            : 
    2007                 :            : /* For debugging purposes: look for a child region for a decl named
    2008                 :            :    IDENTIFIER (or an SSA_NAME for such a decl), returning its value,
    2009                 :            :    or svalue_id::null if none are found.  */
    2010                 :            : 
    2011                 :            : svalue_id
    2012                 :          4 : map_region::get_value_by_name (tree identifier,
    2013                 :            :                                const region_model &model) const
    2014                 :            : {
    2015                 :          4 :   for (map_t::iterator iter = m_map.begin ();
    2016                 :          4 :        iter != m_map.end ();
    2017                 :          4 :        ++iter)
    2018                 :            :     {
    2019                 :          4 :       tree key = (*iter).first;
    2020                 :          4 :       if (TREE_CODE (key) == SSA_NAME)
    2021                 :          0 :         if (SSA_NAME_VAR (key))
    2022                 :          0 :           key = SSA_NAME_VAR (key);
    2023                 :          4 :       if (DECL_P (key))
    2024                 :          4 :         if (DECL_NAME (key) == identifier)
    2025                 :            :           {
    2026                 :          4 :             region_id rid = (*iter).second;
    2027                 :          4 :             region *region = model.get_region (rid);
    2028                 :          4 :             return region->get_value (const_cast<region_model &>(model),
    2029                 :          4 :                                       false, NULL);
    2030                 :            :           }
    2031                 :            :     }
    2032                 :          0 :   return svalue_id::null ();
    2033                 :            : }
    2034                 :            : 
    2035                 :            : /* class struct_or_union_region : public map_region.  */
    2036                 :            : 
    2037                 :            : /* Implementation of map_region::valid_key_p vfunc for
    2038                 :            :    struct_or_union_region.  */
    2039                 :            : 
    2040                 :            : bool
    2041                 :      15005 : struct_or_union_region::valid_key_p (tree key) const
    2042                 :            : {
    2043                 :      15005 :   return TREE_CODE (key) == FIELD_DECL;
    2044                 :            : }
    2045                 :            : 
    2046                 :            : /* Compare the fields of this struct_or_union_region with OTHER, returning
    2047                 :            :    true if they are equal.
    2048                 :            :    For use by region::operator==.  */
    2049                 :            : 
    2050                 :            : bool
    2051                 :      16781 : struct_or_union_region::compare_fields (const struct_or_union_region &other)
    2052                 :            :   const
    2053                 :            : {
    2054                 :      16781 :   return map_region::compare_fields (other);
    2055                 :            : }
    2056                 :            : 
    2057                 :            : /* class struct_region : public struct_or_union_region.  */
    2058                 :            : 
    2059                 :            : /* Implementation of region::clone vfunc for struct_region.  */
    2060                 :            : 
    2061                 :            : region *
    2062                 :      99805 : struct_region::clone () const
    2063                 :            : {
    2064                 :      99805 :   return new struct_region (*this);
    2065                 :            : }
    2066                 :            : 
    2067                 :            : /* Compare the fields of this struct_region with OTHER, returning true
    2068                 :            :    if they are equal.
    2069                 :            :    For use by region::operator==.  */
    2070                 :            : 
    2071                 :            : bool
    2072                 :      16707 : struct_region::compare_fields (const struct_region &other) const
    2073                 :            : {
    2074                 :      16707 :   return struct_or_union_region::compare_fields (other);
    2075                 :            : }
    2076                 :            : 
    2077                 :            : /* class union_region : public struct_or_union_region.  */
    2078                 :            : 
    2079                 :            : /* Implementation of region::clone vfunc for union_region.  */
    2080                 :            : 
    2081                 :            : region *
    2082                 :        475 : union_region::clone () const
    2083                 :            : {
    2084                 :        475 :   return new union_region (*this);
    2085                 :            : }
    2086                 :            : 
    2087                 :            : /* Compare the fields of this union_region with OTHER, returning true
    2088                 :            :    if they are equal.
    2089                 :            :    For use by region::operator==.  */
    2090                 :            : 
    2091                 :            : bool
    2092                 :         74 : union_region::compare_fields (const union_region &other) const
    2093                 :            : {
    2094                 :         74 :   return struct_or_union_region::compare_fields (other);
    2095                 :            : }
    2096                 :            : 
    2097                 :            : /* class frame_region : public map_region.  */
    2098                 :            : 
    2099                 :            : /* Compare the fields of this frame_region with OTHER, returning true
    2100                 :            :    if they are equal.
    2101                 :            :    For use by region::operator==.  */
    2102                 :            : 
    2103                 :            : bool
    2104                 :      42003 : frame_region::compare_fields (const frame_region &other) const
    2105                 :            : {
    2106                 :      42003 :   if (!map_region::compare_fields (other))
    2107                 :            :     return false;
    2108                 :      38952 :   if (m_fun != other.m_fun)
    2109                 :            :     return false;
    2110                 :      38952 :   if (m_depth != other.m_depth)
    2111                 :          0 :     return false;
    2112                 :            :   return true;
    2113                 :            : }
    2114                 :            : 
    2115                 :            : /* Implementation of region::clone vfunc for frame_region.  */
    2116                 :            : 
    2117                 :            : region *
    2118                 :     222206 : frame_region::clone () const
    2119                 :            : {
    2120                 :     222206 :   return new frame_region (*this);
    2121                 :            : }
    2122                 :            : 
    2123                 :            : /* Implementation of map_region::valid_key_p vfunc for frame_region.  */
    2124                 :            : 
    2125                 :            : bool
    2126                 :     905657 : frame_region::valid_key_p (tree key) const
    2127                 :            : {
    2128                 :            :   // TODO: could also check that VAR_DECLs are locals
    2129                 :     905657 :   return (TREE_CODE (key) == PARM_DECL
    2130                 :     905657 :           || TREE_CODE (key) == VAR_DECL
    2131                 :     774855 :           || TREE_CODE (key) == SSA_NAME
    2132                 :     907851 :           || TREE_CODE (key) == RESULT_DECL);
    2133                 :            : }
    2134                 :            : 
    2135                 :            : /* Implementation of region::print_fields vfunc for frame_region.  */
    2136                 :            : 
    2137                 :            : void
    2138                 :          0 : frame_region::print_fields (const region_model &model,
    2139                 :            :                             region_id this_rid,
    2140                 :            :                             pretty_printer *pp) const
    2141                 :            : {
    2142                 :          0 :   map_region::print_fields (model, this_rid, pp);
    2143                 :          0 :   pp_printf (pp, ", function: %qs, depth: %i", function_name (m_fun), m_depth);
    2144                 :          0 : }
    2145                 :            : 
    2146                 :            : /* Implementation of region::add_to_hash vfunc for frame_region.  */
    2147                 :            : 
    2148                 :            : void
    2149                 :     125377 : frame_region::add_to_hash (inchash::hash &hstate) const
    2150                 :            : {
    2151                 :     125377 :   map_region::add_to_hash (hstate);
    2152                 :     125377 :   hstate.add_ptr (m_fun);
    2153                 :     125377 :   hstate.add_int (m_depth);
    2154                 :     125377 : }
    2155                 :            : 
    2156                 :            : /* class globals_region : public scope_region.  */
    2157                 :            : 
    2158                 :            : /* Compare the fields of this globals_region with OTHER, returning true
    2159                 :            :    if they are equal.
    2160                 :            :    For use by region::operator==.  */
    2161                 :            : 
    2162                 :            : bool
    2163                 :       4674 : globals_region::compare_fields (const globals_region &other) const
    2164                 :            : {
    2165                 :       4674 :   return map_region::compare_fields (other);
    2166                 :            : }
    2167                 :            : 
    2168                 :            : /* Implementation of region::clone vfunc for globals_region.  */
    2169                 :            : 
    2170                 :            : region *
    2171                 :      26929 : globals_region::clone () const
    2172                 :            : {
    2173                 :      26929 :   return new globals_region (*this);
    2174                 :            : }
    2175                 :            : 
    2176                 :            : /* Implementation of map_region::valid_key_p vfunc for globals_region.  */
    2177                 :            : 
    2178                 :            : bool
    2179                 :      12085 : globals_region::valid_key_p (tree key) const
    2180                 :            : {
    2181                 :      12085 :   return TREE_CODE (key) == VAR_DECL;
    2182                 :            : }
    2183                 :            : 
    2184                 :            : /* class code_region : public map_region.  */
    2185                 :            : 
    2186                 :            : /* Compare the fields of this code_region with OTHER, returning true
    2187                 :            :    if they are equal.
    2188                 :            :    For use by region::operator==.  */
    2189                 :            : 
    2190                 :            : bool
    2191                 :      20419 : code_region::compare_fields (const code_region &other) const
    2192                 :            : {
    2193                 :      20419 :   return map_region::compare_fields (other);
    2194                 :            : }
    2195                 :            : 
    2196                 :            : /* Implementation of region::clone vfunc for code_region.  */
    2197                 :            : 
    2198                 :            : region *
    2199                 :     116788 : code_region::clone () const
    2200                 :            : {
    2201                 :     116788 :   return new code_region (*this);
    2202                 :            : }
    2203                 :            : 
    2204                 :            : /* Implementation of map_region::valid_key_p vfunc for code_region.  */
    2205                 :            : 
    2206                 :            : bool
    2207                 :     404455 : code_region::valid_key_p (tree key) const
    2208                 :            : {
    2209                 :     404455 :   return TREE_CODE (key) == FUNCTION_DECL;
    2210                 :            : }
    2211                 :            : 
    2212                 :            : /* class array_region : public region.  */
    2213                 :            : 
    2214                 :            : /* array_region's copy ctor.  */
    2215                 :            : 
    2216                 :     176840 : array_region::array_region (const array_region &other)
    2217                 :            : : region (other),
    2218                 :     176840 :   m_map (other.m_map)
    2219                 :            : {
    2220                 :     176840 : }
    2221                 :            : 
    2222                 :            : /* Get a child region for the element with index INDEX_SID.  */
    2223                 :            : 
    2224                 :            : region_id
    2225                 :       1222 : array_region::get_element (region_model *model,
    2226                 :            :                            region_id this_rid,
    2227                 :            :                            svalue_id index_sid,
    2228                 :            :                            region_model_context *ctxt)
    2229                 :            : {
    2230                 :       1222 :   tree element_type = TREE_TYPE (get_type ());
    2231                 :       1222 :   svalue *index_sval = model->get_svalue (index_sid);
    2232                 :       1222 :   if (tree cst_index = index_sval->maybe_get_constant ())
    2233                 :            :     {
    2234                 :        894 :       key_t key = key_from_constant (cst_index);
    2235                 :        894 :       region_id element_rid
    2236                 :        894 :         = get_or_create (model, this_rid, key, element_type, ctxt);
    2237                 :        894 :       return element_rid;
    2238                 :            :    }
    2239                 :            : 
    2240                 :        328 :   return model->get_or_create_view (this_rid, element_type, ctxt);
    2241                 :            : }
    2242                 :            : 
    2243                 :            : /* Implementation of region::clone vfunc for array_region.  */
    2244                 :            : 
    2245                 :            : region *
    2246                 :     176840 : array_region::clone () const
    2247                 :            : {
    2248                 :     176840 :   return new array_region (*this);
    2249                 :            : }
    2250                 :            : 
    2251                 :            : /* Compare the fields of this array_region with OTHER, returning true
    2252                 :            :    if they are equal.
    2253                 :            :    For use by region::operator==.  */
    2254                 :            : 
    2255                 :            : bool
    2256                 :      30028 : array_region::compare_fields (const array_region &other) const
    2257                 :            : {
    2258                 :      30028 :   if (m_map.elements () != other.m_map.elements ())
    2259                 :            :     return false;
    2260                 :            : 
    2261                 :      39674 :   for (map_t::iterator iter = m_map.begin ();
    2262                 :      39674 :        iter != m_map.end ();
    2263                 :      39674 :        ++iter)
    2264                 :            :     {
    2265                 :       9646 :       int key = (*iter).first;
    2266                 :       9646 :       region_id e = (*iter).second;
    2267                 :       9646 :       region_id *other_slot = const_cast <map_t &> (other.m_map).get (key);
    2268                 :       9646 :       if (other_slot == NULL)
    2269                 :          0 :         return false;
    2270                 :       9646 :       if (e != *other_slot)
    2271                 :            :         return false;
    2272                 :            :     }
    2273                 :      30028 :   return true;
    2274                 :            : }
    2275                 :            : 
    2276                 :            : /* Implementation of region::print_fields vfunc for array_region.  */
    2277                 :            : 
    2278                 :            : void
    2279                 :          4 : array_region::print_fields (const region_model &model,
    2280                 :            :                             region_id this_rid,
    2281                 :            :                             pretty_printer *pp) const
    2282                 :            : {
    2283                 :          4 :   region::print_fields (model, this_rid, pp);
    2284                 :          4 :   pp_string (pp, ", array: {");
    2285                 :          8 :   for (map_t::iterator iter = m_map.begin ();
    2286                 :          8 :        iter != m_map.end ();
    2287                 :          8 :        ++iter)
    2288                 :            :     {
    2289                 :          4 :       if (iter != m_map.begin ())
    2290                 :          0 :         pp_string (pp, ", ");
    2291                 :          4 :       int key = (*iter).first;
    2292                 :          4 :       region_id child_rid = (*iter).second;
    2293                 :          4 :       pp_printf (pp, "[%i]: ", key);
    2294                 :          4 :       child_rid.print (pp);
    2295                 :            :     }
    2296                 :          4 :   pp_string (pp, "}");
    2297                 :          4 : }
    2298                 :            : 
    2299                 :            : /* Implementation of region::validate vfunc for array_region.  */
    2300                 :            : 
    2301                 :            : void
    2302                 :     230681 : array_region::validate (const region_model &model) const
    2303                 :            : {
    2304                 :     230681 :   region::validate (model);
    2305                 :     303353 :   for (map_t::iterator iter = m_map.begin ();
    2306                 :     303353 :        iter != m_map.end ();
    2307                 :     303353 :        ++iter)
    2308                 :            :     {
    2309                 :      72672 :       region_id child_rid = (*iter).second;
    2310                 :      72672 :       child_rid.validate (model);
    2311                 :            :     }
    2312                 :     230681 : }
    2313                 :            : 
    2314                 :            : /* Implementation of region::dump_dot_to_pp vfunc for array_region.  */
    2315                 :            : 
    2316                 :            : void
    2317                 :          0 : array_region::dump_dot_to_pp (const region_model &model,
    2318                 :            :                               region_id this_rid,
    2319                 :            :                               pretty_printer *pp) const
    2320                 :            : {
    2321                 :          0 :   region::dump_dot_to_pp (model, this_rid, pp);
    2322                 :          0 :   for (map_t::iterator iter = m_map.begin ();
    2323                 :          0 :        iter != m_map.end ();
    2324                 :          0 :        ++iter)
    2325                 :            :     {
    2326                 :            :       // TODO: add nodes/edges to label things
    2327                 :            : 
    2328                 :          0 :       int key = (*iter).first;
    2329                 :          0 :       region_id child_rid = (*iter).second;
    2330                 :            : 
    2331                 :          0 :       pp_printf (pp, "rid_label_%i [label=\"", child_rid.as_int ());
    2332                 :          0 :       pp_write_text_to_stream (pp);
    2333                 :          0 :       pp_printf (pp, "%qi", key);
    2334                 :          0 :       pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
    2335                 :          0 :       pp_string (pp, "\"];");
    2336                 :          0 :       pp_newline (pp);
    2337                 :            : 
    2338                 :          0 :       pp_printf (pp, "rid_label_%i", child_rid.as_int ());
    2339                 :          0 :       pp_string (pp, " -> ");
    2340                 :          0 :       child_rid.dump_node_name_to_pp (pp);
    2341                 :          0 :       pp_string (pp, ";");
    2342                 :          0 :       pp_newline (pp);
    2343                 :            :     }
    2344                 :          0 : }
    2345                 :            : 
    2346                 :            : /* Implementation of region::dump_child_label vfunc for array_region.  */
    2347                 :            : 
    2348                 :            : void
    2349                 :          4 : array_region::dump_child_label (const region_model &model,
    2350                 :            :                               region_id this_rid,
    2351                 :            :                               region_id child_rid,
    2352                 :            :                               pretty_printer *pp) const
    2353                 :            : {
    2354                 :          4 :   region::dump_child_label (model, this_rid, child_rid, pp);
    2355                 :            : 
    2356                 :          8 :   for (map_t::iterator iter = m_map.begin ();
    2357                 :          8 :        iter != m_map.end ();
    2358                 :          8 :        ++iter)
    2359                 :            :     {
    2360                 :          4 :       if (child_rid == (*iter).second)
    2361                 :            :         {
    2362                 :          4 :           int key = (*iter).first;
    2363                 :          4 :           pp_printf (pp, "[%i]: ", key);
    2364                 :            :         }
    2365                 :            :     }
    2366                 :          4 : }
    2367                 :            : 
    2368                 :            : /* Look for a child region for KEY within this array_region.
    2369                 :            :    If it doesn't already exist, create a child array_region, using TYPE for
    2370                 :            :    its type.
    2371                 :            :    Return the region_id of the child (whether pre-existing, or
    2372                 :            :    newly-created).
    2373                 :            :    Notify CTXT if we don't know how to handle TYPE.  */
    2374                 :            : 
    2375                 :            : region_id
    2376                 :        894 : array_region::get_or_create (region_model *model,
    2377                 :            :                              region_id this_rid,
    2378                 :            :                              key_t key,
    2379                 :            :                              tree type,
    2380                 :            :                              region_model_context *ctxt)
    2381                 :            : {
    2382                 :        894 :   region_id *slot = m_map.get (key);
    2383                 :        265 :   if (slot)
    2384                 :        265 :     return *slot;
    2385                 :        629 :   region_id child_rid = model->add_region_for_type (this_rid, type, ctxt);
    2386                 :        629 :   m_map.put (key, child_rid);
    2387                 :        629 :   return child_rid;
    2388                 :            : }
    2389                 :            : 
    2390                 :            : /* Get the region_id for the child region for KEY within this
    2391                 :            :    ARRAY_REGION, or NULL if there is no such child region.  */
    2392                 :            : 
    2393                 :            : region_id *
    2394                 :          0 : array_region::get (key_t key)
    2395                 :            : {
    2396                 :          0 :   region_id *slot = m_map.get (key);
    2397                 :          0 :   return slot;
    2398                 :            : }
    2399                 :            : 
    2400                 :            : /* Implementation of region::add_to_hash vfunc for array_region.  */
    2401                 :            : 
    2402                 :            : void
    2403                 :      92598 : array_region::add_to_hash (inchash::hash &hstate) const
    2404                 :            : {
    2405                 :      92598 :   region::add_to_hash (hstate);
    2406                 :            :   // TODO
    2407                 :      92598 : }
    2408                 :            : 
    2409                 :            : /* Implementation of region::remap_region_ids vfunc for array_region.  */
    2410                 :            : 
    2411                 :            : void
    2412                 :      94670 : array_region::remap_region_ids (const region_id_map &map)
    2413                 :            : {
    2414                 :      94670 :   region::remap_region_ids (map);
    2415                 :            : 
    2416                 :            :   /* Remap the region ids within the map entries.  */
    2417                 :      94670 :   for (map_t::iterator iter = m_map.begin ();
    2418                 :     182844 :        iter != m_map.end (); ++iter)
    2419                 :      61874 :     map.update (&(*iter).second);
    2420                 :      94670 : }
    2421                 :            : 
    2422                 :            : /* Look for a child region with id CHILD_RID within this array_region.
    2423                 :            :    If one is found, write its key to *OUT and return true,
    2424                 :            :    otherwise return false.  */
    2425                 :            : 
    2426                 :            : bool
    2427                 :       1742 : array_region::get_key_for_child_region (region_id child_rid, key_t *out) const
    2428                 :            : {
    2429                 :            :   // TODO: do we want to store an inverse map?
    2430                 :       2036 :   for (map_t::iterator iter = m_map.begin ();
    2431                 :       2036 :        iter != m_map.end ();
    2432                 :       2036 :        ++iter)
    2433                 :            :     {
    2434                 :       1666 :       key_t key = (*iter).first;
    2435                 :       1666 :       region_id r = (*iter).second;
    2436                 :       1666 :       if (r == child_rid)
    2437                 :            :         {
    2438                 :       1372 :           *out = key;
    2439                 :       1372 :           return true;
    2440                 :            :         }
    2441                 :            :     }
    2442                 :            : 
    2443                 :        370 :   return false;
    2444                 :            : }
    2445                 :            : 
    2446                 :            : /* qsort comparator for array_region's keys.  */
    2447                 :            : 
    2448                 :            : int
    2449                 :      20970 : array_region::key_cmp (const void *p1, const void *p2)
    2450                 :            : {
    2451                 :      20970 :   key_t i1 = *(const key_t *)p1;
    2452                 :      20970 :   key_t i2 = *(const key_t *)p2;
    2453                 :            : 
    2454                 :      20970 :   if (i1 > i2)
    2455                 :            :     return 1;
    2456                 :       9623 :   else if (i1 < i2)
    2457                 :            :     return -1;
    2458                 :            :   else
    2459                 :          0 :     return 0;
    2460                 :            : }
    2461                 :            : 
    2462                 :            : /* Implementation of region::walk_for_canonicalization vfunc for
    2463                 :            :    array_region.  */
    2464                 :            : 
    2465                 :            : void
    2466                 :      61910 : array_region::walk_for_canonicalization (canonicalization *c) const
    2467                 :            : {
    2468                 :      61910 :   auto_vec<int> keys (m_map.elements ());
    2469                 :      61910 :   for (map_t::iterator iter = m_map.begin ();
    2470                 :      81996 :        iter != m_map.end ();
    2471                 :      81996 :        ++iter)
    2472                 :            :     {
    2473                 :      20086 :       int key_a = (*iter).first;
    2474                 :      20086 :       keys.quick_push (key_a);
    2475                 :            :     }
    2476                 :      61910 :   keys.qsort (key_cmp);
    2477                 :            : 
    2478                 :            :   unsigned i;
    2479                 :            :   int key;
    2480                 :      99325 :   FOR_EACH_VEC_ELT (keys, i, key)
    2481                 :            :     {
    2482                 :      20086 :       region_id rid = *const_cast<array_region *>(this)->m_map.get (key);
    2483                 :      20086 :       c->walk_rid (rid);
    2484                 :            :     }
    2485                 :      61910 : }
    2486                 :            : 
    2487                 :            : /* Convert constant CST into an array_region::key_t.  */
    2488                 :            : 
    2489                 :            : array_region::key_t
    2490                 :        931 : array_region::key_from_constant (tree cst)
    2491                 :            : {
    2492                 :        931 :   gcc_assert (CONSTANT_CLASS_P (cst));
    2493                 :        931 :   wide_int w = wi::to_wide (cst);
    2494                 :        931 :   key_t result = w.to_shwi ();
    2495                 :        931 :   return result;
    2496                 :            : }
    2497                 :            : 
    2498                 :            : /* Convert array_region::key_t KEY into a tree constant.  */
    2499                 :            : 
    2500                 :            : tree
    2501                 :         65 : array_region::constant_from_key (key_t key)
    2502                 :            : {
    2503                 :         65 :   tree array_type = get_type ();
    2504                 :         65 :   tree index_type = TYPE_DOMAIN (array_type);
    2505                 :         65 :   return build_int_cst (index_type, key);
    2506                 :            : }
    2507                 :            : 
    2508                 :            : /* class function_region : public map_region.  */
    2509                 :            : 
    2510                 :            : /* Compare the fields of this function_region with OTHER, returning true
    2511                 :            :    if they are equal.
    2512                 :            :    For use by region::operator==.  */
    2513                 :            : 
    2514                 :            : bool
    2515                 :      51809 : function_region::compare_fields (const function_region &other) const
    2516                 :            : {
    2517                 :      51809 :   return map_region::compare_fields (other);
    2518                 :            : }
    2519                 :            : 
    2520                 :            : /* Implementation of region::clone vfunc for function_region.  */
    2521                 :            : 
    2522                 :            : region *
    2523                 :     299160 : function_region::clone () const
    2524                 :            : {
    2525                 :     299160 :   return new function_region (*this);
    2526                 :            : }
    2527                 :            : 
    2528                 :            : /* Implementation of map_region::valid_key_p vfunc for function_region.  */
    2529                 :            : 
    2530                 :            : bool
    2531                 :         11 : function_region::valid_key_p (tree key) const
    2532                 :            : {
    2533                 :         11 :   return TREE_CODE (key) == LABEL_DECL;
    2534                 :            : }
    2535                 :            : 
    2536                 :            : /* class stack_region : public region.  */
    2537                 :            : 
    2538                 :            : /* stack_region's copy ctor.  */
    2539                 :            : 
    2540                 :     161131 : stack_region::stack_region (const stack_region &other)
    2541                 :            : : region (other),
    2542                 :     161131 :   m_frame_rids (other.m_frame_rids.length ())
    2543                 :            : {
    2544                 :            :   int i;
    2545                 :            :   region_id *frame_rid;
    2546                 :     383337 :   FOR_EACH_VEC_ELT (other.m_frame_rids, i, frame_rid)
    2547                 :     222206 :     m_frame_rids.quick_push (*frame_rid);
    2548                 :     161131 : }
    2549                 :            : 
    2550                 :            : /* Compare the fields of this stack_region with OTHER, returning true
    2551                 :            :    if they are equal.
    2552                 :            :    For use by region::operator==.  */
    2553                 :            : 
    2554                 :            : bool
    2555                 :      31398 : stack_region::compare_fields (const stack_region &other) const
    2556                 :            : {
    2557                 :      94190 :   if (m_frame_rids.length () != other.m_frame_rids.length ())
    2558                 :            :     return false;
    2559                 :            : 
    2560                 :            :   int i;
    2561                 :            :   region_id *frame_rid;
    2562                 :      73401 :   FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
    2563                 :      42003 :     if (m_frame_rids[i] != other.m_frame_rids[i])
    2564                 :            :       return false;
    2565                 :            : 
    2566                 :            :   return true;
    2567                 :            : }
    2568                 :            : 
    2569                 :            : /* Implementation of region::clone vfunc for stack_region.  */
    2570                 :            : 
    2571                 :            : region *
    2572                 :     161131 : stack_region::clone () const
    2573                 :            : {
    2574                 :     161131 :   return new stack_region (*this);
    2575                 :            : }
    2576                 :            : 
    2577                 :            : /* Implementation of region::print_fields vfunc for stack_region.  */
    2578                 :            : 
    2579                 :            : void
    2580                 :          2 : stack_region::print_fields (const region_model &model,
    2581                 :            :                             region_id this_rid,
    2582                 :            :                             pretty_printer *pp) const
    2583                 :            : {
    2584                 :          2 :   region::print_fields (model, this_rid, pp);
    2585                 :            :   // TODO
    2586                 :          2 : }
    2587                 :            : 
    2588                 :            : /* Implementation of region::dump_child_label vfunc for stack_region.  */
    2589                 :            : 
    2590                 :            : void
    2591                 :          0 : stack_region::dump_child_label (const region_model &model,
    2592                 :            :                                 region_id this_rid ATTRIBUTE_UNUSED,
    2593                 :            :                                 region_id child_rid,
    2594                 :            :                                 pretty_printer *pp) const
    2595                 :            : {
    2596                 :          0 :   function *fun = model.get_region<frame_region> (child_rid)->get_function ();
    2597                 :          0 :   pp_printf (pp, "frame for %qs: ", function_name (fun));
    2598                 :          0 : }
    2599                 :            : 
    2600                 :            : /* Implementation of region::validate vfunc for stack_region.  */
    2601                 :            : 
    2602                 :            : void
    2603                 :     368774 : stack_region::validate (const region_model &model) const
    2604                 :            : {
    2605                 :     368774 :   region::validate (model);
    2606                 :     368774 :   int i;
    2607                 :     368774 :   region_id *frame_rid;
    2608                 :     813297 :   FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
    2609                 :     444523 :     m_frame_rids[i].validate (model);
    2610                 :     368774 : }
    2611                 :            : 
    2612                 :            : /* Push FRAME_RID (for a frame_region) onto this stack.  */
    2613                 :            : 
    2614                 :            : void
    2615                 :     183398 : stack_region::push_frame (region_id frame_rid)
    2616                 :            : {
    2617                 :     183398 :   m_frame_rids.safe_push (frame_rid);
    2618                 :     183398 : }
    2619                 :            : 
    2620                 :            : /* Get the region_id of the top-most frame in this stack, if any.  */
    2621                 :            : 
    2622                 :            : region_id
    2623                 :      31578 : stack_region::get_current_frame_id () const
    2624                 :            : {
    2625                 :      31578 :   if (m_frame_rids.length () > 0)
    2626                 :      31578 :     return m_frame_rids[m_frame_rids.length () - 1];
    2627                 :            :   else
    2628                 :          0 :     return region_id::null ();
    2629                 :            : }
    2630                 :            : 
    2631                 :            : /* Pop the topmost frame_region from this stack.
    2632                 :            : 
    2633                 :            :    Purge the frame region and all its descendent regions.
    2634                 :            :    Convert any pointers that point into such regions into
    2635                 :            :    POISON_KIND_POPPED_STACK svalues.
    2636                 :            : 
    2637                 :            :    Return the ID of any return value from the frame.
    2638                 :            : 
    2639                 :            :    If PURGE, then purge all unused svalues, with the exception of any
    2640                 :            :    return value for the frame, which is temporarily
    2641                 :            :    preserved in case no regions reference it, so it can
    2642                 :            :    be written into a region in the caller.
    2643                 :            : 
    2644                 :            :    Accumulate stats on purged entities into STATS.  */
    2645                 :            : 
    2646                 :            : svalue_id
    2647                 :       1594 : stack_region::pop_frame (region_model *model, bool purge, purge_stats *stats,
    2648                 :            :                          region_model_context *ctxt)
    2649                 :            : {
    2650                 :       1594 :   gcc_assert (m_frame_rids.length () > 0);
    2651                 :            : 
    2652                 :       1594 :   region_id frame_rid = get_current_frame_id ();
    2653                 :       1594 :   frame_region *frame = model->get_region<frame_region> (frame_rid);
    2654                 :            : 
    2655                 :            :   /* Evaluate the result, within the callee frame.  */
    2656                 :       1594 :   svalue_id result_sid;
    2657                 :       1594 :   tree fndecl = frame->get_function ()->decl;
    2658                 :       1594 :   tree result = DECL_RESULT (fndecl);
    2659                 :       3186 :   if (result && TREE_TYPE (result) != void_type_node)
    2660                 :        597 :     result_sid = model->get_rvalue (result, ctxt);
    2661                 :            : 
    2662                 :            :   /* Pop the frame RID.  */
    2663                 :       1594 :   m_frame_rids.pop ();
    2664                 :            : 
    2665                 :       3074 :   model->delete_region_and_descendents (frame_rid,
    2666                 :            :                                         POISON_KIND_POPPED_STACK,
    2667                 :            :                                         stats,
    2668                 :       1480 :                                         ctxt ? ctxt->get_logger () : NULL);
    2669                 :            : 
    2670                 :            :   /* Delete unused svalues, but don't delete the return value.  */
    2671                 :       1594 :   if (purge)
    2672                 :       1579 :     model->purge_unused_svalues (stats, ctxt, &result_sid);
    2673                 :            : 
    2674                 :       1594 :   model->validate ();
    2675                 :            : 
    2676                 :       1594 :   return result_sid;
    2677                 :            : }
    2678                 :            : 
    2679                 :            : /* Implementation of region::add_to_hash vfunc for stack_region.  */
    2680                 :            : 
    2681                 :            : void
    2682                 :      92813 : stack_region::add_to_hash (inchash::hash &hstate) const
    2683                 :            : {
    2684                 :      92813 :   region::add_to_hash (hstate);
    2685                 :            : 
    2686                 :      92813 :   int i;
    2687                 :      92813 :   region_id *frame_rid;
    2688                 :     218190 :   FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
    2689                 :     125377 :     inchash::add (*frame_rid, hstate);
    2690                 :      92813 : }
    2691                 :            : 
    2692                 :            : /* Implementation of region::remap_region_ids vfunc for stack_region.  */
    2693                 :            : 
    2694                 :            : void
    2695                 :      89157 : stack_region::remap_region_ids (const region_id_map &map)
    2696                 :            : {
    2697                 :      89157 :   region::remap_region_ids (map);
    2698                 :      89157 :   int i;
    2699                 :      89157 :   region_id *frame_rid;
    2700                 :     209654 :   FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
    2701                 :     120497 :     map.update (&m_frame_rids[i]);
    2702                 :      89157 : }
    2703                 :            : 
    2704                 :            : /* Attempt to merge STACK_REGION_A and STACK_REGION_B using MERGER.
    2705                 :            :    Return true if the merger is possible, false otherwise.  */
    2706                 :            : 
    2707                 :            : bool
    2708                 :     173347 : stack_region::can_merge_p (const stack_region *stack_region_a,
    2709                 :            :                            const stack_region *stack_region_b,
    2710                 :            :                            model_merger *merger)
    2711                 :            : {
    2712                 :     346694 :   if (stack_region_a->get_num_frames ()
    2713                 :     173347 :       != stack_region_b->get_num_frames ())
    2714                 :            :     return false;
    2715                 :            : 
    2716                 :     173347 :   region_model *merged_model = merger->m_merged_model;
    2717                 :            : 
    2718                 :     173347 :   region_id rid_merged_stack
    2719                 :     173347 :     = merged_model->get_root_region ()->ensure_stack_region (merged_model);
    2720                 :            : 
    2721                 :     173347 :   stack_region *merged_stack
    2722                 :     173347 :     = merged_model->get_region <stack_region> (rid_merged_stack);
    2723                 :            : 
    2724                 :            :   /* First, create all frames in the merged model, without populating them.
    2725                 :            :      The merging code assumes that all frames in the merged model already exist,
    2726                 :            :      so we have to do this first to handle the case in which a local in an
    2727                 :            :      older frame points at a local in a more recent frame.  */
    2728                 :     709276 :     for (unsigned i = 0; i < stack_region_a->get_num_frames (); i++)
    2729                 :            :       {
    2730                 :     181291 :         region_id rid_a = stack_region_a->get_frame_rid (i);
    2731                 :     181291 :         frame_region *frame_a = merger->get_region_a <frame_region> (rid_a);
    2732                 :            : 
    2733                 :     181291 :         region_id rid_b = stack_region_b->get_frame_rid (i);
    2734                 :     181291 :         frame_region *frame_b = merger->get_region_b <frame_region> (rid_b);
    2735                 :            : 
    2736                 :     181291 :         if (frame_a->get_function () != frame_b->get_function ())
    2737                 :          0 :           return false;
    2738                 :            : 
    2739                 :     181291 :         frame_region *merged_frame = new frame_region (rid_merged_stack,
    2740                 :     181291 :                                                        frame_a->get_function (),
    2741                 :     181291 :                                                        frame_a->get_depth ());
    2742                 :     181291 :         region_id rid_merged_frame = merged_model->add_region (merged_frame);
    2743                 :     181291 :         merged_stack->push_frame (rid_merged_frame);
    2744                 :            :       }
    2745                 :            : 
    2746                 :            :     /* Now populate the frames we created.  */
    2747                 :     686068 :     for (unsigned i = 0; i < stack_region_a->get_num_frames (); i++)
    2748                 :            :       {
    2749                 :     176897 :         region_id rid_a = stack_region_a->get_frame_rid (i);
    2750                 :     176897 :         frame_region *frame_a = merger->get_region_a <frame_region> (rid_a);
    2751                 :            : 
    2752                 :     176897 :         region_id rid_b = stack_region_b->get_frame_rid (i);
    2753                 :     176897 :         frame_region *frame_b = merger->get_region_b <frame_region> (rid_b);
    2754                 :            : 
    2755                 :     176897 :         region_id rid_merged_frame = merged_stack->get_frame_rid (i);
    2756                 :     176897 :         frame_region *merged_frame
    2757                 :     176897 :           = merged_model->get_region <frame_region> (rid_merged_frame);
    2758                 :     176897 :         if (!map_region::can_merge_p (frame_a, frame_b,
    2759                 :            :                                       merged_frame, rid_merged_frame,
    2760                 :            :                                       merger))
    2761                 :       7210 :           return false;
    2762                 :            :       }
    2763                 :            : 
    2764                 :            :   return true;
    2765                 :            : }
    2766                 :            : 
    2767                 :            : /* Implementation of region::walk_for_canonicalization vfunc for
    2768                 :            :    stack_region.  */
    2769                 :            : 
    2770                 :            : void
    2771                 :      59388 : stack_region::walk_for_canonicalization (canonicalization *c) const
    2772                 :            : {
    2773                 :      59388 :   int i;
    2774                 :      59388 :   region_id *frame_rid;
    2775                 :     140353 :   FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
    2776                 :      80965 :     c->walk_rid (*frame_rid);
    2777                 :      59388 : }
    2778                 :            : 
    2779                 :            : /* For debugging purposes: look for a grandchild region within one of
    2780                 :            :    the child frame regions, where the grandchild is for a decl named
    2781                 :            :    IDENTIFIER (or an SSA_NAME for such a decl):
    2782                 :            : 
    2783                 :            :      stack_region
    2784                 :            :      `-frame_region
    2785                 :            :        `-region for decl named IDENTIFIER
    2786                 :            : 
    2787                 :            :    returning its value, or svalue_id::null if none are found.  */
    2788                 :            : 
    2789                 :            : svalue_id
    2790                 :          2 : stack_region::get_value_by_name (tree identifier,
    2791                 :            :                                  const region_model &model) const
    2792                 :            : {
    2793                 :          2 :   int i;
    2794                 :          2 :   region_id *frame_rid;
    2795                 :          2 :   FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
    2796                 :            :     {
    2797                 :          2 :       frame_region *frame = model.get_region<frame_region> (*frame_rid);
    2798                 :          2 :       svalue_id sid = frame->get_value_by_name (identifier, model);
    2799                 :          2 :       if (!sid.null_p ())
    2800                 :          2 :         return sid;
    2801                 :            :     }
    2802                 :            : 
    2803                 :          0 :   return svalue_id::null ();
    2804                 :            : }
    2805                 :            : 
    2806                 :            : /* class heap_region : public region.  */
    2807                 :            : 
    2808                 :            : /* heap_region's copy ctor.  */
    2809                 :            : 
    2810                 :      39205 : heap_region::heap_region (const heap_region &other)
    2811                 :      39205 : : region (other)
    2812                 :            : {
    2813                 :      39205 : }
    2814                 :            : 
    2815                 :            : /* Compare the fields of this heap_region with OTHER, returning true
    2816                 :            :    if they are equal.
    2817                 :            :    For use by region::operator==.  */
    2818                 :            : 
    2819                 :            : bool
    2820                 :       7108 : heap_region::compare_fields (const heap_region &) const
    2821                 :            : {
    2822                 :            :   /* Empty.  */
    2823                 :       7108 :   return true;
    2824                 :            : }
    2825                 :            : 
    2826                 :            : /* Implementation of region::clone vfunc for heap_region.  */
    2827                 :            : 
    2828                 :            : region *
    2829                 :      39205 : heap_region::clone () const
    2830                 :            : {
    2831                 :      39205 :   return new heap_region (*this);
    2832                 :            : }
    2833                 :            : 
    2834                 :            : /* Implementation of region::walk_for_canonicalization vfunc for
    2835                 :            :    heap_region.  */
    2836                 :            : 
    2837                 :            : void
    2838                 :      15562 : heap_region::walk_for_canonicalization (canonicalization *) const
    2839                 :            : {
    2840                 :            :   /* Empty.  */
    2841                 :      15562 : }
    2842                 :            : 
    2843                 :            : /* class root_region : public region.  */
    2844                 :            : 
    2845                 :            : /* root_region's default ctor.  */
    2846                 :            : 
    2847                 :     175497 : root_region::root_region ()
    2848                 :            : : region (region_id::null (),
    2849                 :            :           svalue_id::null (),
    2850                 :     175497 :           NULL_TREE)
    2851                 :            : {
    2852                 :     175497 : }
    2853                 :            : 
    2854                 :            : /* root_region's copy ctor.  */
    2855                 :            : 
    2856                 :     162761 : root_region::root_region (const root_region &other)
    2857                 :            : : region (other),
    2858                 :            :   m_stack_rid (other.m_stack_rid),
    2859                 :            :   m_globals_rid (other.m_globals_rid),
    2860                 :            :   m_code_rid (other.m_code_rid),
    2861                 :     162761 :   m_heap_rid (other.m_heap_rid)
    2862                 :            : {
    2863                 :     162761 : }
    2864                 :            : 
    2865                 :            : /* Compare the fields of this root_region with OTHER, returning true
    2866                 :            :    if they are equal.
    2867                 :            :    For use by region::operator==.  */
    2868                 :            : 
    2869                 :            : bool
    2870                 :      31894 : root_region::compare_fields (const root_region &other) const
    2871                 :            : {
    2872                 :      31894 :   if (m_stack_rid != other.m_stack_rid)
    2873                 :            :     return false;
    2874                 :      31894 :   if (m_globals_rid != other.m_globals_rid)
    2875                 :            :     return false;
    2876                 :      31894 :   if (m_code_rid != other.m_code_rid)
    2877                 :            :     return false;
    2878                 :      31894 :   if (m_heap_rid != other.m_heap_rid)
    2879                 :          7 :     return false;
    2880                 :            :   return true;
    2881                 :            : }
    2882                 :            : 
    2883                 :            : /* Implementation of region::clone vfunc for root_region.  */
    2884                 :            : 
    2885                 :            : region *
    2886                 :     162761 : root_region::clone () const
    2887                 :            : {
    2888                 :     162761 :   return new root_region (*this);
    2889                 :            : }
    2890                 :            : 
    2891                 :            : /* Implementation of region::print_fields vfunc for root_region.  */
    2892                 :            : 
    2893                 :            : void
    2894                 :         10 : root_region::print_fields (const region_model &model,
    2895                 :            :                            region_id this_rid,
    2896                 :            :                            pretty_printer *pp) const
    2897                 :            : {
    2898                 :         10 :   region::print_fields (model, this_rid, pp);
    2899                 :            :   // TODO
    2900                 :         10 : }
    2901                 :            : 
    2902                 :            : /* Implementation of region::validate vfunc for root_region.  */
    2903                 :            : 
    2904                 :            : void
    2905                 :     370955 : root_region::validate (const region_model &model) const
    2906                 :            : {
    2907                 :     370955 :   region::validate (model);
    2908                 :     370955 :   m_stack_rid.validate (model);
    2909                 :     370955 :   m_globals_rid.validate (model);
    2910                 :     370955 :   m_code_rid.validate (model);
    2911                 :     370955 :   m_heap_rid.validate (model);
    2912                 :     370955 : }
    2913                 :            : 
    2914                 :            : /* Implementation of region::dump_child_label vfunc for root_region.  */
    2915                 :            : 
    2916                 :            : void
    2917                 :         18 : root_region::dump_child_label (const region_model &model ATTRIBUTE_UNUSED,
    2918                 :            :                                region_id this_rid ATTRIBUTE_UNUSED,
    2919                 :            :                                region_id child_rid,
    2920                 :            :                                pretty_printer *pp) const
    2921                 :            : {
    2922                 :         18 :   if (child_rid == m_stack_rid)
    2923                 :          2 :     pp_printf (pp, "stack: ");
    2924                 :         16 :   else if (child_rid == m_globals_rid)
    2925                 :         10 :     pp_printf (pp, "globals: ");
    2926                 :          6 :   else if (child_rid == m_code_rid)
    2927                 :          0 :     pp_printf (pp, "code: ");
    2928                 :          6 :   else if (child_rid == m_heap_rid)
    2929                 :          4 :     pp_printf (pp, "heap: ");
    2930                 :         18 : }
    2931                 :            : 
    2932                 :            : /* Create a new frame_region for a call to FUN and push it onto
    2933                 :            :    the stack.
    2934                 :            : 
    2935                 :            :    If ARG_SIDS is non-NULL, use it to populate the parameters
    2936                 :            :    in the new frame.
    2937                 :            :    Otherwise, populate them with unknown values.
    2938                 :            : 
    2939                 :            :    Return the region_id of the new frame.  */
    2940                 :            : 
    2941                 :            : region_id
    2942                 :       2107 : root_region::push_frame (region_model *model, function *fun,
    2943                 :            :                          vec<svalue_id> *arg_sids,
    2944                 :            :                          region_model_context *ctxt)
    2945                 :            : {
    2946                 :       2107 :   gcc_assert (fun);
    2947                 :            :   /* arg_sids can be NULL.  */
    2948                 :            : 
    2949                 :       2107 :   ensure_stack_region (model);
    2950                 :       2107 :   stack_region *stack = model->get_region <stack_region> (m_stack_rid);
    2951                 :            : 
    2952                 :       2107 :   frame_region *region = new frame_region (m_stack_rid, fun,
    2953                 :       2107 :                                            stack->get_num_frames ());
    2954                 :       2107 :   region_id frame_rid = model->add_region (region);
    2955                 :            : 
    2956                 :            :   // TODO: unify these cases by building a vec of unknown?
    2957                 :            : 
    2958                 :       2107 :   if (arg_sids)
    2959                 :            :     {
    2960                 :            :       /* Arguments supplied from a caller frame.  */
    2961                 :            : 
    2962                 :        693 :       tree fndecl = fun->decl;
    2963                 :        693 :       unsigned idx = 0;
    2964                 :       2443 :       for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
    2965                 :        875 :            iter_parm = DECL_CHAIN (iter_parm), ++idx)
    2966                 :            :         {
    2967                 :            :           /* If there's a mismatching declaration, the call stmt might
    2968                 :            :              not have enough args.  Handle this case by leaving the
    2969                 :            :              rest of the params as uninitialized.  */
    2970                 :       1753 :           if (idx >= arg_sids->length ())
    2971                 :            :             break;
    2972                 :        875 :           svalue_id arg_sid = (*arg_sids)[idx];
    2973                 :        875 :           region_id parm_rid
    2974                 :            :             = region->get_or_create (model, frame_rid, iter_parm,
    2975                 :        875 :                                      TREE_TYPE (iter_parm), ctxt);
    2976                 :        875 :           model->set_value (parm_rid, arg_sid, ctxt);
    2977                 :            : 
    2978                 :            :           /* Also do it for default SSA name (sharing the same unknown
    2979                 :            :              value).  */
    2980                 :        875 :           tree parm_default_ssa = ssa_default_def (fun, iter_parm);
    2981                 :        875 :           if (parm_default_ssa)
    2982                 :            :             {
    2983                 :        551 :               region_id defssa_rid
    2984                 :            :                 = region->get_or_create (model, frame_rid, parm_default_ssa,
    2985                 :        551 :                                          TREE_TYPE (iter_parm), ctxt);
    2986                 :        551 :               model->set_value (defssa_rid, arg_sid, ctxt);
    2987                 :            :             }
    2988                 :            :         }
    2989                 :            :     }
    2990                 :            :   else
    2991                 :            :     {
    2992                 :            :       /* No known arguments (a top-level call within the analysis).  */
    2993                 :            : 
    2994                 :            :       /* Params have a defined, unknown value; they should not inherit
    2995                 :            :          from the poisoned uninit value.  */
    2996                 :       1414 :       tree fndecl = fun->decl;
    2997                 :       3882 :       for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
    2998                 :       1234 :            iter_parm = DECL_CHAIN (iter_parm))
    2999                 :            :         {
    3000                 :       1234 :           region_id parm_rid
    3001                 :            :             = region->get_or_create (model, frame_rid, iter_parm,
    3002                 :       1234 :                                      TREE_TYPE (iter_parm), ctxt);
    3003                 :       1234 :           svalue_id parm_sid
    3004                 :       1234 :             = model->set_to_new_unknown_value (parm_rid, TREE_TYPE (iter_parm),
    3005                 :       1234 :                                                ctxt);
    3006                 :            : 
    3007                 :            :           /* Also do it for default SSA name (sharing the same unknown
    3008                 :            :              value).  */
    3009                 :       1234 :           tree parm_default_ssa = ssa_default_def (fun, iter_parm);
    3010                 :       1234 :           if (parm_default_ssa)
    3011                 :            :             {
    3012                 :       1007 :               region_id defssa_rid
    3013                 :            :                 = region->get_or_create (model, frame_rid, parm_default_ssa,
    3014                 :       1007 :                                          TREE_TYPE (iter_parm), ctxt);
    3015                 :       1007 :               model->get_region (defssa_rid)->set_value (*model, defssa_rid,
    3016                 :            :                                                          parm_sid, ctxt);
    3017                 :            :             }
    3018                 :            :         }
    3019                 :            :     }
    3020                 :            : 
    3021                 :       2107 :   stack->push_frame (frame_rid);
    3022                 :            : 
    3023                 :       2107 :   return frame_rid;
    3024                 :            : }
    3025                 :            : 
    3026                 :            : /* Get the region_id of the top-most frame in this root_region's stack,
    3027                 :            :    if any.  */
    3028                 :            : 
    3029                 :            : region_id
    3030                 :      29984 : root_region::get_current_frame_id (const region_model &model) const
    3031                 :            : {
    3032                 :      29984 :   stack_region *stack = model.get_region <stack_region> (m_stack_rid);
    3033                 :      29984 :   if (stack)
    3034                 :      29984 :     return stack->get_current_frame_id ();
    3035                 :            :   else
    3036                 :          0 :     return region_id::null ();
    3037                 :            : }
    3038                 :            : 
    3039                 :            : /* Pop the topmost frame_region from this root_region's stack;
    3040                 :            :    see the comment for stack_region::pop_frame.  */
    3041                 :            : 
    3042                 :            : svalue_id
    3043                 :       1594 : root_region::pop_frame (region_model *model, bool purge, purge_stats *out,
    3044                 :            :                         region_model_context *ctxt)
    3045                 :            : {
    3046                 :       1594 :   stack_region *stack = model->get_region <stack_region> (m_stack_rid);
    3047                 :       1594 :   return stack->pop_frame (model, purge, out, ctxt);
    3048                 :            : }
    3049                 :            : 
    3050                 :            : /* Return the region_id of the stack region, creating it if doesn't
    3051                 :            :    already exist.  */
    3052                 :            : 
    3053                 :            : region_id
    3054                 :     348807 : root_region::ensure_stack_region (region_model *model)
    3055                 :            : {
    3056                 :     348807 :   if (m_stack_rid.null_p ())
    3057                 :            :     {
    3058                 :     174755 :       svalue_id uninit_sid
    3059                 :            :         = model->add_svalue (new poisoned_svalue (POISON_KIND_UNINIT,
    3060                 :     174755 :                                                   NULL_TREE));
    3061                 :     174755 :       m_stack_rid
    3062                 :     174755 :         = model->add_region (new stack_region (model->get_root_rid (),
    3063                 :     174755 :                                                uninit_sid));
    3064                 :            :     }
    3065                 :     348807 :   return m_stack_rid;
    3066                 :            : }
    3067                 :            : 
    3068                 :            : /* Return the stack region (which could be NULL).  */
    3069                 :            : 
    3070                 :            : stack_region *
    3071                 :    1814990 : root_region::get_stack_region (const region_model *model) const
    3072                 :            : {
    3073                 :    1814990 :   return model->get_region <stack_region> (m_stack_rid);
    3074                 :            : }
    3075                 :            : 
    3076                 :            : /* Return the region_id of the globals region, creating it if doesn't
    3077                 :            :    already exist.  */
    3078                 :            : 
    3079                 :            : region_id
    3080                 :       8860 : root_region::ensure_globals_region (region_model *model)
    3081                 :            : {
    3082                 :       8860 :   if (m_globals_rid.null_p ())
    3083                 :       5722 :     m_globals_rid
    3084                 :       5722 :       = model->add_region (new globals_region (model->get_root_rid ()));
    3085                 :       8860 :   return m_globals_rid;
    3086                 :            : }
    3087                 :            : 
    3088                 :            : /* Return the code region (which could be NULL).  */
    3089                 :            : 
    3090                 :            : code_region *
    3091                 :     561720 : root_region::get_code_region (const region_model *model) const
    3092                 :            : {
    3093                 :     561720 :   return model->get_region <code_region> (m_code_rid);
    3094                 :            : }
    3095                 :            : 
    3096                 :            : /* Return the region_id of the code region, creating it if doesn't
    3097                 :            :    already exist.  */
    3098                 :            : 
    3099                 :            : region_id
    3100                 :     195301 : root_region::ensure_code_region (region_model *model)
    3101                 :            : {
    3102                 :     195301 :   if (m_code_rid.null_p ())
    3103                 :     160516 :     m_code_rid
    3104                 :     160516 :       = model->add_region (new code_region (model->get_root_rid ()));
    3105                 :     195301 :   return m_code_rid;
    3106                 :            : }
    3107                 :            : 
    3108                 :            : /* Return the globals region (which could be NULL).  */
    3109                 :            : 
    3110                 :            : globals_region *
    3111                 :     338051 : root_region::get_globals_region (const region_model *model) const
    3112                 :            : {
    3113                 :     338051 :   return model->get_region <globals_region> (m_globals_rid);
    3114                 :            : }
    3115                 :            : 
    3116                 :            : /* Return the region_id of the heap region, creating it if doesn't
    3117                 :            :    already exist.  */
    3118                 :            : 
    3119                 :            : region_id
    3120                 :     289001 : root_region::ensure_heap_region (region_model *model)
    3121                 :            : {
    3122                 :     289001 :   if (m_heap_rid.null_p ())
    3123                 :            :     {
    3124                 :     135038 :       svalue_id uninit_sid
    3125                 :            :         = model->add_svalue (new poisoned_svalue (POISON_KIND_UNINIT,
    3126                 :     135038 :                                                   NULL_TREE));
    3127                 :     135038 :       m_heap_rid
    3128                 :     135038 :         = model->add_region (new heap_region (model->get_root_rid (),
    3129                 :     135038 :                                               uninit_sid));
    3130                 :            :     }
    3131                 :     289001 :   return m_heap_rid;
    3132                 :            : }
    3133                 :            : 
    3134                 :            : /* Return the heap region (which could be NULL).  */
    3135                 :            : 
    3136                 :            : heap_region *
    3137                 :     330694 : root_region::get_heap_region (const region_model *model) const
    3138                 :            : {
    3139                 :     330694 :   return model->get_region <heap_region> (m_heap_rid);
    3140                 :            : }
    3141                 :            : 
    3142                 :            : /* Implementation of region::remap_region_ids vfunc for root_region.  */
    3143                 :            : 
    3144                 :            : void
    3145                 :      89714 : root_region::remap_region_ids (const region_id_map &map)
    3146                 :            : {
    3147                 :      89714 :   map.update (&m_stack_rid);
    3148                 :      89714 :   map.update (&m_globals_rid);
    3149                 :      89714 :   map.update (&m_code_rid);
    3150                 :      89714 :   map.update (&m_heap_rid);
    3151                 :      89714 : }
    3152                 :            : 
    3153                 :            : /* Attempt to merge ROOT_REGION_A and ROOT_REGION_B into
    3154                 :            :    MERGED_ROOT_REGION using MERGER.
    3155                 :            :    Return true if the merger is possible, false otherwise.  */
    3156                 :            : 
    3157                 :            : bool
    3158                 :     173457 : root_region::can_merge_p (const root_region *root_region_a,
    3159                 :            :                           const root_region *root_region_b,
    3160                 :            :                           root_region *merged_root_region,
    3161                 :            :                           model_merger *merger)
    3162                 :            : {
    3163                 :            :   /* We can only merge if the stacks are sufficiently similar.  */
    3164                 :     173457 :   stack_region *stack_a = root_region_a->get_stack_region (merger->m_model_a);
    3165                 :     173457 :   stack_region *stack_b = root_region_b->get_stack_region (merger->m_model_b);
    3166                 :     173457 :   if (stack_a && stack_b)
    3167                 :            :     {
    3168                 :            :       /* If the two models both have a stack, attempt to merge them.  */
    3169                 :     173347 :       merged_root_region->ensure_stack_region (merger->m_merged_model);
    3170                 :     173347 :       if (!stack_region::can_merge_p (stack_a, stack_b, merger))
    3171                 :            :         return false;
    3172                 :            :     }
    3173                 :        110 :   else if (stack_a || stack_b)
    3174                 :            :     /* Don't attempt to merge if one model has a stack and the other
    3175                 :            :        doesn't.  */
    3176                 :            :     return false;
    3177                 :            : 
    3178                 :     166247 :   map_region *globals_a = root_region_a->get_globals_region (merger->m_model_a);
    3179                 :     166247 :   map_region *globals_b = root_region_b->get_globals_region (merger->m_model_b);
    3180                 :     166247 :   if (globals_a && globals_b)
    3181                 :            :     {
    3182                 :            :       /* If both models have globals regions, attempt to merge them.  */
    3183                 :       5266 :       region_id merged_globals_rid
    3184                 :       5266 :         = merged_root_region->ensure_globals_region (merger->m_merged_model);
    3185                 :       5266 :       map_region *merged_globals
    3186                 :       5266 :         = merged_root_region->get_globals_region (merger->m_merged_model);
    3187                 :       5266 :       if (!map_region::can_merge_p (globals_a, globals_b,
    3188                 :            :                                     merged_globals, merged_globals_rid,
    3189                 :            :                                     merger))
    3190                 :        900 :         return false;
    3191                 :            :     }
    3192                 :            :   /* otherwise, merge as "no globals".  */
    3193                 :            : 
    3194                 :     165347 :   map_region *code_a = root_region_a->get_code_region (merger->m_model_a);
    3195                 :     165347 :   map_region *code_b = root_region_b->get_code_region (merger->m_model_b);
    3196                 :     165347 :   if (code_a && code_b)
    3197                 :            :     {
    3198                 :            :       /* If both models have code regions, attempt to merge them.  */
    3199                 :     159711 :       region_id merged_code_rid
    3200                 :     159711 :         = merged_root_region->ensure_code_region (merger->m_merged_model);
    3201                 :     159711 :       map_region *merged_code
    3202                 :     159711 :         = merged_root_region->get_code_region (merger->m_merged_model);
    3203                 :     159711 :       if (!map_region::can_merge_p (code_a, code_b,
    3204                 :            :                                     merged_code, merged_code_rid,
    3205                 :            :                                     merger))
    3206                 :          0 :         return false;
    3207                 :            :     }
    3208                 :            :   /* otherwise, merge as "no code".  */
    3209                 :            : 
    3210                 :     165347 :   heap_region *heap_a = root_region_a->get_heap_region (merger->m_model_a);
    3211                 :     165347 :   heap_region *heap_b = root_region_b->get_heap_region (merger->m_model_b);
    3212                 :     165347 :   if (heap_a && heap_b)
    3213                 :            :     {
    3214                 :            :       /* If both have a heap, create a "merged" heap.
    3215                 :            :          Actually merging the heap contents happens via the region_svalue
    3216                 :            :          instances, as needed, when seeing pairs of region_svalue instances.  */
    3217                 :     134842 :       merged_root_region->ensure_heap_region (merger->m_merged_model);
    3218                 :            :     }
    3219                 :            :   /* otherwise, merge as "no heap".  */
    3220                 :            : 
    3221                 :            :   return true;
    3222                 :            : }
    3223                 :            : 
    3224                 :            : /* Implementation of region::add_to_hash vfunc for root_region.  */
    3225                 :            : 
    3226                 :            : void
    3227                 :      94200 : root_region::add_to_hash (inchash::hash &hstate) const
    3228                 :            : {
    3229                 :      94200 :   region::add_to_hash (hstate);
    3230                 :      94200 :   inchash::add (m_stack_rid, hstate);
    3231                 :      94200 :   inchash::add (m_globals_rid, hstate);
    3232                 :      94200 :   inchash::add (m_code_rid, hstate);
    3233                 :      94200 :   inchash::add (m_heap_rid, hstate);
    3234                 :      94200 : }
    3235                 :            : 
    3236                 :            : /* Implementation of region::walk_for_canonicalization vfunc for
    3237                 :            :    root_region.  */
    3238                 :            : 
    3239                 :            : void
    3240                 :      59945 : root_region::walk_for_canonicalization (canonicalization *c) const
    3241                 :            : {
    3242                 :      59945 :   c->walk_rid (m_stack_rid);
    3243                 :      59945 :   c->walk_rid (m_globals_rid);
    3244                 :      59945 :   c->walk_rid (m_code_rid);
    3245                 :      59945 :   c->walk_rid (m_heap_rid);
    3246                 :      59945 : }
    3247                 :            : 
    3248                 :            : /* For debugging purposes: look for a descendant region for a local
    3249                 :            :    or global decl named IDENTIFIER (or an SSA_NAME for such a decl),
    3250                 :            :    returning its value, or svalue_id::null if none are found.  */
    3251                 :            : 
    3252                 :            : svalue_id
    3253                 :          4 : root_region::get_value_by_name (tree identifier,
    3254                 :            :                                 const region_model &model) const
    3255                 :            : {
    3256                 :          4 :   if (stack_region *stack = get_stack_region (&model))
    3257                 :            :     {
    3258                 :          2 :       svalue_id sid = stack->get_value_by_name (identifier, model);
    3259                 :          2 :       if (!sid.null_p ())
    3260                 :          2 :         return sid;
    3261                 :            :     }
    3262                 :          2 :   if (map_region *globals = get_globals_region (&model))
    3263                 :            :     {
    3264                 :          2 :       svalue_id sid = globals->get_value_by_name (identifier, model);
    3265                 :          2 :       if (!sid.null_p ())
    3266                 :          2 :         return sid;
    3267                 :            :     }
    3268                 :          0 :   return svalue_id::null ();
    3269                 :            : }
    3270                 :            : 
    3271                 :            : /* class symbolic_region : public map_region.  */
    3272                 :            : 
    3273                 :            : /* symbolic_region's copy ctor.  */
    3274                 :            : 
    3275                 :     139906 : symbolic_region::symbolic_region (const symbolic_region &other)
    3276                 :            : : region (other),
    3277                 :     139906 :   m_possibly_null (other.m_possibly_null)
    3278                 :            : {
    3279                 :     139906 : }
    3280                 :            : 
    3281                 :            : /* Compare the fields of this symbolic_region with OTHER, returning true
    3282                 :            :    if they are equal.
    3283                 :            :    For use by region::operator==.  */
    3284                 :            : 
    3285                 :            : bool
    3286                 :      24312 : symbolic_region::compare_fields (const symbolic_region &other) const
    3287                 :            : {
    3288                 :      24312 :   return m_possibly_null == other.m_possibly_null;
    3289                 :            : }
    3290                 :            : 
    3291                 :            : /* Implementation of region::clone vfunc for symbolic_region.  */
    3292                 :            : 
    3293                 :            : region *
    3294                 :     139906 : symbolic_region::clone () const
    3295                 :            : {
    3296                 :     139906 :   return new symbolic_region (*this);
    3297                 :            : }
    3298                 :            : 
    3299                 :            : /* Implementation of region::walk_for_canonicalization vfunc for
    3300                 :            :    symbolic_region.  */
    3301                 :            : 
    3302                 :            : void
    3303                 :      52223 : symbolic_region::walk_for_canonicalization (canonicalization *) const
    3304                 :            : {
    3305                 :            :   /* Empty.  */
    3306                 :      52223 : }
    3307                 :            : 
    3308                 :            : /* Implementation of region::print_fields vfunc for symbolic_region.  */
    3309                 :            : 
    3310                 :            : void
    3311                 :          2 : symbolic_region::print_fields (const region_model &model,
    3312                 :            :                                region_id this_rid,
    3313                 :            :                                pretty_printer *pp) const
    3314                 :            : {
    3315                 :          2 :   region::print_fields (model, this_rid, pp);
    3316                 :          2 :   pp_printf (pp, ", possibly_null: %s", m_possibly_null ? "true" : "false");
    3317                 :          2 : }
    3318                 :            : 
    3319                 :            : /* class region_model.  */
    3320                 :            : 
    3321                 :            : /* region_model's default ctor.  */
    3322                 :            : 
    3323                 :     175497 : region_model::region_model ()
    3324                 :            : {
    3325                 :     175497 :   m_root_rid = add_region (new root_region ());
    3326                 :     175497 :   m_constraints = new impl_constraint_manager (this);
    3327                 :            :   // TODO
    3328                 :     175497 : }
    3329                 :            : 
    3330                 :            : /* region_model's copy ctor.  */
    3331                 :            : 
    3332                 :     162746 : region_model::region_model (const region_model &other)
    3333                 :     162746 : : m_svalues (other.m_svalues.length ()),
    3334                 :     162746 :   m_regions (other.m_regions.length ()),
    3335                 :     323983 :   m_root_rid (other.m_root_rid)
    3336                 :            : {
    3337                 :            :   /* Clone the svalues and regions.  */
    3338                 :     162746 :   int i;
    3339                 :            : 
    3340                 :     162746 :   svalue *svalue;
    3341                 :    1629970 :   FOR_EACH_VEC_ELT (other.m_svalues, i, svalue)
    3342                 :    1467220 :     m_svalues.quick_push (svalue->clone ());
    3343                 :            : 
    3344                 :            :   region *region;
    3345                 :    2736490 :   FOR_EACH_VEC_ELT (other.m_regions, i, region)
    3346                 :    2573740 :     m_regions.quick_push (region->clone ());
    3347                 :            : 
    3348                 :     162746 :   m_constraints = other.m_constraints->clone (this);
    3349                 :     162746 : }
    3350                 :            : 
    3351                 :            : /* region_model's dtor.  */
    3352                 :            : 
    3353                 :     338243 : region_model::~region_model ()
    3354                 :            : {
    3355                 :     338243 :   delete m_constraints;
    3356                 :     338243 : }
    3357                 :            : 
    3358                 :            : /* region_model's assignment operator.  */
    3359                 :            : 
    3360                 :            : region_model &
    3361                 :         15 : region_model::operator= (const region_model &other)
    3362                 :            : {
    3363                 :         15 :   unsigned i;
    3364                 :         15 :   svalue *svalue;
    3365                 :         15 :   region *region;
    3366                 :            : 
    3367                 :            :   /* Delete existing content.  */
    3368                 :         38 :   FOR_EACH_VEC_ELT (m_svalues, i, svalue)
    3369                 :         23 :     delete svalue;
    3370                 :         15 :   m_svalues.truncate (0);
    3371                 :            : 
    3372                 :         63 :   FOR_EACH_VEC_ELT (m_regions, i, region)
    3373                 :         48 :     delete region;
    3374                 :         15 :   m_regions.truncate (0);
    3375                 :            : 
    3376                 :         15 :   delete m_constraints;
    3377                 :            : 
    3378                 :            :   /* Clone the svalues and regions.  */
    3379                 :         15 :   m_svalues.reserve (other.m_svalues.length (), true);
    3380                 :         15 :   FOR_EACH_VEC_ELT (other.m_svalues, i, svalue)
    3381                 :          0 :     m_svalues.quick_push (svalue->clone ());
    3382                 :            : 
    3383                 :         15 :   m_regions.reserve (other.m_regions.length (), true);
    3384                 :         30 :   FOR_EACH_VEC_ELT (other.m_regions, i, region)
    3385                 :         15 :     m_regions.quick_push (region->clone ());
    3386                 :            : 
    3387                 :         15 :   m_root_rid = other.m_root_rid;
    3388                 :            : 
    3389                 :         15 :   m_constraints = other.m_constraints->clone (this);
    3390                 :            : 
    3391                 :         15 :   return *this;
    3392                 :            : }
    3393                 :            : 
    3394                 :            : /* Equality operator for region_model.
    3395                 :            : 
    3396                 :            :    Amongst other things this directly compares the svalue and region
    3397                 :            :    vectors and so for this to be meaningful both this and OTHER should
    3398                 :            :    have been canonicalized.  */
    3399                 :            : 
    3400                 :            : bool
    3401                 :      40049 : region_model::operator== (const region_model &other) const
    3402                 :            : {
    3403                 :      40049 :   if (m_root_rid != other.m_root_rid)
    3404                 :            :     return false;
    3405                 :            : 
    3406                 :     119361 :   if (m_svalues.length () != other.m_svalues.length ())
    3407                 :            :     return false;
    3408                 :            : 
    3409                 :     101778 :   if (m_regions.length () != other.m_regions.length ())
    3410                 :            :     return false;
    3411                 :            : 
    3412                 :      32925 :   if (*m_constraints != *other.m_constraints)
    3413                 :            :     return false;
    3414                 :            : 
    3415                 :            :   unsigned i;
    3416                 :            :   svalue *svalue;
    3417                 :     303721 :   FOR_EACH_VEC_ELT (other.m_svalues, i, svalue)
    3418                 :     271827 :     if (!(*m_svalues[i] == *other.m_svalues[i]))
    3419                 :            :       return false;
    3420                 :            : 
    3421                 :            :   region *region;
    3422                 :     469522 :   FOR_EACH_VEC_ELT (other.m_regions, i, region)
    3423                 :     440689 :     if (!(*m_regions[i] == *other.m_regions[i]))
    3424                 :            :       return false;
    3425                 :            : 
    3426                 :      28833 :   gcc_checking_assert (hash () == other.hash ());
    3427                 :            : 
    3428                 :            :   return true;
    3429                 :            : }
    3430                 :            : 
    3431                 :            : /* Generate a hash value for this region_model.  */
    3432                 :            : 
    3433                 :            : hashval_t
    3434                 :      94200 : region_model::hash () const
    3435                 :            : {
    3436                 :      94200 :   hashval_t result = 0;
    3437                 :      94200 :   int i;
    3438                 :            : 
    3439                 :      94200 :   svalue *svalue;
    3440                 :     902377 :   FOR_EACH_VEC_ELT (m_svalues, i, svalue)
    3441                 :     808177 :     result ^= svalue->hash ();
    3442                 :            : 
    3443                 :            :   region *region;
    3444                 :    1496740 :   FOR_EACH_VEC_ELT (m_regions, i, region)
    3445                 :    1402540 :     result ^= region->hash ();
    3446                 :            : 
    3447                 :      94200 :   result ^= m_constraints->hash ();
    3448                 :            : 
    3449                 :      94200 :   return result;
    3450                 :            : }
    3451                 :            : 
    3452                 :            : /* Print an all-on-one-line representation of this region_model to PP,
    3453                 :            :    which must support %E for trees.  */
    3454                 :            : 
    3455                 :            : void
    3456                 :          0 : region_model::print (pretty_printer *pp) const
    3457                 :            : {
    3458                 :          0 :   int i;
    3459                 :            : 
    3460                 :          0 :   pp_string (pp, "svalues: [");
    3461                 :          0 :   svalue *svalue;
    3462                 :          0 :   FOR_EACH_VEC_ELT (m_svalues, i, svalue)
    3463                 :            :     {
    3464                 :          0 :       if (i > 0)
    3465                 :          0 :         pp_string (pp, ", ");
    3466                 :          0 :       print_svalue (svalue_id::from_int (i), pp);
    3467                 :            :     }
    3468                 :            : 
    3469                 :          0 :   pp_string (pp, "], regions: [");
    3470                 :            : 
    3471                 :          0 :   region *region;
    3472                 :          0 :   FOR_EACH_VEC_ELT (m_regions, i, region)
    3473                 :            :     {
    3474                 :          0 :       if (i > 0)
    3475                 :          0 :         pp_string (pp, ", ");
    3476                 :          0 :       region->print (*this, region_id::from_int (i), pp);
    3477                 :            :     }
    3478                 :            : 
    3479                 :          0 :   pp_string (pp, "], constraints: ");
    3480                 :            : 
    3481                 :          0 :   m_constraints->print (pp);
    3482                 :          0 : }
    3483                 :            : 
    3484                 :            : /* Print the svalue with id SID to PP.  */
    3485                 :            : 
    3486                 :            : void
    3487                 :         24 : region_model::print_svalue (svalue_id sid, pretty_printer *pp) const
    3488                 :            : {
    3489                 :         24 :   get_svalue (sid)->print (*this, sid, pp);
    3490                 :         24 : }
    3491                 :            : 
    3492                 :            : /* Dump a .dot representation of this region_model to PP, showing
    3493                 :            :    the values and the hierarchy of regions.  */
    3494                 :            : 
    3495                 :            : void
    3496                 :          0 : region_model::dump_dot_to_pp (pretty_printer *pp) const
    3497                 :            : {
    3498                 :          0 :   graphviz_out gv (pp);
    3499                 :            : 
    3500                 :          0 :   pp_string (pp, "digraph \"");
    3501                 :          0 :   pp_write_text_to_stream (pp);
    3502                 :          0 :   pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
    3503                 :          0 :   pp_string (pp, "\" {\n");
    3504                 :            : 
    3505                 :          0 :   gv.indent ();
    3506                 :            : 
    3507                 :          0 :   pp_string (pp, "overlap=false;\n");
    3508                 :          0 :   pp_string (pp, "compound=true;\n");
    3509                 :            : 
    3510                 :          0 :   int i;
    3511                 :            : 
    3512                 :          0 :   svalue *svalue;
    3513                 :          0 :   FOR_EACH_VEC_ELT (m_svalues, i, svalue)
    3514                 :          0 :     svalue->dump_dot_to_pp (*this, svalue_id::from_int (i), pp);
    3515                 :            : 
    3516                 :            :   region *region;
    3517                 :          0 :   FOR_EACH_VEC_ELT (m_regions, i, region)
    3518                 :          0 :     region->dump_dot_to_pp (*this, region_id::from_int (i), pp);
    3519                 :            : 
    3520                 :            :   /* TODO: constraints.  */
    3521                 :            : 
    3522                 :            :   /* Terminate "digraph" */
    3523                 :          0 :   gv.outdent ();
    3524                 :          0 :   pp_string (pp, "}");
    3525                 :          0 :   pp_newline (pp);
    3526                 :          0 : }
    3527                 :            : 
    3528                 :            : /* Dump a .dot representation of this region_model to FP.  */
    3529                 :            : 
    3530                 :            : void
    3531                 :          0 : region_model::dump_dot_to_file (FILE *fp) const
    3532                 :            : {
    3533                 :          0 :   pretty_printer pp;
    3534                 :          0 :   pp_format_decoder (&pp) = default_tree_printer;
    3535                 :          0 :   pp.buffer->stream = fp;
    3536                 :          0 :   dump_dot_to_pp (&pp);
    3537                 :          0 :   pp_flush (&pp);
    3538                 :          0 : }
    3539                 :            : 
    3540                 :            : /* Dump a .dot representation of this region_model to PATH.  */
    3541                 :            : 
    3542                 :            : void
    3543                 :          0 : region_model::dump_dot (const char *path) const
    3544                 :            : {
    3545                 :          0 :   FILE *fp = fopen (path, "w");
    3546                 :          0 :   dump_dot_to_file (fp);
    3547                 :          0 :   fclose (fp);
    3548                 :          0 : }
    3549                 :            : 
    3550                 :            : /* Dump a multiline representation of this model to PP, showing the
    3551                 :            :    region hierarchy, the svalues, and any constraints.
    3552                 :            : 
    3553                 :            :    If SUMMARIZE is true, show only the most pertinent information,
    3554                 :            :    in a form that attempts to be less verbose.
    3555                 :            :    Otherwise, show all information.  */
    3556                 :            : 
    3557                 :            : void
    3558                 :        101 : region_model::dump_to_pp (pretty_printer *pp, bool summarize) const
    3559                 :            : {
    3560                 :        101 :   if (summarize)
    3561                 :            :     {
    3562                 :        182 :       auto_vec<path_var> rep_path_vars;
    3563                 :            : 
    3564                 :         91 :       unsigned i;
    3565                 :         91 :       region *reg;
    3566                 :       1034 :       FOR_EACH_VEC_ELT (m_regions, i, reg)
    3567                 :            :         {
    3568                 :        943 :           region_id rid = region_id::from_int (i);
    3569                 :        943 :           path_var pv = get_representative_path_var (rid);
    3570                 :        943 :           if (pv.m_tree)
    3571                 :        428 :             rep_path_vars.safe_push (pv);
    3572                 :            :         }
    3573                 :         91 :       bool is_first = true;
    3574                 :            : 
    3575                 :            :       /* Work with a copy in case the get_lvalue calls change anything
    3576                 :            :          (they shouldn't).  */
    3577                 :        182 :       region_model copy (*this);
    3578                 :         91 :       copy.dump_summary_of_rep_path_vars (pp, &rep_path_vars, &is_first);
    3579                 :            : 
    3580                 :         91 :       equiv_class *ec;
    3581                 :        283 :       FOR_EACH_VEC_ELT (m_constraints->m_equiv_classes, i, ec)
    3582                 :            :         {
    3583                 :        410 :           for (unsigned j = 0; j < ec->m_vars.length (); j++)
    3584                 :            :             {
    3585                 :        109 :               svalue_id lhs_sid = ec->m_vars[j];
    3586                 :        109 :               tree lhs_tree = get_representative_tree (lhs_sid);
    3587                 :        109 :               if (lhs_tree == NULL_TREE)
    3588                 :          2 :                 continue;
    3589                 :        240 :               for (unsigned k = j + 1; k < ec->m_vars.length (); k++)
    3590                 :            :                 {
    3591                 :         13 :                   svalue_id rhs_sid = ec->m_vars[k];
    3592                 :         13 :                   tree rhs_tree = get_representative_tree (rhs_sid);
    3593                 :         13 :                   if (rhs_tree
    3594                 :         13 :                       && !(CONSTANT_CLASS_P (lhs_tree)
    3595                 :         11 :                            && CONSTANT_CLASS_P (rhs_tree)))
    3596                 :            :                     {
    3597                 :         13 :                       dump_separator (pp, &is_first);
    3598                 :         13 :                       dump_tree (pp, lhs_tree);
    3599                 :         13 :                       pp_string (pp, " == ");
    3600                 :         26 :                       dump_tree (pp, rhs_tree);
    3601                 :            :                     }
    3602                 :            :                 }
    3603                 :            :             }
    3604                 :            :         }
    3605                 :            : 
    3606                 :            :       constraint *c;
    3607                 :        123 :       FOR_EACH_VEC_ELT (m_constraints->m_constraints, i, c)
    3608                 :            :         {
    3609                 :         32 :           const equiv_class &lhs = c->m_lhs.get_obj (*m_constraints);
    3610                 :         32 :           const equiv_class &rhs = c->m_rhs.get_obj (*m_constraints);
    3611                 :         32 :           svalue_id lhs_sid = lhs.get_representative ();
    3612                 :         32 :           svalue_id rhs_sid = rhs.get_representative ();
    3613                 :         32 :           tree lhs_tree = get_representative_tree (lhs_sid);
    3614                 :         32 :           tree rhs_tree = get_representative_tree (rhs_sid);
    3615                 :         32 :           if (lhs_tree && rhs_tree
    3616                 :         32 :               && !(CONSTANT_CLASS_P (lhs_tree) && CONSTANT_CLASS_P (rhs_tree)))
    3617                 :            :             {
    3618                 :         30 :               dump_separator (pp, &is_first);
    3619                 :         30 :               dump_tree (pp, lhs_tree);
    3620                 :         30 :               pp_printf (pp, " %s ", constraint_op_code (c->m_op));
    3621                 :         62 :               dump_tree (pp, rhs_tree);
    3622                 :            :            }
    3623                 :            :         }
    3624                 :            : 
    3625                 :         91 :       return;
    3626                 :            :     }
    3627                 :            : 
    3628                 :         10 :   get_region (m_root_rid)->dump_to_pp (*this, m_root_rid, pp, "", true);
    3629                 :            : 
    3630                 :         10 :   pp_string (pp, "svalues:");
    3631                 :         10 :   pp_newline (pp);
    3632                 :         10 :   int i;
    3633                 :         10 :   svalue *svalue;
    3634                 :         34 :   FOR_EACH_VEC_ELT (m_svalues, i, svalue)
    3635                 :            :     {
    3636                 :         24 :       pp_string (pp, "  ");
    3637                 :         24 :       svalue_id sid = svalue_id::from_int (i);
    3638                 :         24 :       print_svalue (sid, pp);
    3639                 :         24 :       pp_newline (pp);
    3640                 :            :     }
    3641                 :            : 
    3642                 :         10 :   pp_string (pp, "constraint manager:");
    3643                 :         10 :   pp_newline (pp);
    3644                 :         10 :   m_constraints->dump_to_pp (pp);
    3645                 :            : }
    3646                 :            : 
    3647                 :            : /* Dump a multiline representation of this model to FILE.  */
    3648                 :            : 
    3649                 :            : void
    3650                 :          0 : region_model::dump (FILE *fp, bool summarize) const
    3651                 :            : {
    3652                 :          0 :   pretty_printer pp;
    3653                 :          0 :   pp_format_decoder (&pp) = default_tree_printer;
    3654                 :          0 :   pp_show_color (&pp) = pp_show_color (global_dc->printer);
    3655                 :          0 :   pp.buffer->stream = fp;
    3656                 :          0 :   dump_to_pp (&pp, summarize);
    3657                 :          0 :   pp_flush (&pp);
    3658                 :          0 : }
    3659                 :            : 
    3660                 :            : /* Dump a multiline representation of this model to stderr.  */
    3661                 :            : 
    3662                 :            : DEBUG_FUNCTION void
    3663                 :          0 : region_model::dump (bool summarize) const
    3664                 :            : {
    3665                 :          0 :   dump (stderr, summarize);
    3666                 :          0 : }
    3667                 :            : 
    3668                 :            : /* Dump RMODEL fully to stderr (i.e. without summarization).  */
    3669                 :            : 
    3670                 :            : DEBUG_FUNCTION void
    3671                 :          0 : region_model::debug () const
    3672                 :            : {
    3673                 :          0 :   dump (false);
    3674                 :          0 : }
    3675                 :            : 
    3676                 :            : /* Dump VEC to PP, in the form "{VEC elements}: LABEL".  */
    3677                 :            : 
    3678                 :            : static void
    3679                 :        182 : dump_vec_of_tree (pretty_printer *pp,
    3680                 :            :                   bool *is_first,
    3681                 :            :                   const auto_vec<tree> &vec,
    3682                 :            :                   const char *label)
    3683                 :            : {
    3684                 :        182 :   if (vec.length () == 0)
    3685                 :        182 :     return;
    3686                 :            : 
    3687                 :         74 :   dump_separator (pp, is_first);
    3688                 :         74 :   pp_printf (pp, "{");
    3689                 :         74 :   unsigned i;
    3690                 :         74 :   tree key;
    3691                 :        391 :   FOR_EACH_VEC_ELT (vec, i, key)
    3692                 :            :     {
    3693                 :        317 :       if (i > 0)
    3694                 :        243 :         pp_string (pp, ", ");
    3695                 :        317 :       dump_tree (pp, key);
    3696                 :            :     }
    3697                 :         74 :   pp_printf (pp, "}: %s", label);
    3698                 :            : }
    3699                 :            : 
    3700                 :            : /* Dump all *REP_PATH_VARS to PP in compact form, updating *IS_FIRST.
    3701                 :            :    Subroutine of region_model::dump_to_pp.  */
    3702                 :            : 
    3703                 :            : void
    3704                 :         91 : region_model::dump_summary_of_rep_path_vars (pretty_printer *pp,
    3705                 :            :                                              auto_vec<path_var> *rep_path_vars,
    3706                 :            :                                              bool *is_first)
    3707                 :            : {
    3708                 :            :   /* Print pointers, constants, and poisoned values that aren't "uninit";
    3709                 :            :      gather keys for unknown and uninit values.  */
    3710                 :         91 :   unsigned i;
    3711                 :         91 :   path_var *pv;
    3712                 :         91 :   auto_vec<tree> unknown_trees;
    3713                 :         91 :   auto_vec<tree> uninit_trees;
    3714                 :        519 :   FOR_EACH_VEC_ELT (*rep_path_vars, i, pv)
    3715                 :            :     {
    3716                 :        428 :       if (TREE_CODE (pv->m_tree) == STRING_CST)
    3717                 :          8 :         continue;
    3718                 :        426 :       tentative_region_model_context ctxt;
    3719                 :        426 :       region_id child_rid = get_lvalue (*pv, &ctxt);
    3720                 :        426 :       if (ctxt.had_errors_p ())
    3721                 :          0 :         continue;
    3722                 :        426 :       region *child_region = get_region (child_rid);
    3723                 :        426 :       if (!child_region)
    3724                 :          0 :         continue;
    3725                 :        426 :       svalue_id sid = child_region->get_value_direct ();
    3726                 :        426 :       if (sid.null_p ())
    3727                 :          6 :         continue;
    3728                 :        420 :       svalue *sval = get_svalue (sid);
    3729                 :        420 :       switch (sval->get_kind ())
    3730                 :            :         {
    3731                 :          0 :         default:
    3732                 :          0 :           gcc_unreachable ();
    3733                 :         69 :         case SK_REGION:
    3734                 :         69 :           {
    3735                 :         69 :             region_svalue *region_sval = as_a <region_svalue *> (sval);
    3736                 :         69 :             region_id pointee_rid = region_sval->get_pointee ();
    3737                 :         69 :             gcc_assert (!pointee_rid.null_p ());
    3738                 :         69 :             tree pointee = get_representative_path_var (pointee_rid).m_tree;
    3739                 :         69 :             dump_separator (pp, is_first);
    3740                 :         69 :             dump_tree (pp, pv->m_tree);
    3741                 :         69 :             pp_string (pp, ": ");
    3742                 :         69 :             pp_character (pp, '&');
    3743                 :         69 :             if (pointee)
    3744                 :          6 :               dump_tree (pp, pointee);
    3745                 :            :             else
    3746                 :         63 :               pointee_rid.print (pp);
    3747                 :            :           }
    3748                 :         69 :           break;
    3749                 :         34 :         case SK_CONSTANT:
    3750                 :         34 :           dump_separator (pp, is_first);
    3751                 :         34 :           dump_tree (pp, pv->m_tree);
    3752                 :         34 :           pp_string (pp, ": ");
    3753                 :        454 :           dump_tree (pp, sval->dyn_cast_constant_svalue ()->get_constant ());
    3754                 :            :           break;
    3755                 :        317 :         case SK_UNKNOWN:
    3756                 :        317 :           unknown_trees.safe_push (pv->m_tree);
    3757                 :        317 :           break;
    3758                 :          0 :         case SK_POISONED:
    3759                 :          0 :           {
    3760                 :          0 :             poisoned_svalue *poisoned_sval = as_a <poisoned_svalue *> (sval);
    3761                 :          0 :             enum poison_kind pkind = poisoned_sval->get_poison_kind ();
    3762                 :          0 :             if (pkind == POISON_KIND_UNINIT)
    3763                 :          0 :               uninit_trees.safe_push (pv->m_tree);
    3764                 :            :             else
    3765                 :            :               {
    3766                 :          0 :                 dump_separator (pp, is_first);
    3767                 :          0 :                 dump_tree (pp, pv->m_tree);
    3768                 :          0 :                 pp_printf (pp, ": %s", poison_kind_to_str (pkind));
    3769                 :            :               }
    3770                 :            :           }
    3771                 :            :           break;
    3772                 :          0 :         case SK_SETJMP:
    3773                 :          0 :           dump_separator (pp, is_first);
    3774                 :          0 :           pp_printf (pp, "setjmp: EN: %i",
    3775                 :          0 :                      sval->dyn_cast_setjmp_svalue ()->get_enode_index ());
    3776                 :          0 :           break;
    3777                 :            :         }
    3778                 :            :     }
    3779                 :            : 
    3780                 :            :   /* Print unknown and uninitialized values in consolidated form.  */
    3781                 :         91 :   dump_vec_of_tree (pp, is_first, unknown_trees, "unknown");
    3782                 :         91 :   dump_vec_of_tree (pp, is_first, uninit_trees, "uninit");
    3783                 :         91 : }
    3784                 :            : 
    3785                 :            : /* Assert that this object is valid.  */
    3786                 :            : 
    3787                 :            : void
    3788                 :     370955 : region_model::validate () const
    3789                 :            : {
    3790                 :            :   /* Skip this in a release build.  */
    3791                 :            : #if !CHECKING_P
    3792                 :            :   return;
    3793                 :            : #endif
    3794                 :            : 
    3795                 :     370955 :   m_constraints->validate ();
    3796                 :            : 
    3797                 :     370955 :   unsigned i;
    3798                 :     370955 :   region *r;
    3799                 :    5537120 :   FOR_EACH_VEC_ELT (m_regions, i, r)
    3800                 :    5166160 :     r->validate (*this);
    3801                 :            : 
    3802                 :            :   // TODO: anything else?
    3803                 :            : 
    3804                 :            :   /* Verify that the stack region (if any) has an "uninitialized" value.  */
    3805                 :     370955 :   region *stack_region = get_root_region ()->get_stack_region (this);
    3806                 :     370955 :   if (stack_region)
    3807                 :            :     {
    3808                 :     368774 :       svalue_id stack_value_sid = stack_region->get_value_direct ();
    3809                 :     368774 :       svalue *stack_value = get_svalue (stack_value_sid);
    3810                 :     368774 :       gcc_assert (stack_value->get_kind () == SK_POISONED);
    3811                 :     368774 :       poisoned_svalue *subclass = stack_value->dyn_cast_poisoned_svalue ();
    3812                 :     368774 :       gcc_assert (subclass);
    3813                 :     368774 :       gcc_assert (subclass->get_poison_kind () == POISON_KIND_UNINIT);
    3814                 :            :     }
    3815                 :     370955 : }
    3816                 :            : 
    3817                 :            : /* Global data for use by svalue_id_cmp_by_constant_svalue.  */
    3818                 :            : 
    3819                 :            : static region_model *svalue_id_cmp_by_constant_svalue_model = NULL;
    3820                 :            : 
    3821                 :            : /* Comparator for use by region_model::canonicalize.  */
    3822                 :            : 
    3823                 :            : static int
    3824                 :     830822 : svalue_id_cmp_by_constant_svalue (const void *p1, const void *p2)
    3825                 :            : {
    3826                 :     830822 :   const svalue_id *sid1 = (const svalue_id *)p1;
    3827                 :     830822 :   const svalue_id *sid2 = (const svalue_id *)p2;
    3828                 :     830822 :   gcc_assert (!sid1->null_p ());
    3829                 :     830822 :   gcc_assert (!sid2->null_p ());
    3830                 :     830822 :   gcc_assert (svalue_id_cmp_by_constant_svalue_model);
    3831                 :     830822 :   const svalue &sval1
    3832                 :     830822 :     = *svalue_id_cmp_by_constant_svalue_model->get_svalue (*sid1);
    3833                 :     830822 :   const svalue &sval2
    3834                 :     830822 :     = *svalue_id_cmp_by_constant_svalue_model->get_svalue (*sid2);
    3835                 :     830822 :   gcc_assert (sval1.get_kind () == SK_CONSTANT);
    3836                 :     830822 :   gcc_assert (sval2.get_kind () == SK_CONSTANT);
    3837                 :            : 
    3838                 :     830822 :   tree cst1 = ((const constant_svalue &)sval1).get_constant ();
    3839                 :     830822 :   tree cst2 = ((const constant_svalue &)sval2).get_constant ();
    3840                 :     830822 :   return tree_cmp (cst1, cst2);
    3841                 :            : }
    3842                 :            : 
    3843                 :            : /* Reorder the regions and svalues into a deterministic "canonical" order,
    3844                 :            :    to maximize the chance of equality.
    3845                 :            :    If non-NULL, notify CTXT about the svalue id remapping.  */
    3846                 :            : 
    3847                 :            : void
    3848                 :      59945 : region_model::canonicalize (region_model_context *ctxt)
    3849                 :            : {
    3850                 :            :   /* Walk all regions and values in a deterministic order, visiting
    3851                 :            :      rids and sids, generating a rid and sid map.  */
    3852                 :      59945 :   canonicalization c (*this);
    3853                 :            : 
    3854                 :            :   /* (1): Walk all svalues, putting constants first, sorting the constants
    3855                 :            :      (thus imposing an ordering on any constants that are purely referenced
    3856                 :            :      by constraints).
    3857                 :            :      Ignore other svalues for now.  */
    3858                 :      59945 :   {
    3859                 :      59945 :     unsigned i;
    3860                 :      59945 :     auto_vec<svalue_id> sids;
    3861                 :      59945 :     svalue *sval;
    3862                 :     572527 :     FOR_EACH_VEC_ELT (m_svalues, i, sval)
    3863                 :            :       {
    3864                 :     512582 :         if (sval->get_kind () == SK_CONSTANT)
    3865                 :     135820 :           sids.safe_push (svalue_id::from_int (i));
    3866                 :            :       }
    3867                 :      59945 :     svalue_id_cmp_by_constant_svalue_model = this;
    3868                 :      59945 :     sids.qsort (svalue_id_cmp_by_constant_svalue);
    3869                 :      59945 :     svalue_id_cmp_by_constant_svalue_model = NULL;
    3870                 :      59945 :     svalue_id *sid;
    3871                 :     239322 :     FOR_EACH_VEC_ELT (sids, i, sid)
    3872                 :     135820 :       c.walk_sid (*sid);
    3873                 :            :   }
    3874                 :            : 
    3875                 :            :   /* (2): Walk all regions (and thus their values) in a deterministic
    3876                 :            :      order.  */
    3877                 :      59945 :   c.walk_rid (m_root_rid);
    3878                 :            : 
    3879                 :            :   /* (3): Ensure we've visited everything, as we don't want to purge
    3880                 :            :      at this stage.  Anything we visit for the first time here has
    3881                 :            :      arbitrary order.  */
    3882                 :      59945 :   {
    3883                 :      59945 :     unsigned i;
    3884                 :      59945 :     region *region;
    3885                 :     967385 :     FOR_EACH_VEC_ELT (m_regions, i, region)
    3886                 :     907440 :       c.walk_rid (region_id::from_int (i));
    3887                 :            :     svalue *sval;
    3888                 :     572527 :     FOR_EACH_VEC_ELT (m_svalues, i, sval)
    3889                 :     512582 :       c.walk_sid (svalue_id::from_int (i));
    3890                 :            :   }
    3891                 :            : 
    3892                 :            :   /* (4): We now have a reordering of the regions and values.
    3893                 :            :      Apply it.  */
    3894                 :      59945 :   remap_svalue_ids (c.m_sid_map);
    3895                 :      59945 :   remap_region_ids (c.m_rid_map);
    3896                 :      59945 :   if (ctxt)
    3897                 :      32928 :     ctxt->remap_svalue_ids (c.m_sid_map);
    3898                 :            : 
    3899                 :            :   /* (5): Canonicalize the constraint_manager (it has already had its
    3900                 :            :      svalue_ids remapped above).  This makes use of the new svalue_id
    3901                 :            :      values, and so must happen last.  */
    3902                 :     119513 :   m_constraints->canonicalize (get_num_svalues ());
    3903                 :            : 
    3904                 :      59945 :   validate ();
    3905                 :      59945 : }
    3906                 :            : 
    3907                 :            : /* Return true if this region_model is in canonical form.  */
    3908                 :            : 
    3909                 :            : bool
    3910                 :      26835 : region_model::canonicalized_p () const
    3911                 :            : {
    3912                 :      53670 :   region_model copy (*this);
    3913                 :      26835 :   copy.canonicalize (NULL);
    3914                 :      26835 :   return *this == copy;
    3915                 :            : }
    3916                 :            : 
    3917                 :            : /* A subclass of pending_diagnostic for complaining about uses of
    3918                 :            :    poisoned values.  */
    3919                 :            : 
    3920                 :            : class poisoned_value_diagnostic
    3921                 :            : : public pending_diagnostic_subclass<poisoned_value_diagnostic>
    3922                 :            : {
    3923                 :            : public:
    3924                 :         12 :   poisoned_value_diagnostic (tree expr, enum poison_kind pkind)
    3925                 :         12 :   : m_expr (expr), m_pkind (pkind)
    3926                 :            :   {}
    3927                 :            : 
    3928                 :         27 :   const char *get_kind () const FINAL OVERRIDE { return "poisoned_value_diagnostic"; }
    3929                 :            : 
    3930                 :          9 :   bool operator== (const poisoned_value_diagnostic &other) const
    3931                 :            :   {
    3932                 :          9 :     return m_expr == other.m_expr;
    3933                 :            :   }
    3934                 :            : 
    3935                 :          9 :   bool emit (rich_location *rich_loc) FINAL OVERRIDE
    3936                 :            :   {
    3937                 :          9 :     switch (m_pkind)
    3938                 :            :       {
    3939                 :          0 :       default:
    3940                 :          0 :         gcc_unreachable ();
    3941                 :          5 :       case POISON_KIND_UNINIT:
    3942                 :          5 :         {
    3943                 :          5 :           diagnostic_metadata m;
    3944                 :          5 :           m.add_cwe (457); /* "CWE-457: Use of Uninitialized Variable".  */
    3945                 :          5 :           return warning_meta (rich_loc, m,
    3946                 :            :                                OPT_Wanalyzer_use_of_uninitialized_value,
    3947                 :            :                                "use of uninitialized value %qE",
    3948                 :            :                                m_expr);
    3949                 :            :         }
    3950                 :          4 :         break;
    3951                 :          4 :       case POISON_KIND_FREED:
    3952                 :          4 :         {
    3953                 :          4 :           diagnostic_metadata m;
    3954                 :          4 :           m.add_cwe (416); /* "CWE-416: Use After Free".  */
    3955                 :          4 :           return warning_meta (rich_loc, m,
    3956                 :            :                                OPT_Wanalyzer_use_after_free,
    3957                 :            :                                "use after %<free%> of %qE",
    3958                 :            :                                m_expr);
    3959                 :            :         }
    3960                 :          0 :         break;
    3961                 :          0 :       case POISON_KIND_POPPED_STACK:
    3962                 :          0 :         {
    3963                 :            :           /* TODO: which CWE?  */
    3964                 :          0 :           return warning_at (rich_loc,
    3965                 :            :                              OPT_Wanalyzer_use_of_pointer_in_stale_stack_frame,
    3966                 :            :                              "use of pointer %qE within stale stack frame",
    3967                 :          0 :                              m_expr);
    3968                 :            :         }
    3969                 :            :         break;
    3970                 :            :       }
    3971                 :            :   }
    3972                 :            : 
    3973                 :         18 :   label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
    3974                 :            :   {
    3975                 :         18 :     switch (m_pkind)
    3976                 :            :       {
    3977                 :          0 :       default:
    3978                 :          0 :         gcc_unreachable ();
    3979                 :         10 :       case POISON_KIND_UNINIT:
    3980                 :         10 :         return ev.formatted_print ("use of uninitialized value %qE here",
    3981                 :         10 :                                    m_expr);
    3982                 :          8 :       case POISON_KIND_FREED:
    3983                 :          8 :         return ev.formatted_print ("use after %<free%> of %qE here",
    3984                 :          8 :                                    m_expr);
    3985                 :          0 :       case POISON_KIND_POPPED_STACK:
    3986                 :          0 :         return ev.formatted_print
    3987                 :            :           ("use of pointer %qE within stale stack frame here",
    3988                 :          0 :            m_expr);
    3989                 :            :       }
    3990                 :            :   }
    3991                 :            : 
    3992                 :            : private:
    3993                 :            :   tree m_expr;
    3994                 :            :   enum poison_kind m_pkind;
    3995                 :            : };
    3996                 :            : 
    3997                 :            : /* Determine if EXPR is poisoned, and if so, queue a diagnostic to CTXT.  */
    3998                 :            : 
    3999                 :            : void
    4000                 :      11924 : region_model::check_for_poison (tree expr, region_model_context *ctxt)
    4001                 :            : {
    4002                 :      11924 :   if (!ctxt)
    4003                 :            :     return;
    4004                 :            : 
    4005                 :            :   // TODO: this is disabled for now (too many false positives)
    4006                 :            :   return;
    4007                 :            : 
    4008                 :            :   svalue_id expr_sid = get_rvalue (expr, ctxt);
    4009                 :            :   gcc_assert (!expr_sid.null_p ());
    4010                 :            :   svalue *expr_svalue = get_svalue (expr_sid);
    4011                 :            :   gcc_assert (expr_svalue);
    4012                 :            :   if (const poisoned_svalue *poisoned_sval
    4013                 :            :         = expr_svalue->dyn_cast_poisoned_svalue ())
    4014                 :            :     {
    4015                 :            :       enum poison_kind pkind = poisoned_sval->get_poison_kind ();
    4016                 :            :       ctxt->warn (new poisoned_value_diagnostic (expr, pkind));
    4017                 :            :     }
    4018                 :            : }
    4019                 :            : 
    4020                 :            : /* Update this model for the ASSIGN stmt, using CTXT to report any
    4021                 :            :    diagnostics.  */
    4022                 :            : 
    4023                 :            : void
    4024                 :       7462 : region_model::on_assignment (const gassign *assign, region_model_context *ctxt)
    4025                 :            : {
    4026                 :       7462 :   tree lhs = gimple_assign_lhs (assign);
    4027                 :       7462 :   tree rhs1 = gimple_assign_rhs1 (assign);
    4028                 :            : 
    4029                 :       7462 :   region_id lhs_rid = get_lvalue (lhs, ctxt);
    4030                 :            : 
    4031                 :            :   /* Check for uses of poisoned values.  */
    4032                 :       7462 :   switch (get_gimple_rhs_class (gimple_expr_code (assign)))
    4033                 :            :     {
    4034                 :          0 :     case GIMPLE_INVALID_RHS:
    4035                 :          0 :       gcc_unreachable ();
    4036                 :          0 :       break;
    4037                 :          0 :     case GIMPLE_TERNARY_RHS:
    4038                 :          0 :       check_for_poison (gimple_assign_rhs3 (assign), ctxt);
    4039                 :            :       /* Fallthru */
    4040                 :       2107 :     case GIMPLE_BINARY_RHS:
    4041                 :       4214 :       check_for_poison (gimple_assign_rhs2 (assign), ctxt);
    4042                 :            :       /* Fallthru */
    4043                 :       7462 :     case GIMPLE_UNARY_RHS:
    4044                 :       7462 :     case GIMPLE_SINGLE_RHS:
    4045                 :       7462 :       check_for_poison (gimple_assign_rhs1 (assign), ctxt);
    4046                 :            :     }
    4047                 :            : 
    4048                 :       7462 :   if (lhs_rid.null_p ())
    4049                 :        251 :     return;
    4050                 :            :   // TODO: issue a warning for this case
    4051                 :            : 
    4052                 :       7462 :   enum tree_code op = gimple_assign_rhs_code (assign);
    4053                 :       7462 :   switch (op)
    4054                 :            :     {
    4055                 :          9 :     default:
    4056                 :          9 :       {
    4057                 :          9 :         if (0)
    4058                 :            :           sorry_at (assign->location, "unhandled assignment op: %qs",
    4059                 :            :                     get_tree_code_name (op));
    4060                 :          9 :         set_to_new_unknown_value (lhs_rid, TREE_TYPE (lhs), ctxt);
    4061                 :            :       }
    4062                 :          9 :       break;
    4063                 :            : 
    4064                 :            :     case BIT_FIELD_REF:
    4065                 :            :       {
    4066                 :            :         // TODO
    4067                 :            :       }
    4068                 :            :       break;
    4069                 :            : 
    4070                 :            :     case CONSTRUCTOR:
    4071                 :            :       {
    4072                 :            :         /* e.g. "x ={v} {CLOBBER};"  */
    4073                 :            :         // TODO
    4074                 :            :       }
    4075                 :            :       break;
    4076                 :            : 
    4077                 :        386 :     case POINTER_PLUS_EXPR:
    4078                 :        386 :       {
    4079                 :            :         /* e.g. "_1 = a_10(D) + 12;" */
    4080                 :        386 :         tree ptr = rhs1;
    4081                 :        386 :         tree offset = gimple_assign_rhs2 (assign);
    4082                 :            : 
    4083                 :        386 :         svalue_id ptr_sid = get_rvalue (ptr, ctxt);
    4084                 :        386 :         svalue_id offset_sid = get_rvalue (offset, ctxt);
    4085                 :        386 :         region_id element_rid
    4086                 :        386 :           = get_or_create_pointer_plus_expr (TREE_TYPE (TREE_TYPE (ptr)),
    4087                 :            :                                              ptr_sid, offset_sid,
    4088                 :        386 :                                              ctxt);
    4089                 :        386 :         svalue_id element_ptr_sid
    4090                 :        386 :           = get_or_create_ptr_svalue (TREE_TYPE (ptr), element_rid);
    4091                 :        386 :         set_value (lhs_rid, element_ptr_sid, ctxt);
    4092                 :            :       }
    4093                 :        386 :       break;
    4094                 :            : 
    4095                 :          3 :     case POINTER_DIFF_EXPR:
    4096                 :          3 :       {
    4097                 :            :         /* e.g. "_1 = p_2(D) - q_3(D);".  */
    4098                 :            : 
    4099                 :            :         /* TODO.  */
    4100                 :            : 
    4101                 :          3 :         set_to_new_unknown_value (lhs_rid, TREE_TYPE (lhs), ctxt);
    4102                 :            :       }
    4103                 :          3 :       break;
    4104                 :            : 
    4105                 :        262 :     case ADDR_EXPR:
    4106                 :        262 :       {
    4107                 :            :         /* LHS = &RHS;  */
    4108                 :        262 :         svalue_id ptr_sid = get_rvalue (rhs1, ctxt);
    4109                 :        262 :         set_value (lhs_rid, ptr_sid, ctxt);
    4110                 :            :       }
    4111                 :        262 :       break;
    4112                 :            : 
    4113                 :        238 :     case MEM_REF:
    4114                 :        238 :       {
    4115                 :        238 :         region_id rhs_rid = get_lvalue (rhs1, ctxt);
    4116                 :        238 :         svalue_id rhs_sid
    4117                 :        238 :           = get_region (rhs_rid)->get_value (*this, true, ctxt);
    4118                 :        238 :         set_value (lhs_rid, rhs_sid, ctxt);
    4119                 :            :       }
    4120                 :        238 :       break;
    4121                 :            : 
    4122                 :       1057 :     case REAL_CST:
    4123                 :       1057 :     case INTEGER_CST:
    4124                 :       1057 :     case ARRAY_REF:
    4125                 :       1057 :       {
    4126                 :            :         /* LHS = RHS;  */
    4127                 :       1057 :         svalue_id cst_sid = get_rvalue (rhs1, ctxt);
    4128                 :       1057 :         set_value (lhs_rid, cst_sid, ctxt);
    4129                 :            :       }
    4130                 :       1057 :       break;
    4131                 :            : 
    4132                 :       2652 :     case FIX_TRUNC_EXPR:
    4133                 :       2652 :     case FLOAT_EXPR:
    4134                 :       2652 :     case NOP_EXPR:
    4135                 :            :       // cast: TODO
    4136                 :            :       // fall though for now
    4137                 :       2652 :     case SSA_NAME:
    4138                 :       2652 :     case VAR_DECL:
    4139                 :       2652 :     case PARM_DECL:
    4140                 :       2652 :       {
    4141                 :            :         /* LHS = VAR;  */
    4142                 :       2652 :         svalue_id var_sid = get_rvalue (rhs1, ctxt);
    4143                 :       2652 :         set_value (lhs_rid, var_sid, ctxt);
    4144                 :            :       }
    4145                 :       2652 :       break;
    4146                 :            : 
    4147                 :        580 :     case EQ_EXPR:
    4148                 :        580 :     case GE_EXPR:
    4149                 :        580 :     case LE_EXPR:
    4150                 :        580 :     case NE_EXPR:
    4151                 :        580 :     case GT_EXPR:
    4152                 :        580 :     case LT_EXPR:
    4153                 :        580 :       {
    4154                 :        580 :         tree rhs2 = gimple_assign_rhs2 (assign);
    4155                 :            : 
    4156                 :            :         // TODO: constraints between svalues
    4157                 :        580 :         svalue_id rhs1_sid = get_rvalue (rhs1, ctxt);
    4158                 :        580 :         svalue_id rhs2_sid = get_rvalue (rhs2, ctxt);
    4159                 :            : 
    4160                 :        580 :         tristate t = eval_condition (rhs1_sid, op, rhs2_sid);
    4161                 :        580 :         if (t.is_known ())
    4162                 :        353 :           set_value (lhs_rid,
    4163                 :        353 :                      get_rvalue (t.is_true ()
    4164                 :            :                                  ? boolean_true_node
    4165                 :            :                                  : boolean_false_node,
    4166                 :            :                                  ctxt),
    4167                 :            :                      ctxt);
    4168                 :            :         else
    4169                 :        227 :           set_to_new_unknown_value (lhs_rid, TREE_TYPE (lhs), ctxt);
    4170                 :            :       }
    4171                 :        580 :       break;
    4172                 :            : 
    4173                 :         19 :     case NEGATE_EXPR:
    4174                 :         19 :     case BIT_NOT_EXPR:
    4175                 :         19 :       {
    4176                 :            :         // TODO: unary ops
    4177                 :            : 
    4178                 :            :         // TODO: constant?
    4179                 :            : 
    4180                 :         19 :         set_to_new_unknown_value (lhs_rid, TREE_TYPE (lhs), ctxt);
    4181                 :            :       }
    4182                 :         19 :       break;
    4183                 :            : 
    4184                 :       1135 :     case PLUS_EXPR:
    4185                 :       1135 :     case MINUS_EXPR:
    4186                 :       1135 :     case MULT_EXPR:
    4187                 :       1135 :     case TRUNC_DIV_EXPR:
    4188                 :       1135 :     case TRUNC_MOD_EXPR:
    4189                 :       1135 :     case LSHIFT_EXPR:
    4190                 :       1135 :     case RSHIFT_EXPR:
    4191                 :       1135 :     case BIT_IOR_EXPR:
    4192                 :       1135 :     case BIT_XOR_EXPR:
    4193                 :       1135 :     case BIT_AND_EXPR:
    4194                 :       1135 :     case MIN_EXPR:
    4195                 :       1135 :     case MAX_EXPR:
    4196                 :       1135 :       {
    4197                 :            :         /* Binary ops.  */
    4198                 :       1135 :         tree rhs2 = gimple_assign_rhs2 (assign);
    4199                 :            : 
    4200                 :       1135 :         svalue_id rhs1_sid = get_rvalue (rhs1, ctxt);
    4201                 :       1135 :         svalue_id rhs2_sid = get_rvalue (rhs2, ctxt);
    4202                 :            : 
    4203                 :       1135 :         if (tree rhs1_cst = maybe_get_constant (rhs1_sid))
    4204                 :        292 :           if (tree rhs2_cst = maybe_get_constant (rhs2_sid))
    4205                 :            :             {
    4206                 :        258 :               tree result = fold_binary (op, TREE_TYPE (lhs),
    4207                 :            :                                          rhs1_cst, rhs2_cst);
    4208                 :        258 :               if (result && CONSTANT_CLASS_P (result))
    4209                 :            :                 {
    4210                 :        251 :                   svalue_id result_sid
    4211                 :        251 :                     = get_or_create_constant_svalue (result);
    4212                 :        251 :                   set_value (lhs_rid, result_sid, ctxt);
    4213                 :        251 :                   return;
    4214                 :            :                 }
    4215                 :            :             }
    4216                 :        884 :         set_to_new_unknown_value (lhs_rid, TREE_TYPE (lhs), ctxt);
    4217                 :            :       }
    4218                 :        884 :       break;
    4219                 :            : 
    4220                 :        844 :     case COMPONENT_REF:
    4221                 :        844 :       {
    4222                 :            :         /* LHS = op0.op1;  */
    4223                 :        844 :         region_id child_rid = get_lvalue (rhs1, ctxt);
    4224                 :        844 :         svalue_id child_sid
    4225                 :        844 :           = get_region (child_rid)->get_value (*this, true, ctxt);
    4226                 :        844 :         set_value (lhs_rid, child_sid, ctxt);
    4227                 :            :       }
    4228                 :        844 :       break;
    4229                 :            :     }
    4230                 :            : }
    4231                 :            : 
    4232                 :            : /* Update this model for the CALL stmt, using CTXT to report any
    4233                 :            :    diagnostics - the first half.
    4234                 :            : 
    4235                 :            :    Updates to the region_model that should be made *before* sm-states
    4236                 :            :    are updated are done here; other updates to the region_model are done
    4237                 :            :    in region_model::on_call_post.
    4238                 :            : 
    4239                 :            :    Return true if the function call has unknown side effects (it wasn't
    4240                 :            :    recognized and we don't have a body for it, or are unable to tell which
    4241                 :            :    fndecl it is).  */
    4242                 :            : 
    4243                 :            : bool
    4244                 :       2949 : region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
    4245                 :            : {
    4246                 :       2949 :   region_id lhs_rid;
    4247                 :       2949 :   tree lhs_type = NULL_TREE;
    4248                 :       2949 :   if (tree lhs = gimple_call_lhs (call))
    4249                 :            :     {
    4250                 :       1137 :       lhs_rid = get_lvalue (lhs, ctxt);
    4251                 :       1137 :       lhs_type = TREE_TYPE (lhs);
    4252                 :            :     }
    4253                 :            : 
    4254                 :            :   /* Check for uses of poisoned values.
    4255                 :            :      For now, special-case "free", to avoid warning about "use-after-free"
    4256                 :            :      when "double free" would be more precise.  */
    4257                 :       2949 :   if (!is_special_named_call_p (call, "free", 1))
    4258                 :       4703 :     for (unsigned i = 0; i < gimple_call_num_args (call); i++)
    4259                 :       2355 :       check_for_poison (gimple_call_arg (call, i), ctxt);
    4260                 :            : 
    4261                 :       2949 :   bool unknown_side_effects = false;
    4262                 :            : 
    4263                 :       2949 :   if (tree callee_fndecl = get_fndecl_for_call (call, ctxt))
    4264                 :            :     {
    4265                 :       2923 :       if (is_named_call_p (callee_fndecl, "malloc", call, 1))
    4266                 :            :         {
    4267                 :            :           // TODO: capture size as a svalue?
    4268                 :        275 :           region_id new_rid = add_new_malloc_region ();
    4269                 :        275 :           if (!lhs_rid.null_p ())
    4270                 :            :             {
    4271                 :        275 :               svalue_id ptr_sid
    4272                 :        275 :                 = get_or_create_ptr_svalue (lhs_type, new_rid);
    4273                 :        275 :               set_value (lhs_rid, ptr_sid, ctxt);
    4274                 :            :             }
    4275                 :        275 :           return false;
    4276                 :            :         }
    4277                 :       2648 :       else if (is_named_call_p (callee_fndecl, "__builtin_alloca", call, 1))
    4278                 :            :         {
    4279                 :          8 :           region_id frame_rid = get_current_frame_id ();
    4280                 :          8 :           region_id new_rid
    4281                 :          8 :             = add_region (new symbolic_region (frame_rid, NULL_TREE, false));
    4282                 :          8 :           if (!lhs_rid.null_p ())
    4283                 :            :             {
    4284                 :          8 :               svalue_id ptr_sid
    4285                 :          8 :                 = get_or_create_ptr_svalue (lhs_type, new_rid);
    4286                 :          8 :               set_value (lhs_rid, ptr_sid, ctxt);
    4287                 :            :             }
    4288                 :          8 :           return false;
    4289                 :            :         }
    4290                 :       2640 :       else if (gimple_call_builtin_p (call, BUILT_IN_EXPECT)
    4291                 :       2638 :                || gimple_call_builtin_p (call, BUILT_IN_EXPECT_WITH_PROBABILITY)
    4292                 :       5277 :                || gimple_call_internal_p (call, IFN_BUILTIN_EXPECT))
    4293                 :            :         {
    4294                 :            :           /* __builtin_expect's return value is its initial argument.  */
    4295                 :          3 :           if (!lhs_rid.null_p ())
    4296                 :            :             {
    4297                 :          3 :               tree initial_arg = gimple_call_arg (call, 0);
    4298                 :          3 :               svalue_id sid = get_rvalue (initial_arg, ctxt);
    4299                 :          3 :               set_value (lhs_rid, sid, ctxt);
    4300                 :            :             }
    4301                 :          3 :           return false;
    4302                 :            :         }
    4303                 :       2637 :       else if (is_named_call_p (callee_fndecl, "strlen", call, 1))
    4304                 :            :         {
    4305                 :         13 :           region_id buf_rid = deref_rvalue (gimple_call_arg (call, 0), ctxt);
    4306                 :         13 :           svalue_id buf_sid
    4307                 :         13 :             = get_region (buf_rid)->get_value (*this, true, ctxt);
    4308                 :         13 :           if (tree cst_expr = maybe_get_constant (buf_sid))
    4309                 :            :             {
    4310                 :          2 :               if (TREE_CODE (cst_expr) == STRING_CST
    4311                 :          2 :                   && !lhs_rid.null_p ())
    4312                 :            :                 {
    4313                 :            :                   /* TREE_STRING_LENGTH is sizeof, not strlen.  */
    4314                 :          2 :                   int sizeof_cst = TREE_STRING_LENGTH (cst_expr);
    4315                 :          2 :                   int strlen_cst = sizeof_cst - 1;
    4316                 :          2 :                   tree t_cst = build_int_cst (lhs_type, strlen_cst);
    4317                 :          2 :                   svalue_id result_sid
    4318                 :          2 :                     = get_or_create_constant_svalue (t_cst);
    4319                 :          2 :                   set_value (lhs_rid, result_sid, ctxt);
    4320                 :          2 :                   return false;
    4321                 :            :                 }
    4322                 :            :             }
    4323                 :            :           /* Otherwise an unknown value.  */
    4324                 :            :         }
    4325                 :       2624 :       else if (is_named_call_p (callee_fndecl,
    4326                 :            :                                 "__analyzer_dump_num_heap_regions", call, 0))
    4327                 :            :         {
    4328                 :            :           /* Handle the builtin "__analyzer_dump_num_heap_regions" by emitting
    4329                 :            :              a warning (for use in DejaGnu tests).  */
    4330                 :          5 :           int num_heap_regions = 0;
    4331                 :          5 :           region_id heap_rid = get_root_region ()->ensure_heap_region (this);
    4332                 :          5 :           unsigned i;
    4333                 :          5 :           region *region;
    4334                 :         56 :           FOR_EACH_VEC_ELT (m_regions, i, region)
    4335                 :         51 :             if (region->get_parent () == heap_rid)
    4336                 :          2 :               num_heap_regions++;
    4337                 :            :           /* Use quotes to ensure the output isn't truncated.  */
    4338                 :          5 :           warning_at (call->location, 0,
    4339                 :            :                       "num heap regions: %qi", num_heap_regions);
    4340                 :          5 :           return false;
    4341                 :            :         }
    4342                 :       2619 :       else if (!fndecl_has_gimple_body_p (callee_fndecl)
    4343                 :       4682 :                && !DECL_PURE_P (callee_fndecl))
    4344                 :            :         unknown_side_effects = true;
    4345                 :            :     }
    4346                 :            :   else
    4347                 :            :     unknown_side_effects = true;
    4348                 :            : 
    4349                 :            :   /* Unknown return value.  */
    4350                 :       2656 :   if (!lhs_rid.null_p ())
    4351                 :        849 :     set_to_new_unknown_value (lhs_rid, lhs_type, ctxt);
    4352                 :            : 
    4353                 :            :   return unknown_side_effects;
    4354                 :            : }
    4355                 :            : 
    4356                 :            : /* Update this model for the CALL stmt, using CTXT to report any
    4357                 :            :    diagnostics - the second half.
    4358                 :            : 
    4359                 :            :    Updates to the region_model that should be made *after* sm-states
    4360                 :            :    are updated are done here; other updates to the region_model are done
    4361                 :            :    in region_model::on_call_pre.
    4362                 :            : 
    4363                 :            :    If UNKNOWN_SIDE_EFFECTS is true, also call handle_unrecognized_call
    4364                 :            :    to purge state.  */
    4365                 :            : 
    4366                 :            : void
    4367                 :       3684 : region_model::on_call_post (const gcall *call,
    4368                 :            :                             bool unknown_side_effects,
    4369                 :            :                             region_model_context *ctxt)
    4370                 :            : {
    4371                 :            :   /* Update for "free" here, after sm-handling.
    4372                 :            : 
    4373                 :            :      If the ptr points to an underlying heap region, delete the region,
    4374                 :            :      poisoning pointers to it and regions within it.
    4375                 :            : 
    4376                 :            :      We delay this until after sm-state has been updated so that the
    4377                 :            :      sm-handling can transition all of the various casts of the pointer
    4378                 :            :      to a "freed" state *before* we delete the related region here.
    4379                 :            : 
    4380                 :            :      This has to be done here so that the sm-handling can use the fact
    4381                 :            :      that they point to the same region to establish that they are equal
    4382                 :            :      (in region_model::eval_condition_without_cm), and thus transition
    4383                 :            :      all pointers to the region to the "freed" state together, regardless
    4384                 :            :      of casts.  */
    4385                 :       3684 :   if (tree callee_fndecl = get_fndecl_for_call (call, ctxt))
    4386                 :       3658 :     if (is_named_call_p (callee_fndecl, "free", call, 1))
    4387                 :            :       {
    4388                 :        608 :         tree ptr = gimple_call_arg (call, 0);
    4389                 :        608 :         svalue_id ptr_sid = get_rvalue (ptr, ctxt);
    4390                 :        608 :         svalue *ptr_sval = get_svalue (ptr_sid);
    4391                 :       1216 :         if (region_svalue *ptr_to_region_sval
    4392                 :        608 :             = ptr_sval->dyn_cast_region_svalue ())
    4393                 :            :           {
    4394                 :            :             /* If the ptr points to an underlying heap region, delete it,
    4395                 :            :                poisoning pointers.  */
    4396                 :        121 :             region_id pointee_rid = ptr_to_region_sval->get_pointee ();
    4397                 :        121 :             region_id heap_rid = get_root_region ()->ensure_heap_region (this);
    4398                 :        121 :             if (!pointee_rid.null_p ()
    4399                 :        121 :                 && get_region (pointee_rid)->get_parent () == heap_rid)
    4400                 :            :               {
    4401                 :        104 :                 purge_stats stats;
    4402                 :        104 :                 delete_region_and_descendents (pointee_rid,
    4403                 :            :                                                POISON_KIND_FREED,
    4404                 :        104 :                                                &stats, ctxt->get_logger ());
    4405                 :        104 :                 purge_unused_svalues (&stats, ctxt);
    4406                 :        104 :                 validate ();
    4407                 :            :                 // TODO: do anything with stats?
    4408                 :            :               }
    4409                 :            :           }
    4410                 :        608 :         return;
    4411                 :            :       }
    4412                 :            : 
    4413                 :       3076 :   if (unknown_side_effects)
    4414                 :       1233 :     handle_unrecognized_call (call, ctxt);
    4415                 :            : }
    4416                 :            : 
    4417                 :            : /* Helper class for region_model::handle_unrecognized_call, for keeping
    4418                 :            :    track of all regions that are reachable, and, of those, which are
    4419                 :            :    mutable.  */
    4420                 :            : 
    4421                 :       1233 : class reachable_regions
    4422                 :            : {
    4423                 :            : public:
    4424                 :       1233 :   reachable_regions (region_model *model)
    4425                 :       1233 :   : m_model (model), m_reachable_rids (), m_mutable_rids ()
    4426                 :            :   {}
    4427                 :            : 
    4428                 :            :   /* Lazily mark RID as being reachable, recursively adding regions
    4429                 :            :      reachable from RID.  */
    4430                 :       5614 :   void add (region_id rid, bool is_mutable)
    4431                 :            :   {
    4432                 :       5614 :     gcc_assert (!rid.null_p ());
    4433                 :            : 
    4434                 :       5614 :     unsigned idx = rid.as_int ();
    4435                 :            :     /* Bail out if this region is already in the sets at the IS_MUTABLE
    4436                 :            :        level of mutability.  */
    4437                 :       5614 :     if (!is_mutable && bitmap_bit_p (m_reachable_rids, idx))
    4438                 :       3593 :       return;
    4439                 :       5473 :     bitmap_set_bit (m_reachable_rids, idx);
    4440                 :            : 
    4441                 :       5473 :     if (is_mutable)
    4442                 :            :       {
    4443                 :       5337 :         if (bitmap_bit_p (m_mutable_rids, idx))
    4444                 :            :           return;
    4445                 :            :         else
    4446                 :       1885 :           bitmap_set_bit (m_mutable_rids, idx);
    4447                 :            :       }
    4448                 :            : 
    4449                 :            :     /* If this region's value is a pointer, add the pointee.  */
    4450                 :       2021 :     region *reg = m_model->get_region (rid);
    4451                 :       2021 :     svalue_id sid = reg->get_value_direct ();
    4452                 :       2021 :     svalue *sval = m_model->get_svalue (sid);
    4453                 :       2021 :     if (sval)
    4454                 :       1379 :       if (region_svalue *ptr = sval->dyn_cast_region_svalue ())
    4455                 :            :         {
    4456                 :         79 :           region_id pointee_rid = ptr->get_pointee ();
    4457                 :            :           /* Use const-ness of pointer type to affect mutability.  */
    4458                 :         79 :           bool ptr_is_mutable = true;
    4459                 :         79 :           if (ptr->get_type ()
    4460                 :         79 :               && TREE_CODE (ptr->get_type ()) == POINTER_TYPE
    4461                 :        144 :               && TYPE_READONLY (TREE_TYPE (ptr->get_type ())))
    4462                 :            :             ptr_is_mutable = false;
    4463                 :         79 :           add (pointee_rid, ptr_is_mutable);
    4464                 :            :         }
    4465                 :            : 
    4466                 :            :     /* Add descendents of this region.  */
    4467                 :       4042 :     region_id_set descendents (m_model);
    4468                 :       2021 :     m_model->get_descendents (rid, &descendents, region_id::null ());
    4469                 :     152068 :     for (unsigned i = 0; i < m_model->get_num_regions (); i++)
    4470                 :            :       {
    4471                 :      74013 :         region_id iter_rid = region_id::from_int (i);
    4472                 :      74013 :         if (descendents.region_p (iter_rid))
    4473                 :       4936 :           add (iter_rid, is_mutable);
    4474                 :            :       }
    4475                 :            :   }
    4476                 :            : 
    4477                 :      27399 :   bool mutable_p (region_id rid)
    4478                 :            :   {
    4479                 :      27399 :     gcc_assert (!rid.null_p ());
    4480                 :      27399 :     return bitmap_bit_p (m_mutable_rids, rid.as_int ());
    4481                 :            :   }
    4482                 :            : 
    4483                 :            : private:
    4484                 :            :   region_model *m_model;
    4485                 :            : 
    4486                 :            :   /* The region ids already seen.  This has to be an auto_bitmap rather than
    4487                 :            :      an auto_sbitmap as new regions can be created within the model during
    4488                 :            :      the traversal.  */
    4489                 :            :   auto_bitmap m_reachable_rids;
    4490                 :            : 
    4491                 :            :   /* The region_ids that can be changed (accessed via non-const pointers).  */
    4492                 :            :   auto_bitmap m_mutable_rids;
    4493                 :            : };
    4494                 :            : 
    4495                 :            : /* Handle a call CALL to a function with unknown behavior.
    4496                 :            : 
    4497                 :            :    Traverse the regions in this model, determining what regions are
    4498                 :            :    reachable from pointer arguments to CALL and from global variables,
    4499                 :            :    recursively.
    4500                 :            : 
    4501                 :            :    Set all reachable regions to new unknown values and purge sm-state
    4502                 :            :    from their values, and from values that point to them.  */
    4503                 :            : 
    4504                 :            : void
    4505                 :       1233 : region_model::handle_unrecognized_call (const gcall *call,
    4506                 :            :                                         region_model_context *ctxt)
    4507                 :            : {
    4508                 :       1233 :   tree fndecl = get_fndecl_for_call (call, ctxt);
    4509                 :            : 
    4510                 :       1233 :   reachable_regions reachable_regions (this);
    4511                 :            : 
    4512                 :            :   /* Determine the reachable regions and their mutability.  */
    4513                 :       1233 :   {
    4514                 :            :     /* Globals.  */
    4515                 :       1233 :     region_id globals_rid = get_globals_region_id ();
    4516                 :       1233 :     if (!globals_rid.null_p ())
    4517                 :        265 :       reachable_regions.add (globals_rid, true);
    4518                 :            : 
    4519                 :            :     /* Params that are pointers.  */
    4520                 :       1233 :     tree iter_param_types = NULL_TREE;
    4521                 :       1233 :     if (fndecl)
    4522                 :       1217 :       iter_param_types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
    4523                 :       2101 :     for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (call); arg_idx++)
    4524                 :            :       {
    4525                 :            :         /* Track expected param type, where available.  */
    4526                 :        868 :         tree param_type = NULL_TREE;
    4527                 :        868 :         if (iter_param_types)
    4528                 :            :           {
    4529                 :        811 :             param_type = TREE_VALUE (iter_param_types);
    4530                 :        811 :             gcc_assert (param_type);
    4531                 :        811 :             iter_param_types = TREE_CHAIN (iter_param_types);
    4532                 :            :           }
    4533                 :            : 
    4534                 :        868 :         tree parm = gimple_call_arg (call, arg_idx);
    4535                 :        868 :         svalue_id parm_sid = get_rvalue (parm, ctxt);
    4536                 :        868 :         svalue *parm_sval = get_svalue (parm_sid);
    4537                 :        868 :         if (parm_sval)
    4538                 :        868 :           if (region_svalue *parm_ptr = parm_sval->dyn_cast_region_svalue ())
    4539                 :            :             {
    4540                 :        334 :               region_id pointee_rid = parm_ptr->get_pointee ();
    4541                 :        334 :               bool is_mutable = true;
    4542                 :        334 :               if (param_type
    4543                 :        326 :                   && TREE_CODE (param_type) == POINTER_TYPE
    4544                 :        660 :                   &&  TYPE_READONLY (TREE_TYPE (param_type)))
    4545                 :            :                 is_mutable = false;
    4546                 :        334 :               reachable_regions.add (pointee_rid, is_mutable);
    4547                 :            :             }
    4548                 :            :         // FIXME: what about compound parms that contain ptrs?
    4549                 :            :       }
    4550                 :            :   }
    4551                 :            : 
    4552                 :            :   /* OK: we now have all reachable regions.
    4553                 :            :      Set them all to new unknown values.  */
    4554                 :      49836 :   for (unsigned i = 0; i < get_num_regions (); i++)
    4555                 :            :     {
    4556                 :      23685 :       region_id iter_rid = region_id::from_int (i);
    4557                 :      23685 :       if (reachable_regions.mutable_p (iter_rid))
    4558                 :            :         {
    4559                 :       1885 :           region *reg = get_region (iter_rid);
    4560                 :            : 
    4561                 :            :           /* Purge any sm-state for any underlying svalue.  */
    4562                 :       1885 :           svalue_id curr_sid = reg->get_value_direct ();
    4563                 :       1885 :           if (!curr_sid.null_p ())
    4564                 :       1192 :             ctxt->on_unknown_change (curr_sid);
    4565                 :            : 
    4566                 :       1885 :           set_to_new_unknown_value (iter_rid,
    4567                 :            :                                     reg->get_type (),
    4568                 :       1885 :                                     ctxt);
    4569                 :            :         }
    4570                 :            :     }
    4571                 :            : 
    4572                 :            :   /* Purge sm-state for any remaining svalues that point to regions that
    4573                 :            :      were reachable.  This helps suppress leak false-positives.
    4574                 :            : 
    4575                 :            :      For example, if we had a malloc call that was cast to a "foo *" type,
    4576                 :            :      we could have a temporary void * for the result of malloc which has its
    4577                 :            :      own svalue, not reachable from the function call, but for which the
    4578                 :            :      "foo *" svalue was reachable.  If we don't purge it, the temporary will
    4579                 :            :      be reported as a leak.  */
    4580                 :            :   int i;
    4581                 :            :   svalue *svalue;
    4582                 :      19984 :   FOR_EACH_VEC_ELT (m_svalues, i, svalue)
    4583                 :      18751 :     if (region_svalue *ptr = svalue->dyn_cast_region_svalue ())
    4584                 :            :       {
    4585                 :       3714 :         region_id pointee_rid = ptr->get_pointee ();
    4586                 :       3714 :         if (reachable_regions.mutable_p (pointee_rid))
    4587                 :        334 :           ctxt->on_unknown_change (svalue_id::from_int (i));
    4588                 :            :       }
    4589                 :            : 
    4590                 :       1233 :   validate ();
    4591                 :       1233 : }
    4592                 :            : 
    4593                 :            : /* Update this model for the RETURN_STMT, using CTXT to report any
    4594                 :            :    diagnostics.  */
    4595                 :            : 
    4596                 :            : void
    4597                 :       1883 : region_model::on_return (const greturn *return_stmt, region_model_context *ctxt)
    4598                 :            : {
    4599                 :       1883 :   tree callee = get_current_function ()->decl;
    4600                 :       1883 :   tree lhs = DECL_RESULT (callee);
    4601                 :       1883 :   tree rhs = gimple_return_retval (return_stmt);
    4602                 :            : 
    4603                 :       1883 :   if (lhs && rhs)
    4604                 :        667 :     set_value (get_lvalue (lhs, ctxt), get_rvalue (rhs, ctxt), ctxt);
    4605                 :       1883 : }
    4606                 :            : 
    4607                 :            : /* Update this model for a call and return of setjmp/sigsetjmp at CALL within
    4608                 :            :    ENODE, using CTXT to report any diagnostics.
    4609                 :            : 
    4610                 :            :    This is for the initial direct invocation of setjmp/sigsetjmp (which returns
    4611                 :            :    0), as opposed to any second return due to longjmp/sigsetjmp.  */
    4612                 :            : 
    4613                 :            : void
    4614                 :         11 : region_model::on_setjmp (const gcall *call, const exploded_node *enode,
    4615                 :            :                          region_model_context *ctxt)
    4616                 :            : {
    4617                 :         11 :   region_id buf_rid = deref_rvalue (gimple_call_arg (call, 0), ctxt);
    4618                 :         11 :   region *buf = get_region (buf_rid);
    4619                 :            : 
    4620                 :            :   /* Create a setjmp_svalue for this call and store it in BUF_RID's region.  */
    4621                 :         11 :   if (buf)
    4622                 :            :     {
    4623                 :         11 :       setjmp_record r (enode, call);
    4624                 :         11 :       svalue *sval = new setjmp_svalue (r, buf->get_type ());
    4625                 :         11 :       svalue_id new_sid = add_svalue (sval);
    4626                 :         11 :       set_value (buf_rid, new_sid, ctxt);
    4627                 :            :     }
    4628                 :            : 
    4629                 :            :   /* Direct calls to setjmp return 0.  */
    4630                 :         11 :   if (tree lhs = gimple_call_lhs (call))
    4631                 :            :     {
    4632                 :          9 :       tree zero = build_int_cst (TREE_TYPE (lhs), 0);
    4633                 :          9 :       svalue_id new_sid = get_or_create_constant_svalue (zero);
    4634                 :          9 :       region_id lhs_rid = get_lvalue (lhs, ctxt);
    4635                 :          9 :       set_value (lhs_rid, new_sid, ctxt);
    4636                 :            :     }
    4637                 :         11 : }
    4638                 :            : 
    4639                 :            : /* Update this region_model for rewinding from a "longjmp" at LONGJMP_CALL
    4640                 :            :    to a "setjmp" at SETJMP_CALL where the final stack depth should be
    4641                 :            :    SETJMP_STACK_DEPTH.  Purge any stack frames, potentially reporting on
    4642                 :            :    leaks to CTXT.  */
    4643                 :            : 
    4644                 :            : void
    4645                 :         14 : region_model::on_longjmp (const gcall *longjmp_call, const gcall *setjmp_call,
    4646                 :            :                           int setjmp_stack_depth,
    4647                 :            :                           region_model_context *ctxt)
    4648                 :            : {
    4649                 :            :   /* Evaluate the val, using the frame of the "longjmp".  */
    4650                 :         14 :   tree fake_retval = gimple_call_arg (longjmp_call, 1);
    4651                 :         14 :   svalue_id fake_retval_sid = get_rvalue (fake_retval, ctxt);
    4652                 :            : 
    4653                 :            :   /* Pop any frames until we reach the stack depth of the function where
    4654                 :            :      setjmp was called.  */
    4655                 :         14 :   gcc_assert (get_stack_depth () >= setjmp_stack_depth);
    4656                 :         29 :   while (get_stack_depth () > setjmp_stack_depth)
    4657                 :            :     {
    4658                 :            :       /* Don't purge unused svalues yet, as we're using fake_retval_sid.  */
    4659                 :         15 :       pop_frame (false, NULL, ctxt);
    4660                 :            :     }
    4661                 :            : 
    4662                 :         14 :   gcc_assert (get_stack_depth () == setjmp_stack_depth);
    4663                 :            : 
    4664                 :            :   /* Assign to LHS of "setjmp" in new_state.  */
    4665                 :         14 :   if (tree lhs = gimple_call_lhs (setjmp_call))
    4666                 :            :     {
    4667                 :            :       /* Passing 0 as the val to longjmp leads to setjmp returning 1.  */
    4668                 :         14 :       tree t_zero = build_int_cst (TREE_TYPE (fake_retval), 0);
    4669                 :         14 :       svalue_id zero_sid = get_or_create_constant_svalue (t_zero);
    4670                 :         14 :       tristate eq_zero = eval_condition (fake_retval_sid, EQ_EXPR, zero_sid);
    4671                 :            :       /* If we have 0, use 1.  */
    4672                 :         14 :       if (eq_zero.is_true ())
    4673                 :            :         {
    4674                 :          2 :           tree t_one = build_int_cst (TREE_TYPE (fake_retval), 1);
    4675                 :          2 :           svalue_id one_sid = get_or_create_constant_svalue (t_one);
    4676                 :          2 :           fake_retval_sid = one_sid;
    4677                 :            :         }
    4678                 :            :       else
    4679                 :            :         {
    4680                 :            :           /* Otherwise note that the value is nonzero.  */
    4681                 :         12 :           m_constraints->add_constraint (fake_retval_sid, NE_EXPR, zero_sid);
    4682                 :            :         }
    4683                 :            : 
    4684                 :         14 :       region_id lhs_rid = get_lvalue (lhs, ctxt);
    4685                 :         14 :       set_value (lhs_rid, fake_retval_sid, ctxt);
    4686                 :            :     }
    4687                 :            : 
    4688                 :            :   /* Now that we've assigned the fake_retval, we can purge the unused
    4689                 :            :      svalues, which could detect leaks.  */
    4690                 :         14 :   purge_unused_svalues (NULL, ctxt, NULL);
    4691                 :         14 :   validate ();
    4692                 :         14 : }
    4693                 :            : 
    4694                 :            : /* Update this region_model for a phi stmt of the form
    4695                 :            :      LHS = PHI <...RHS...>.
    4696                 :            :    where RHS is for the appropriate edge.  */
    4697                 :            : 
    4698                 :            : void
    4699                 :       5778 : region_model::handle_phi (const gphi *phi,
    4700                 :            :                           tree lhs, tree rhs, bool is_back_edge,
    4701                 :            :                           region_model_context *ctxt)
    4702                 :            : {
    4703                 :            :   /* For now, don't bother tracking the .MEM SSA names.  */
    4704                 :       5778 :   if (tree var = SSA_NAME_VAR (lhs))
    4705                 :       5497 :     if (TREE_CODE (var) == VAR_DECL)
    4706                 :       5419 :       if (VAR_DECL_IS_VIRTUAL_OPERAND (var))
    4707                 :       2082 :         return;
    4708                 :            : 
    4709                 :       3696 :   svalue_id rhs_sid = get_rvalue (rhs, ctxt);
    4710                 :            : 
    4711                 :       3696 :   if (is_back_edge && get_svalue (rhs_sid)->get_kind () != SK_UNKNOWN)
    4712                 :            :     {
    4713                 :            :       /* If we have a back edge, we probably have a loop.
    4714                 :            :          Use an unknown value, to avoid effectively unrolling the
    4715                 :            :          loop.
    4716                 :            :          To terminate, we need to avoid generating a series of
    4717                 :            :          models with an unbounded monotonically increasing number of
    4718                 :            :          redundant unknown values; hence we need to purge svalues
    4719                 :            :          before inserting the state into the exploded graph, to
    4720                 :            :          collect unused svalues.  */
    4721                 :       1579 :       set_to_new_unknown_value (get_lvalue (lhs, ctxt), TREE_TYPE (lhs), ctxt);
    4722                 :            :     }
    4723                 :            :   else
    4724                 :       2117 :     set_value (get_lvalue (lhs, ctxt), rhs_sid, ctxt);
    4725                 :            : 
    4726                 :       3696 :   if (ctxt)
    4727                 :       2613 :     ctxt->on_phi (phi, rhs);
    4728                 :            : }
    4729                 :            : 
    4730                 :            : /* Implementation of region_model::get_lvalue; the latter adds type-checking.
    4731                 :            : 
    4732                 :            :    Get the id of the region for PV within this region_model,
    4733                 :            :    emitting any diagnostics to CTXT.  */
    4734                 :            : 
    4735                 :            : region_id
    4736                 :      88446 : region_model::get_lvalue_1 (path_var pv, region_model_context *ctxt)
    4737                 :            : {
    4738                 :      88446 :   tree expr = pv.m_tree;
    4739                 :            : 
    4740                 :      88446 :   gcc_assert (expr);
    4741                 :            : 
    4742                 :      88446 :   switch (TREE_CODE (expr))
    4743                 :            :     {
    4744                 :         34 :     default:
    4745                 :         34 :       return make_region_for_unexpected_tree_code (ctxt, expr,
    4746                 :         34 :                                                    dump_location_t ());
    4747                 :            : 
    4748                 :        631 :     case ARRAY_REF:
    4749                 :        631 :       {
    4750                 :        631 :         tree array = TREE_OPERAND (expr, 0);
    4751                 :        631 :         tree index = TREE_OPERAND (expr, 1);
    4752                 :            : #if 0
    4753                 :            :         // TODO: operands 2 and 3, if present:
    4754                 :            :         gcc_assert (TREE_OPERAND (expr, 2) == NULL_TREE);
    4755                 :            :         gcc_assert (TREE_OPERAND (expr, 3) == NULL_TREE);
    4756                 :            : #endif
    4757                 :            : 
    4758                 :        631 :         region_id array_rid = get_lvalue (array, ctxt);
    4759                 :        631 :         svalue_id index_sid = get_rvalue (index, ctxt);
    4760                 :        631 :         region *base_array_reg = get_region (array_rid);
    4761                 :        631 :         array_region *array_reg  = base_array_reg->dyn_cast_array_region ();
    4762                 :        631 :         if (!array_reg)
    4763                 :            :           {
    4764                 :            :             /* Normally, array_rid ought to refer to an array_region, since
    4765                 :            :                array's type will be ARRAY_TYPE.  However, if we have an
    4766                 :            :                unexpected tree code for array, we could have a
    4767                 :            :                symbolic_region here.  If so, we're in error-handling. */
    4768                 :          0 :             gcc_assert (base_array_reg->get_type () == NULL_TREE);
    4769                 :          0 :             return make_region_for_unexpected_tree_code (ctxt, expr,
    4770                 :          0 :                                                          dump_location_t ());
    4771                 :            :           }
    4772                 :        631 :         return array_reg->get_element (this, array_rid, index_sid, ctxt);
    4773                 :            :       }
    4774                 :         40 :       break;
    4775                 :            : 
    4776                 :         40 :     case BIT_FIELD_REF:
    4777                 :         40 :       {
    4778                 :            :         /* For now, create a view, as if a cast, ignoring the bit positions.  */
    4779                 :         40 :         tree obj = TREE_OPERAND (expr, 0);
    4780                 :         40 :         return get_or_create_view (get_lvalue (obj, ctxt), TREE_TYPE (expr),
    4781                 :         40 :                                    ctxt);
    4782                 :       1701 :       };
    4783                 :       1701 :       break;
    4784                 :            : 
    4785                 :       1701 :     case MEM_REF:
    4786                 :       1701 :       {
    4787                 :       1701 :         tree ptr = TREE_OPERAND (expr, 0);
    4788                 :       1701 :         tree offset = TREE_OPERAND (expr, 1);
    4789                 :       1701 :         svalue_id ptr_sid = get_rvalue (ptr, ctxt);
    4790                 :       1701 :         svalue_id offset_sid = get_rvalue (offset, ctxt);
    4791                 :       1701 :         return get_or_create_mem_ref (TREE_TYPE (expr), ptr_sid,
    4792                 :       1701 :                                       offset_sid, ctxt);
    4793                 :            :       }
    4794                 :       8139 :       break;
    4795                 :            : 
    4796                 :       8139 :     case VAR_DECL:
    4797                 :            :       /* Handle globals.  */
    4798                 :       8139 :       if (is_global_var (expr))
    4799                 :            :         {
    4800                 :       3588 :           region_id globals_rid
    4801                 :       3588 :             = get_root_region ()->ensure_globals_region (this);
    4802                 :       3588 :           map_region *globals = get_region<map_region> (globals_rid);
    4803                 :       3588 :           region_id var_rid = globals->get_or_create (this, globals_rid, expr,
    4804                 :       3588 :                                                       TREE_TYPE (expr), ctxt);
    4805                 :       3588 :           return var_rid;
    4806                 :            :         }
    4807                 :            : 
    4808                 :            :       /* Fall through.  */
    4809                 :            : 
    4810                 :      78138 :     case SSA_NAME:
    4811                 :      78138 :     case PARM_DECL:
    4812                 :      78138 :     case RESULT_DECL:
    4813                 :      78138 :       {
    4814                 :      78138 :         gcc_assert (TREE_CODE (expr) == SSA_NAME
    4815                 :            :                     || TREE_CODE (expr) == PARM_DECL
    4816                 :            :                     || TREE_CODE (expr) == VAR_DECL
    4817                 :            :                     || TREE_CODE (expr) == RESULT_DECL);
    4818                 :            : 
    4819                 :      78138 :         int stack_depth = pv.m_stack_depth;
    4820                 :      78138 :         stack_region *stack = get_root_region ()->get_stack_region (this);
    4821                 :      78138 :         gcc_assert (stack);
    4822                 :      78138 :         region_id frame_rid = stack->get_frame_rid (stack_depth);
    4823                 :      78138 :         frame_region *frame = get_region <frame_region> (frame_rid);
    4824                 :      78138 :         gcc_assert (frame);
    4825                 :      78138 :         region_id child_rid = frame->get_or_create (this, frame_rid, expr,
    4826                 :      78138 :                                                     TREE_TYPE (expr), ctxt);
    4827                 :      78138 :         return child_rid;
    4828                 :            :       }
    4829                 :            : 
    4830                 :       3092 :     case COMPONENT_REF:
    4831                 :       3092 :       {
    4832                 :            :         /* obj.field  */
    4833                 :       3092 :         tree obj = TREE_OPERAND (expr, 0);
    4834                 :       3092 :         tree field = TREE_OPERAND (expr, 1);
    4835                 :       3092 :         tree obj_type = TREE_TYPE (obj);
    4836                 :       3092 :         if (TREE_CODE (obj_type) != RECORD_TYPE
    4837                 :       3092 :             && TREE_CODE (obj_type) != UNION_TYPE)
    4838                 :          9 :           return make_region_for_unexpected_tree_code (ctxt, obj_type,
    4839                 :          9 :                                                        dump_location_t ());
    4840                 :       3083 :         region_id obj_rid = get_lvalue (obj, ctxt);
    4841                 :       3083 :         region_id struct_or_union_rid
    4842                 :       3083 :           = get_or_create_view (obj_rid, TREE_TYPE (obj), ctxt);
    4843                 :       3083 :         return get_field_region (struct_or_union_rid, field, ctxt);
    4844                 :            :       }
    4845                 :         18 :       break;
    4846                 :            : 
    4847                 :         18 :     case CONST_DECL:
    4848                 :         18 :       {
    4849                 :         18 :         tree cst_type = TREE_TYPE (expr);
    4850                 :         18 :         region_id cst_rid = add_region_for_type (m_root_rid, cst_type, ctxt);
    4851                 :         18 :         if (tree value = DECL_INITIAL (expr))
    4852                 :            :           {
    4853                 :         18 :             svalue_id sid = get_rvalue (value, ctxt);
    4854                 :         18 :             get_region (cst_rid)->set_value (*this, cst_rid, sid, ctxt);
    4855                 :            :           }
    4856                 :         18 :         return cst_rid;
    4857                 :            :       }
    4858                 :       1056 :       break;
    4859                 :            : 
    4860                 :       1056 :     case STRING_CST:
    4861                 :       1056 :       {
    4862                 :       1056 :         tree cst_type = TREE_TYPE (expr);
    4863                 :       1056 :         array_region *cst_region = new array_region (m_root_rid, cst_type);
    4864                 :       1056 :         region_id cst_rid = add_region (cst_region);
    4865                 :       1056 :         svalue_id cst_sid = get_or_create_constant_svalue (expr);
    4866                 :       1056 :         cst_region->set_value (*this, cst_rid, cst_sid, ctxt);
    4867                 :       1056 :         return cst_rid;
    4868                 :            :       }
    4869                 :        148 :       break;
    4870                 :            : 
    4871                 :        148 :     case NOP_EXPR:
    4872                 :        148 :     case VIEW_CONVERT_EXPR:
    4873                 :        148 :       {
    4874                 :        148 :         tree obj = TREE_OPERAND (expr, 0);
    4875                 :        148 :         return get_or_create_view (get_lvalue (obj, ctxt), TREE_TYPE (expr),
    4876                 :        148 :                                    ctxt);
    4877                 :            :       };
    4878                 :            :       break;
    4879                 :            :     }
    4880                 :            : }
    4881                 :            : 
    4882                 :            : /* If we see a tree code we don't know how to handle, rather than
    4883                 :            :    ICE or generate bogus results, create a dummy region, and notify
    4884                 :            :    CTXT so that it can mark the new state as being not properly
    4885                 :            :    modelled.  The exploded graph can then stop exploring that path,
    4886                 :            :    since any diagnostics we might issue will have questionable
    4887                 :            :    validity.  */
    4888                 :            : 
    4889                 :            : region_id
    4890                 :         61 : region_model::make_region_for_unexpected_tree_code (region_model_context *ctxt,
    4891                 :            :                                                     tree t,
    4892                 :            :                                                     const dump_location_t &loc)
    4893                 :            : {
    4894                 :         61 :   gcc_assert (ctxt);
    4895                 :         61 :   region_id new_rid
    4896                 :         61 :     = add_region (new symbolic_region (m_root_rid, NULL_TREE, false));
    4897                 :         61 :   ctxt->on_unexpected_tree_code (t, loc);
    4898                 :         61 :   return new_rid;
    4899                 :            : }
    4900                 :            : 
    4901                 :            : /* Assert that SRC_TYPE can be converted to DST_TYPE as a no-op.  */
    4902                 :            : 
    4903                 :            : static void
    4904                 :     943127 : assert_compat_types (tree src_type, tree dst_type)
    4905                 :            : {
    4906                 :     943127 :   if (src_type && dst_type && !VOID_TYPE_P (dst_type))
    4907                 :     943022 :     gcc_checking_assert (useless_type_conversion_p (src_type, dst_type));
    4908                 :     943127 : }
    4909                 :            : 
    4910                 :            : /* Get the id of the region for PV within this region_model,
    4911                 :            :    emitting any diagnostics to CTXT.  */
    4912                 :            : 
    4913                 :            : region_id
    4914                 :      88494 : region_model::get_lvalue (path_var pv, region_model_context *ctxt)
    4915                 :            : {
    4916                 :      88494 :   if (pv.m_tree == NULL_TREE)
    4917                 :         48 :     return region_id::null ();
    4918                 :            : 
    4919                 :      88446 :   region_id result_rid = get_lvalue_1 (pv, ctxt);
    4920                 :      88446 :   assert_compat_types (get_region (result_rid)->get_type (),
    4921                 :      88446 :                        TREE_TYPE (pv.m_tree));
    4922                 :      88446 :   return result_rid;
    4923                 :            : }
    4924                 :            : 
    4925                 :            : /* Get the region_id for EXPR within this region_model (assuming the most
    4926                 :            :    recent stack frame if it's a local).  */
    4927                 :            : 
    4928                 :            : region_id
    4929                 :      23284 : region_model::get_lvalue (tree expr, region_model_context *ctxt)
    4930                 :            : {
    4931                 :      23284 :   return get_lvalue (path_var (expr, get_stack_depth () - 1), ctxt);
    4932                 :            : }
    4933                 :            : 
    4934                 :            : /* Implementation of region_model::get_rvalue; the latter adds type-checking.
    4935                 :            : 
    4936                 :            :    Get the value of PV within this region_model,
    4937                 :            :    emitting any diagnostics to CTXT.  */
    4938                 :            : 
    4939                 :            : svalue_id
    4940                 :     854681 : region_model::get_rvalue_1 (path_var pv, region_model_context *ctxt)
    4941                 :            : {
    4942                 :     854681 :   gcc_assert (pv.m_tree);
    4943                 :            : 
    4944                 :     854681 :   switch (TREE_CODE (pv.m_tree))
    4945                 :            :     {
    4946                 :         94 :     default:
    4947                 :         94 :       {
    4948                 :         94 :         svalue *unknown_sval = new unknown_svalue (TREE_TYPE (pv.m_tree));
    4949                 :         94 :         return add_svalue (unknown_sval);
    4950                 :            :       }
    4951                 :      37691 :       break;
    4952                 :            : 
    4953                 :      37691 :     case ADDR_EXPR:
    4954                 :      37691 :       {
    4955                 :            :         /* "&EXPR".  */
    4956                 :      37691 :         tree expr = pv.m_tree;
    4957                 :      37691 :         tree op0 = TREE_OPERAND (expr, 0);
    4958                 :      37691 :         if (TREE_CODE (op0) == FUNCTION_DECL)
    4959                 :      35580 :           return get_svalue_for_fndecl (TREE_TYPE (expr), op0, ctxt);
    4960                 :       2111 :         else if (TREE_CODE (op0) == LABEL_DECL)
    4961                 :         10 :           return get_svalue_for_label (TREE_TYPE (expr), op0, ctxt);
    4962                 :       2101 :         region_id expr_rid = get_lvalue (op0, ctxt);
    4963                 :       2101 :         return get_or_create_ptr_svalue (TREE_TYPE (expr), expr_rid);
    4964                 :            :       }
    4965                 :        332 :       break;
    4966                 :            : 
    4967                 :        332 :     case ARRAY_REF:
    4968                 :        332 :       {
    4969                 :        332 :         region_id element_rid = get_lvalue (pv, ctxt);
    4970                 :        332 :         return get_region (element_rid)->get_value (*this, true, ctxt);
    4971                 :            :       }
    4972                 :            : 
    4973                 :     753220 :     case INTEGER_CST:
    4974                 :     753220 :     case REAL_CST:
    4975                 :     753220 :     case STRING_CST:
    4976                 :     753220 :       return get_or_create_constant_svalue (pv.m_tree);
    4977                 :            : 
    4978                 :      63344 :     case COMPONENT_REF:
    4979                 :      63344 :     case MEM_REF:
    4980                 :      63344 :     case SSA_NAME:
    4981                 :      63344 :     case VAR_DECL:
    4982                 :      63344 :     case PARM_DECL:
    4983                 :      63344 :     case RESULT_DECL:
    4984                 :      63344 :       {
    4985                 :      63344 :         region_id var_rid = get_lvalue (pv, ctxt);
    4986                 :      63344 :         return get_region (var_rid)->get_value (*this, true, ctxt);
    4987                 :            :       }
    4988                 :            :     }
    4989                 :            : }
    4990                 :            : 
    4991                 :            : /* Get the value of PV within this region_model,
    4992                 :            :    emitting any diagnostics to CTXT.  */
    4993                 :            : 
    4994                 :            : svalue_id
    4995                 :     864291 : region_model::get_rvalue (path_var pv, region_model_context *ctxt)
    4996                 :            : {
    4997                 :     864291 :   if (pv.m_tree == NULL_TREE)
    4998                 :       9610 :     return svalue_id::null ();
    4999                 :     854681 :   svalue_id result_sid = get_rvalue_1 (pv, ctxt);
    5000                 :            : 
    5001                 :     854681 :   assert_compat_types (get_svalue (result_sid)->get_type (),
    5002                 :     854681 :                        TREE_TYPE (pv.m_tree));
    5003                 :            : 
    5004                 :     854681 :   return result_sid;
    5005                 :            : }
    5006                 :            : 
    5007                 :            : /* Get the value of EXPR within this region_model (assuming the most
    5008                 :            :    recent stack frame if it's a local).  */
    5009                 :            : 
    5010                 :            : svalue_id
    5011                 :     859559 : region_model::get_rvalue (tree expr, region_model_context *ctxt)
    5012                 :            : {
    5013                 :     859559 :   return get_rvalue (path_var (expr, get_stack_depth () - 1), ctxt);
    5014                 :            : }
    5015                 :            : 
    5016                 :            : /* Return an svalue_id for a pointer to RID of type PTR_TYPE, reusing
    5017                 :            :    existing pointer values if one is available.  */
    5018                 :            : 
    5019                 :            : svalue_id
    5020                 :     193701 : region_model::get_or_create_ptr_svalue (tree ptr_type, region_id rid)
    5021                 :            : {
    5022                 :            :   /* Reuse existing region_svalue, if one of the right type is
    5023                 :            :      available.  */
    5024                 :            :   /* In theory we could stash a svalue_id in "region", but differing
    5025                 :            :      pointer types muddles things.
    5026                 :            :      For now, just do a linear search through all existing svalues.  */
    5027                 :     193701 :   int i;
    5028                 :     193701 :   svalue *svalue;
    5029                 :     930790 :   FOR_EACH_VEC_ELT (m_svalues, i, svalue)
    5030                 :     770081 :     if (region_svalue *ptr_svalue = svalue->dyn_cast_region_svalue ())
    5031                 :     139969 :       if (ptr_svalue->get_pointee () == rid
    5032                 :     139969 :           && ptr_svalue->get_type () == ptr_type)
    5033                 :      32992 :         return svalue_id::from_int (i);
    5034                 :            : 
    5035                 :     160709 :   return add_svalue (new region_svalue (ptr_type, rid));
    5036                 :            : }
    5037                 :            : 
    5038                 :            : /* Return an svalue_id for a constant_svalue for CST_EXPR,
    5039                 :            :    creating the constant_svalue if necessary.
    5040                 :            :    The constant_svalue instances are reused, based on pointer equality
    5041                 :            :    of trees  */
    5042                 :            : 
    5043                 :            : svalue_id
    5044                 :     755431 : region_model::get_or_create_constant_svalue (tree cst_expr)
    5045                 :            : {
    5046                 :     755431 :   gcc_assert (cst_expr);
    5047                 :            : 
    5048                 :            :   /* Reuse one if it already exists.  */
    5049                 :            :   // TODO: maybe store a map, rather than do linear search?
    5050                 :            :   int i;
    5051                 :            :   svalue *svalue;
    5052                 :    7054410 :   FOR_EACH_VEC_ELT (m_svalues, i, svalue)
    5053                 :    6480970 :     if (svalue->maybe_get_constant () == cst_expr)
    5054                 :     181994 :       return svalue_id::from_int (i);
    5055                 :            : 
    5056                 :     573437 :   svalue_id cst_sid = add_svalue (new constant_svalue (cst_expr));
    5057                 :     573437 :   return cst_sid;
    5058                 :            : }
    5059                 :            : 
    5060                 :            : /* Return an svalue_id for a region_svalue for FNDECL,
    5061                 :            :    creating the function_region if necessary.  */
    5062                 :            : 
    5063                 :            : svalue_id
    5064                 :      35580 : region_model::get_svalue_for_fndecl (tree ptr_type, tree fndecl,
    5065                 :            :                                      region_model_context *ctxt)
    5066                 :            : {
    5067                 :      35580 :   gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
    5068                 :      35580 :   region_id function_rid = get_region_for_fndecl (fndecl, ctxt);
    5069                 :      35580 :   return get_or_create_ptr_svalue (ptr_type, function_rid);
    5070                 :            : }
    5071                 :            : 
    5072                 :            : /* Return a region_id for a function_region for FNDECL,
    5073                 :            :    creating it if necessary.  */
    5074                 :            : 
    5075                 :            : region_id
    5076                 :      35590 : region_model::get_region_for_fndecl (tree fndecl,
    5077                 :            :                                      region_model_context *ctxt)
    5078                 :            : {
    5079                 :      35590 :   gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
    5080                 :            : 
    5081                 :      35590 :   region_id code_rid = get_root_region ()->ensure_code_region (this);
    5082                 :      35590 :   code_region *code = get_root_region ()->get_code_region (this);
    5083                 :            : 
    5084                 :      71180 :   return code->get_or_create (this, code_rid, fndecl, TREE_TYPE (fndecl),
    5085                 :      35590 :                               ctxt);
    5086                 :            : }
    5087                 :            : 
    5088                 :            : /* Return an svalue_id for a region_svalue for LABEL,
    5089                 :            :    creating the label_region if necessary.  */
    5090                 :            : 
    5091                 :            : svalue_id
    5092                 :         10 : region_model::get_svalue_for_label (tree ptr_type, tree label,
    5093                 :            :                                     region_model_context *ctxt)
    5094                 :            : {
    5095                 :         10 :   gcc_assert (TREE_CODE (label) == LABEL_DECL);
    5096                 :         10 :   region_id label_rid = get_region_for_label (label, ctxt);
    5097                 :         10 :   return get_or_create_ptr_svalue (ptr_type, label_rid);
    5098                 :            : }
    5099                 :            : 
    5100                 :            : /* Return a region_id for a label_region for LABEL,
    5101                 :            :    creating it if necessary.  */
    5102                 :            : 
    5103                 :            : region_id
    5104                 :         10 : region_model::get_region_for_label (tree label,
    5105                 :            :                                     region_model_context *ctxt)
    5106                 :            : {
    5107                 :         10 :   gcc_assert (TREE_CODE (label) == LABEL_DECL);
    5108                 :            : 
    5109                 :         10 :   tree fndecl = DECL_CONTEXT (label);
    5110                 :         10 :   gcc_assert (fndecl && TREE_CODE (fndecl) == FUNCTION_DECL);
    5111                 :            : 
    5112                 :         10 :   region_id func_rid = get_region_for_fndecl (fndecl, ctxt);
    5113                 :         10 :   function_region *func_reg = get_region <function_region> (func_rid);
    5114                 :         20 :   return func_reg->get_or_create (this, func_rid, label, TREE_TYPE (label),
    5115                 :         10 :                                   ctxt);
    5116                 :            : }
    5117                 :            : 
    5118                 :            : /* Build a cast of SRC_EXPR to DST_TYPE, or return NULL_TREE.
    5119                 :            : 
    5120                 :            :    Adapted from gcc::jit::playback::context::build_cast, which in turn is
    5121                 :            :    adapted from
    5122                 :            :      - c/c-typeck.c:build_c_cast
    5123                 :            :      - c/c-convert.c: convert
    5124                 :            :      - convert.h
    5125                 :            :    Only some kinds of cast are currently supported here.  */
    5126                 :            : 
    5127                 :            : static tree
    5128                 :        502 : build_cast (tree dst_type, tree src_expr)
    5129                 :            : {
    5130                 :        502 :   tree result = targetm.convert_to_type (dst_type, src_expr);
    5131                 :        502 :   if (result)
    5132                 :            :     return result;
    5133                 :        502 :   enum tree_code dst_code = TREE_CODE (dst_type);
    5134                 :        502 :   switch (dst_code)
    5135                 :            :     {
    5136                 :        430 :     case INTEGER_TYPE:
    5137                 :        430 :     case ENUMERAL_TYPE:
    5138                 :        430 :       result = convert_to_integer (dst_type, src_expr);
    5139                 :        430 :       goto maybe_fold;
    5140                 :            : 
    5141                 :         16 :     case BOOLEAN_TYPE:
    5142                 :            :       /* Compare with c_objc_common_truthvalue_conversion and
    5143                 :            :          c_common_truthvalue_conversion. */
    5144                 :            :       /* For now, convert to: (src_expr != 0)  */
    5145                 :         16 :       result = build2 (NE_EXPR, dst_type,
    5146                 :            :                        src_expr,
    5147                 :         16 :                        build_int_cst (TREE_TYPE (src_expr), 0));
    5148                 :         16 :       goto maybe_fold;
    5149                 :            : 
    5150                 :          2 :     case REAL_TYPE:
    5151                 :          2 :       result = convert_to_real (dst_type, src_expr);
    5152                 :          2 :       goto maybe_fold;
    5153                 :            : 
    5154                 :         14 :     case POINTER_TYPE:
    5155                 :         14 :       result = build1 (NOP_EXPR, dst_type, src_expr);
    5156                 :         14 :       goto maybe_fold;
    5157                 :            : 
    5158                 :            :     default:
    5159                 :            :       return NULL_TREE;
    5160                 :            : 
    5161                 :        462 :     maybe_fold:
    5162                 :        462 :       if (TREE_CODE (result) != C_MAYBE_CONST_EXPR)
    5163                 :        462 :         result = fold (result);
    5164                 :            :       return result;
    5165                 :            :     }
    5166                 :            : }
    5167                 :            : 
    5168                 :            : /* If the type of SID's underlying value is DST_TYPE, return SID.
    5169                 :            :    Otherwise, attempt to create (or reuse) an svalue representing an access
    5170                 :            :    of SID as a DST_TYPE and return that value's svalue_id.  */
    5171                 :            : 
    5172                 :            : svalue_id
    5173                 :     825971 : region_model::maybe_cast_1 (tree dst_type, svalue_id sid)
    5174                 :            : {
    5175                 :     825971 :   svalue *sval = get_svalue (sid);
    5176                 :     825971 :   tree src_type = sval->get_type ();
    5177                 :     825971 :   if (src_type == dst_type)
    5178                 :     823882 :     return sid;
    5179                 :            : 
    5180                 :       2089 :   if (POINTER_TYPE_P (dst_type)
    5181                 :       1226 :       || POINTER_TYPE_P (src_type))
    5182                 :            :     {
    5183                 :            :       /* Pointer to region.  */
    5184                 :        883 :       if (region_svalue *ptr_sval = sval->dyn_cast_region_svalue ())
    5185                 :        493 :         return get_or_create_ptr_svalue (dst_type, ptr_sval->get_pointee ());
    5186                 :            : 
    5187                 :            :       /* Unknown pointer?   Get or create a new unknown pointer of the
    5188                 :            :          correct type, preserving the equality between the pointers.  */
    5189                 :        390 :       if (sval->dyn_cast_unknown_svalue ())
    5190                 :            :         {
    5191                 :        229 :           equiv_class &ec = m_constraints->get_equiv_class (sid);
    5192                 :            : 
    5193                 :            :           /* Look for an existing pointer of the correct type within the EC.  */
    5194                 :        229 :           int i;
    5195                 :        229 :           svalue_id *equiv_sid;
    5196                 :        422 :           FOR_EACH_VEC_ELT (ec.m_vars, i, equiv_sid)
    5197                 :            :             {
    5198                 :        270 :               svalue *equiv_val = get_svalue (*equiv_sid);
    5199                 :        270 :               if (equiv_val->get_type () == dst_type)
    5200                 :         77 :                 return *equiv_sid;
    5201                 :            :             }
    5202                 :            : 
    5203                 :            :           /* Otherwise, create a new unknown pointer of the correct type.  */
    5204                 :        152 :           svalue *unknown_sval = new unknown_svalue (dst_type);
    5205                 :        152 :           svalue_id new_ptr_sid = add_svalue (unknown_sval);
    5206                 :        152 :           m_constraints->add_constraint (sid, EQ_EXPR, new_ptr_sid);
    5207                 :        152 :           return new_ptr_sid;
    5208                 :            :         }
    5209                 :            :     }
    5210                 :            : 
    5211                 :            :   /* Attempt to cast constants.  */
    5212                 :       1367 :   if (tree src_cst = sval->maybe_get_constant ())
    5213                 :            :     {
    5214                 :        502 :       if (tree dst = build_cast (dst_type, src_cst))
    5215                 :        462 :         if (CONSTANT_CLASS_P (dst))
    5216                 :        462 :           return get_or_create_constant_svalue (dst);
    5217                 :            :     }
    5218                 :            : 
    5219                 :            :   /* Otherwise, return a new unknown value.  */
    5220                 :        905 :   svalue *unknown_sval = new unknown_svalue (dst_type);
    5221                 :        905 :   return add_svalue (unknown_sval);
    5222                 :            : }
    5223                 :            : 
    5224                 :            : /* If the type of SID's underlying value is DST_TYPE, return SID.
    5225                 :            :    Otherwise, attempt to create (or reuse) an svalue representing an access
    5226                 :            :    of SID as a DST_TYPE and return that value's svalue_id.
    5227                 :            : 
    5228                 :            :    If the result != SID, then call CTXT's on_cast vfunc (if CTXT is non-NULL),
    5229                 :            :    so that sm-state can be propagated from SID to the result.  */
    5230                 :            : 
    5231                 :            : svalue_id
    5232                 :     825971 : region_model::maybe_cast (tree dst_type, svalue_id sid,
    5233                 :            :                           region_model_context *ctxt)
    5234                 :            : {
    5235                 :     825971 :   svalue_id result = maybe_cast_1 (dst_type, sid);
    5236                 :     825971 :   if (result != sid)
    5237                 :       2089 :     if (ctxt)
    5238                 :            :       {
    5239                 :            :         /* Notify ctxt about a cast, so any sm-state can be copied.  */
    5240                 :       1812 :         ctxt->on_cast (sid, result);
    5241                 :            :       }
    5242                 :     825971 :   return result;
    5243                 :            : }
    5244                 :            : 
    5245                 :            : /* Ensure that the region for OBJ_RID has a child region for FIELD;
    5246                 :            :    return the child region's region_id.  */
    5247                 :            : 
    5248                 :            : region_id
    5249                 :       3083 : region_model::get_field_region (region_id struct_or_union_rid, tree field,
    5250                 :            :                                 region_model_context *ctxt)
    5251                 :            : {
    5252                 :       3083 :   struct_or_union_region *sou_reg
    5253                 :       3083 :     = get_region<struct_or_union_region> (struct_or_union_rid);
    5254                 :            : 
    5255                 :            :   /* Inherit constness from parent type.  */
    5256                 :       3083 :   const int qual_mask = TYPE_QUAL_CONST;
    5257                 :       3083 :   int sou_quals = TYPE_QUALS (sou_reg->get_type ()) & qual_mask;
    5258                 :       3083 :   tree field_type = TREE_TYPE (field);
    5259                 :       3083 :   tree field_type_with_quals = build_qualified_type (field_type, sou_quals);
    5260                 :            : 
    5261                 :            :   // TODO: maybe convert to a vfunc?
    5262                 :       3083 :   if (sou_reg->get_kind () == RK_UNION)
    5263                 :            :     {
    5264                 :            :       /* Union.
    5265                 :            :          Get a view of the union as a whole, with the type of the field.  */
    5266                 :         41 :       region_id view_rid
    5267                 :         41 :         = get_or_create_view (struct_or_union_rid, field_type_with_quals, ctxt);
    5268                 :         41 :       return view_rid;
    5269                 :            :     }
    5270                 :            :   else
    5271                 :            :     {
    5272                 :            :       /* Struct.  */
    5273                 :       3042 :       region_id child_rid
    5274                 :            :         = sou_reg->get_or_create (this, struct_or_union_rid, field,
    5275                 :       3042 :                                   field_type_with_quals, ctxt);
    5276                 :       3042 :       return child_rid;
    5277                 :            :     }
    5278                 :            : }
    5279                 :            : 
    5280                 :            : /* Get a region_id for referencing PTR_SID, creating a region if need be, and
    5281                 :            :    potentially generating warnings via CTXT.  */
    5282                 :            : 
    5283                 :            : region_id
    5284                 :       2126 : region_model::deref_rvalue (svalue_id ptr_sid, region_model_context *ctxt)
    5285                 :            : {
    5286                 :       2126 :   gcc_assert (!ptr_sid.null_p ());
    5287                 :       2126 :   svalue *ptr_svalue = get_svalue (ptr_sid);
    5288                 :       2126 :   gcc_assert (ptr_svalue);
    5289                 :            : 
    5290                 :       2126 :   switch (ptr_svalue->get_kind ())
    5291                 :            :     {
    5292                 :       1588 :     case SK_REGION:
    5293                 :       1588 :       {
    5294                 :       1588 :         region_svalue *region_sval = as_a <region_svalue *> (ptr_svalue);
    5295                 :       1588 :         return region_sval->get_pointee ();
    5296                 :            :       }
    5297                 :            : 
    5298                 :         51 :     case SK_CONSTANT:
    5299                 :         51 :       goto create_symbolic_region;
    5300                 :            : 
    5301                 :         26 :     case SK_POISONED:
    5302                 :         26 :       {
    5303                 :         26 :         if (ctxt)
    5304                 :         12 :           if (tree ptr = get_representative_tree (ptr_sid))
    5305                 :            :             {
    5306                 :         12 :               poisoned_svalue *poisoned_sval
    5307                 :         12 :                 = as_a <poisoned_svalue *> (ptr_svalue);
    5308                 :         12 :               enum poison_kind pkind = poisoned_sval->get_poison_kind ();
    5309                 :         12 :               ctxt->warn (new poisoned_value_diagnostic (ptr, pkind));
    5310                 :            :             }
    5311                 :         26 :         goto create_symbolic_region;
    5312                 :            :       }
    5313                 :            : 
    5314                 :        538 :     case SK_UNKNOWN:
    5315                 :        538 :       {
    5316                 :        538 :       create_symbolic_region:
    5317                 :            :         /* We need a symbolic_region to represent this unknown region.
    5318                 :            :            We don't know if it on the heap, stack, or a global,
    5319                 :            :            so use the root region as parent.  */
    5320                 :        538 :         region_id new_rid
    5321                 :        538 :           = add_region (new symbolic_region (m_root_rid, NULL_TREE, false));
    5322                 :            : 
    5323                 :            :         /* We need to write the region back into the pointer,
    5324                 :            :            or we'll get a new, different region each time.
    5325                 :            :            We do this by changing the meaning of ptr_sid, replacing
    5326                 :            :            the unknown value with the ptr to the new region.
    5327                 :            :            We replace the meaning of the ID rather than simply writing
    5328                 :            :            to PTR's lvalue since there could be several places sharing
    5329                 :            :            the same unknown ptr value.  */
    5330                 :        538 :         svalue *ptr_val
    5331                 :        538 :           = new region_svalue (ptr_svalue->get_type (), new_rid);
    5332                 :        538 :         replace_svalue (ptr_sid, ptr_val);
    5333                 :            : 
    5334                 :        538 :         return new_rid;
    5335                 :            :       }
    5336                 :            : 
    5337                 :          0 :     case SK_SETJMP:
    5338                 :          0 :       goto create_symbolic_region;
    5339                 :            :     }
    5340                 :            : 
    5341                 :          0 :   gcc_unreachable ();
    5342                 :            : }
    5343                 :            : 
    5344                 :            : /* Get a region_id for referencing PTR, creating a region if need be, and
    5345                 :            :    potentially generating warnings via CTXT.  */
    5346                 :            : 
    5347                 :            : region_id
    5348                 :         39 : region_model::deref_rvalue (tree ptr, region_model_context *ctxt)
    5349                 :            : {
    5350                 :         39 :   svalue_id ptr_sid = get_rvalue (ptr, ctxt);
    5351                 :         39 :   return deref_rvalue (ptr_sid, ctxt);
    5352                 :            : }
    5353                 :            : 
    5354                 :            : /* Set the value of the region given by LHS_RID to the value given
    5355                 :            :    by RHS_SID.  */
    5356                 :            : 
    5357                 :            : void
    5358                 :      17596 : region_model::set_value (region_id lhs_rid, svalue_id rhs_sid,
    5359                 :            :                          region_model_context *ctxt)
    5360                 :            : {
    5361                 :      17596 :   gcc_assert (!lhs_rid.null_p ());
    5362                 :      17596 :   gcc_assert (!rhs_sid.null_p ());
    5363                 :      17596 :   get_region (lhs_rid)->set_value (*this, lhs_rid, rhs_sid, ctxt);
    5364                 :      17596 : }
    5365                 :            : 
    5366                 :            : /* Set the value of the region given by LHS to the value given
    5367                 :            :    by RHS.  */
    5368                 :            : 
    5369                 :            : void
    5370                 :          8 : region_model::set_value (tree lhs, tree rhs, region_model_context *ctxt)
    5371                 :            : {
    5372                 :          8 :   region_id lhs_rid = get_lvalue (lhs, ctxt);
    5373                 :          8 :   svalue_id rhs_sid = get_rvalue (rhs, ctxt);
    5374                 :          8 :   gcc_assert (!lhs_rid.null_p ());
    5375                 :          8 :   gcc_assert (!rhs_sid.null_p ());
    5376                 :          8 :   set_value (lhs_rid, rhs_sid, ctxt);
    5377                 :          8 : }
    5378                 :            : 
    5379                 :            : /* Determine what is known about the condition "LHS_SID OP RHS_SID" within
    5380                 :            :    this model.  */
    5381                 :            : 
    5382                 :            : tristate
    5383                 :       9968 : region_model::eval_condition (svalue_id lhs_sid,
    5384                 :            :                               enum tree_code op,
    5385                 :            :                               svalue_id rhs_sid) const
    5386                 :            : {
    5387                 :       9968 :   svalue *lhs = get_svalue (lhs_sid);
    5388                 :       9968 :   svalue *rhs = get_svalue (rhs_sid);
    5389                 :            : 
    5390                 :            :   /* For now, make no attempt to capture constraints on floating-point
    5391                 :            :      values.  */
    5392                 :       9968 :   if ((lhs->get_type () && FLOAT_TYPE_P (lhs->get_type ()))
    5393                 :      19918 :       || (rhs->get_type () && FLOAT_TYPE_P (rhs->get_type ())))
    5394                 :         18 :     return tristate::unknown ();
    5395                 :            : 
    5396                 :       9950 :   tristate ts = eval_condition_without_cm (lhs_sid, op, rhs_sid);
    5397                 :            : 
    5398                 :       9950 :   if (ts.is_known ())
    5399                 :       1123 :     return ts;
    5400                 :            : 
    5401                 :            :   /* Otherwise, try constraints.  */
    5402                 :       8827 :   return m_constraints->eval_condition (lhs_sid, op, rhs_sid);
    5403                 :            : }
    5404                 :            : 
    5405                 :            : /* Determine what is known about the condition "LHS_SID OP RHS_SID" within
    5406                 :            :    this model, without resorting to the constraint_manager.
    5407                 :            : 
    5408                 :            :    This is exposed so that impl_region_model_context::on_state_leak can
    5409                 :            :    check for equality part-way through region_model::purge_unused_svalues
    5410                 :            :    without risking creating new ECs.  */
    5411                 :            : 
    5412                 :            : tristate
    5413                 :      22851 : region_model::eval_condition_without_cm (svalue_id lhs_sid,
    5414                 :            :                                          enum tree_code op,
    5415                 :            :                                          svalue_id rhs_sid) const
    5416                 :            : {
    5417                 :      22851 :   svalue *lhs = get_svalue (lhs_sid);
    5418                 :      22851 :   svalue *rhs = get_svalue (rhs_sid);
    5419                 :      22851 :   gcc_assert (lhs);
    5420                 :      22851 :   gcc_assert (rhs);
    5421                 :            : 
    5422                 :            :   /* See what we know based on the values.  */
    5423                 :      22851 :   if (lhs && rhs)
    5424                 :            :     {
    5425                 :            :       /* For now, make no attempt to capture constraints on floating-point
    5426                 :            :          values.  */
    5427                 :      22851 :       if ((lhs->get_type () && FLOAT_TYPE_P (lhs->get_type ()))
    5428                 :      45702 :           || (rhs->get_type () && FLOAT_TYPE_P (rhs->get_type ())))
    5429                 :         92 :         return tristate::unknown ();
    5430                 :            : 
    5431                 :      22759 :       if (lhs == rhs)
    5432                 :            :         {
    5433                 :            :           /* If we have the same svalue, then we have equality
    5434                 :            :              (apart from NaN-handling).
    5435                 :            :              TODO: should this definitely be the case for poisoned values?  */
    5436                 :        547 :           switch (op)
    5437                 :            :             {
    5438                 :        296 :             case EQ_EXPR:
    5439                 :        296 :             case GE_EXPR:
    5440                 :        296 :             case LE_EXPR:
    5441                 :        296 :               return tristate::TS_TRUE;
    5442                 :            : 
    5443                 :        251 :             case NE_EXPR:
    5444                 :        251 :             case GT_EXPR:
    5445                 :        251 :             case LT_EXPR:
    5446                 :        251 :               return tristate::TS_FALSE;
    5447                 :            : 
    5448                 :            :             default:
    5449                 :            :               /* For other ops, use the logic below.  */
    5450                 :            :               break;
    5451                 :            :             }
    5452                 :            :         }
    5453                 :            : 
    5454                 :            :       /* If we have a pair of region_svalues, compare them.  */
    5455                 :      22212 :       if (region_svalue *lhs_ptr = lhs->dyn_cast_region_svalue ())
    5456                 :       6923 :         if (region_svalue *rhs_ptr = rhs->dyn_cast_region_svalue ())
    5457                 :            :           {
    5458                 :       1199 :             tristate res = region_svalue::eval_condition (lhs_ptr, op, rhs_ptr);
    5459                 :       1199 :             if (res.is_known ())
    5460                 :       1177 :               return res;
    5461                 :            :             /* Otherwise, only known through constraints.  */
    5462                 :            :           }
    5463                 :            : 
    5464                 :            :       /* If we have a pair of constants, compare them.  */
    5465                 :      21035 :       if (constant_svalue *cst_lhs = lhs->dyn_cast_constant_svalue ())
    5466                 :       2559 :         if (constant_svalue *cst_rhs = rhs->dyn_cast_constant_svalue ())
    5467                 :        898 :           return constant_svalue::eval_condition (cst_lhs, op, cst_rhs);
    5468                 :            : 
    5469                 :            :       /* Handle comparison of a region_svalue against zero.  */
    5470                 :      20137 :       if (region_svalue *ptr = lhs->dyn_cast_region_svalue ())
    5471                 :       5746 :         if (constant_svalue *cst_rhs = rhs->dyn_cast_constant_svalue ())
    5472                 :       2518 :           if (zerop (cst_rhs->get_constant ()))
    5473                 :            :             {
    5474                 :            :               /* A region_svalue is a non-NULL pointer, except in certain
    5475                 :            :                  special cases (see the comment for region::non_null_p.  */
    5476                 :        872 :               region *pointee = get_region (ptr->get_pointee ());
    5477                 :        872 :               if (pointee->non_null_p (*this))
    5478                 :            :                 {
    5479                 :        538 :                   switch (op)
    5480                 :            :                     {
    5481                 :          0 :                     default:
    5482                 :          0 :                       gcc_unreachable ();
    5483                 :            : 
    5484                 :        506 :                     case EQ_EXPR:
    5485                 :        506 :                     case GE_EXPR:
    5486                 :        506 :                     case LE_EXPR:
    5487                 :        506 :                       return tristate::TS_FALSE;
    5488                 :            : 
    5489                 :         32 :                     case NE_EXPR:
    5490                 :         32 :                     case GT_EXPR:
    5491                 :         32 :                     case LT_EXPR:
    5492                 :         32 :                       return tristate::TS_TRUE;
    5493                 :            :                     }
    5494                 :            :                 }
    5495                 :            :             }
    5496                 :            :     }
    5497                 :            : 
    5498                 :      19599 :   return tristate::TS_UNKNOWN;
    5499                 :            : }
    5500                 :            : 
    5501                 :            : /* Attempt to add the constraint "LHS OP RHS" to this region_model.
    5502                 :            :    If it is consistent with existing constraints, add it, and return true.
    5503                 :            :    Return false if it contradicts existing constraints.
    5504                 :            :    Use CTXT for reporting any diagnostics associated with the accesses.  */
    5505                 :            : 
    5506                 :            : bool
    5507                 :       7436 : region_model::add_constraint (tree lhs, enum tree_code op, tree rhs,
    5508                 :            :                               region_model_context *ctxt)
    5509                 :            : {
    5510                 :            :   /* For now, make no attempt to capture constraints on floating-point
    5511                 :            :      values.  */
    5512                 :      14804 :   if (FLOAT_TYPE_P (TREE_TYPE (lhs)) || FLOAT_TYPE_P (TREE_TYPE (rhs)))
    5513                 :            :     return true;
    5514                 :            : 
    5515                 :       7368 :   svalue_id lhs_sid = get_rvalue (lhs, ctxt);
    5516                 :       7368 :   svalue_id rhs_sid = get_rvalue (rhs, ctxt);
    5517                 :            : 
    5518                 :       7368 :   tristate t_cond = eval_condition (lhs_sid, op, rhs_sid);
    5519                 :            : 
    5520                 :            :   /* If we already have the condition, do nothing.  */
    5521                 :       7368 :   if (t_cond.is_true ())
    5522                 :            :     return true;
    5523                 :            : 
    5524                 :            :   /* Reject a constraint that would contradict existing knowledge, as
    5525                 :            :      unsatisfiable.  */
    5526                 :       6769 :   if (t_cond.is_false ())
    5527                 :            :     return false;
    5528                 :            : 
    5529                 :            :   /* Store the constraint.  */
    5530                 :       6263 :   m_constraints->add_constraint (lhs_sid, op, rhs_sid);
    5531                 :            : 
    5532                 :       6263 :   add_any_constraints_from_ssa_def_stmt (lhs, op, rhs, ctxt);
    5533                 :            : 
    5534                 :            :   /* If we now know a symbolic_region is non-NULL, clear its
    5535                 :            :      m_possibly_null.  */
    5536                 :       6263 :   if (zerop (rhs) && op == NE_EXPR)
    5537                 :        937 :     if (region_svalue *ptr = get_svalue (lhs_sid)->dyn_cast_region_svalue ())
    5538                 :            :       {
    5539                 :         47 :         region *pointee = get_region (ptr->get_pointee ());
    5540                 :         47 :         if (symbolic_region *sym_reg = pointee->dyn_cast_symbolic_region ())
    5541                 :         47 :           sym_reg->m_possibly_null = false;
    5542                 :            :       }
    5543                 :            : 
    5544                 :            :   /* Notify the context, if any.  This exists so that the state machines
    5545                 :            :      in a program_state can be notified about the condition, and so can
    5546                 :            :      set sm-state for e.g. unchecked->checked, both for cfg-edges, and
    5547                 :            :      when synthesizing constraints as above.  */
    5548                 :       6263 :   if (ctxt)
    5549                 :       5215 :     ctxt->on_condition (lhs, op, rhs);
    5550                 :            : 
    5551                 :            :   return true;
    5552                 :            : }
    5553                 :            : 
    5554                 :            : /* Subroutine of region_model::add_constraint for handling optimized
    5555                 :            :    && and || conditionals.
    5556                 :            : 
    5557                 :            :    If we have an SSA_NAME for a boolean compared against 0,
    5558                 :            :    look at anything implied by the def stmt and call add_constraint
    5559                 :            :    for it (which could recurse).
    5560                 :            : 
    5561                 :            :    For example, if we have
    5562                 :            :       _1 = p_6 == 0B;
    5563                 :            :       _2 = p_8 == 0B
    5564                 :            :       _3 = _1 | _2
    5565                 :            :     and add the constraint
    5566                 :            :       (_3 == 0),
    5567                 :            :     then the def stmt for _3 implies that _1 and _2 are both false,
    5568                 :            :     and hence we can add the constraints:
    5569                 :            :       p_6 != 0B
    5570                 :            :       p_8 != 0B.  */
    5571                 :            : 
    5572                 :            : void
    5573                 :       6263 : region_model::add_any_constraints_from_ssa_def_stmt (tree lhs,
    5574                 :            :                                                      enum tree_code op,
    5575                 :            :                                                      tree rhs,
    5576                 :            :                                                      region_model_context *ctxt)
    5577                 :            : {
    5578                 :       6263 :   if (TREE_CODE (lhs) != SSA_NAME)
    5579                 :            :     return;
    5580                 :            : 
    5581                 :       5951 :   if (!zerop (rhs))
    5582                 :            :     return;
    5583                 :            : 
    5584                 :       1823 :   if (op != NE_EXPR && op != EQ_EXPR)
    5585                 :            :     return;
    5586                 :            : 
    5587                 :       1710 :   gimple *def_stmt = SSA_NAME_DEF_STMT (lhs);
    5588                 :       1710 :   if (const gassign *assign = dyn_cast<gassign *> (def_stmt))
    5589                 :        518 :     add_any_constraints_from_gassign (op, rhs, assign, ctxt);
    5590                 :       1192 :   else if (gcall *call = dyn_cast<gcall *> (def_stmt))
    5591                 :        800 :     add_any_constraints_from_gcall (op, rhs, call, ctxt);
    5592                 :            : }
    5593                 :            : 
    5594                 :            : /* Add any constraints for an SSA_NAME defined by ASSIGN
    5595                 :            :    where the result OP RHS.  */
    5596                 :            : 
    5597                 :            : void
    5598                 :        518 : region_model::add_any_constraints_from_gassign (enum tree_code op,
    5599                 :            :                                                 tree rhs,
    5600                 :            :                                                 const gassign *assign,
    5601                 :            :                                                 region_model_context *ctxt)
    5602                 :            : {
    5603                 :            :   /* We have either
    5604                 :            :      - "LHS != false" (i.e. LHS is true), or
    5605                 :            :      - "LHS == false" (i.e. LHS is false).  */
    5606                 :        518 :   bool is_true = op == NE_EXPR;
    5607                 :            : 
    5608                 :        518 :   enum tree_code rhs_code = gimple_assign_rhs_code (assign);
    5609                 :            : 
    5610                 :        518 :   switch (rhs_code)
    5611                 :            :     {
    5612                 :            :     default:
    5613                 :            :       break;
    5614                 :            : 
    5615                 :         49 :     case NOP_EXPR:
    5616                 :         49 :       {
    5617                 :         49 :         add_constraint (gimple_assign_rhs1 (assign), op, rhs, ctxt);
    5618                 :            :       }
    5619                 :         49 :       break;
    5620                 :            : 
    5621                 :         12 :     case BIT_AND_EXPR:
    5622                 :         12 :       {
    5623                 :         12 :         if (is_true)
    5624                 :            :           {
    5625                 :            :             /* ...and "LHS == (rhs1 & rhs2) i.e. "(rhs1 & rhs2)" is true
    5626                 :            :                then both rhs1 and rhs2 must be true.  */
    5627                 :          6 :             tree rhs1 = gimple_assign_rhs1 (assign);
    5628                 :          6 :             tree rhs2 = gimple_assign_rhs2 (assign);
    5629                 :          6 :             add_constraint (rhs1, NE_EXPR, boolean_false_node, ctxt);
    5630                 :          6 :             add_constraint (rhs2, NE_EXPR, boolean_false_node, ctxt);
    5631                 :            :           }
    5632                 :            :       }
    5633                 :            :       break;
    5634                 :            : 
    5635                 :         14 :     case BIT_IOR_EXPR:
    5636                 :         14 :       {
    5637                 :         14 :         if (!is_true)
    5638                 :            :           {
    5639                 :            :             /* ...and "LHS == (rhs1 | rhs2)
    5640                 :            :                i.e. "(rhs1 | rhs2)" is false
    5641                 :            :                then both rhs1 and rhs2 must be false.  */
    5642                 :          7 :             tree rhs1 = gimple_assign_rhs1 (assign);
    5643                 :          7 :             tree rhs2 = gimple_assign_rhs2 (assign);
    5644                 :          7 :             add_constraint (rhs1, EQ_EXPR, boolean_false_node, ctxt);
    5645                 :          7 :             add_constraint (rhs2, EQ_EXPR, boolean_false_node, ctxt);
    5646                 :            :           }
    5647                 :            :       }
    5648                 :            :       break;
    5649                 :            : 
    5650                 :         59 :     case EQ_EXPR:
    5651                 :         59 :     case NE_EXPR:
    5652                 :         59 :       {
    5653                 :            :         /* ...and "LHS == (rhs1 OP rhs2)"
    5654                 :            :            then rhs1 OP rhs2 must have the same logical value as LHS.  */
    5655                 :         59 :         tree rhs1 = gimple_assign_rhs1 (assign);
    5656                 :         59 :         tree rhs2 = gimple_assign_rhs2 (assign);
    5657                 :         59 :         if (!is_true)
    5658                 :         33 :           rhs_code
    5659                 :         33 :             = invert_tree_comparison (rhs_code, false /* honor_nans */);
    5660                 :         59 :         add_constraint (rhs1, rhs_code, rhs2, ctxt);
    5661                 :            :       }
    5662                 :         59 :       break;
    5663                 :            :     }
    5664                 :        518 : }
    5665                 :            : 
    5666                 :            : /* Add any constraints for an SSA_NAME defined by CALL
    5667                 :            :    where the result OP RHS.  */
    5668                 :            : 
    5669                 :            : void
    5670                 :        800 : region_model::add_any_constraints_from_gcall (enum tree_code op,
    5671                 :            :                                               tree rhs,
    5672                 :            :                                               const gcall *call,
    5673                 :            :                                               region_model_context *ctxt)
    5674                 :            : {
    5675                 :        800 :   if (gimple_call_builtin_p (call, BUILT_IN_EXPECT)
    5676                 :        796 :       || gimple_call_builtin_p (call, BUILT_IN_EXPECT_WITH_PROBABILITY)
    5677                 :       1594 :       || gimple_call_internal_p (call, IFN_BUILTIN_EXPECT))
    5678                 :            :     {
    5679                 :            :       /* __builtin_expect's return value is its initial argument.  */
    5680                 :         21 :       add_constraint (gimple_call_arg (call, 0), op, rhs, ctxt);
    5681                 :            :     }
    5682                 :        800 : }
    5683                 :            : 
    5684                 :            : /* Determine what is known about the condition "LHS OP RHS" within
    5685                 :            :    this model.
    5686                 :            :    Use CTXT for reporting any diagnostics associated with the accesses.  */
    5687                 :            : 
    5688                 :            : tristate
    5689                 :       2010 : region_model::eval_condition (tree lhs,
    5690                 :            :                               enum tree_code op,
    5691                 :            :                               tree rhs,
    5692                 :            :                               region_model_context *ctxt)
    5693                 :            : {
    5694                 :            :   /* For now, make no attempt to model constraints on floating-point
    5695                 :            :      values.  */
    5696                 :       4016 :   if (FLOAT_TYPE_P (TREE_TYPE (lhs)) || FLOAT_TYPE_P (TREE_TYPE (rhs)))
    5697                 :          4 :     return tristate::unknown ();
    5698                 :            : 
    5699                 :       2006 :   return eval_condition (get_rvalue (lhs, ctxt), op, get_rvalue (rhs, ctxt));
    5700                 :            : }
    5701                 :            : 
    5702                 :            : /* If SID is a constant value, return the underlying tree constant.
    5703                 :            :    Otherwise, return NULL_TREE.  */
    5704                 :            : 
    5705                 :            : tree
    5706                 :       2065 : region_model::maybe_get_constant (svalue_id sid) const
    5707                 :            : {
    5708                 :       2065 :   gcc_assert (!sid.null_p ());
    5709                 :       2065 :   svalue *sval = get_svalue (sid);
    5710                 :       2065 :   return sval->maybe_get_constant ();
    5711                 :            : }
    5712                 :            : 
    5713                 :            : /* Create a new child region of the heap (creating the heap region if
    5714                 :            :    necessary).
    5715                 :            :    Return the region_id of the new child region.  */
    5716                 :            : 
    5717                 :            : region_id
    5718                 :     154031 : region_model::add_new_malloc_region ()
    5719                 :            : {
    5720                 :     154031 :   region_id heap_rid
    5721                 :     154031 :     = get_root_region ()->ensure_heap_region (this);
    5722                 :     154031 :   return add_region (new symbolic_region (heap_rid, NULL_TREE, true));
    5723                 :            : }
    5724                 :            : 
    5725                 :            : /* Attempt to return a tree that represents SID, or return NULL_TREE.  */
    5726                 :            : 
    5727                 :            : tree
    5728                 :       1093 : region_model::get_representative_tree (svalue_id sid) const
    5729                 :            : {
    5730                 :       1093 :   if (sid.null_p ())
    5731                 :            :     return NULL_TREE;
    5732                 :            : 
    5733                 :            :   /* Find the first region that stores the value (e.g. a local) and
    5734                 :            :      generate a representative tree for it.  */
    5735                 :            :   unsigned i;
    5736                 :            :   region *region;
    5737                 :       2018 :   FOR_EACH_VEC_ELT (m_regions, i, region)
    5738                 :       1982 :     if (sid == region->get_value_direct ())
    5739                 :            :       {
    5740                 :        265 :         path_var pv = get_representative_path_var (region_id::from_int (i));
    5741                 :        265 :         if (pv.m_tree)
    5742                 :        265 :           return pv.m_tree;
    5743                 :            :       }
    5744                 :            : 
    5745                 :            :   /* Handle string literals and various other pointers.  */
    5746                 :         36 :   svalue *sval = get_svalue (sid);
    5747                 :         36 :   if (region_svalue *ptr_sval = sval->dyn_cast_region_svalue ())
    5748                 :            :     {
    5749                 :          2 :       region_id rid = ptr_sval->get_pointee ();
    5750                 :          2 :       path_var pv = get_representative_path_var (rid);
    5751                 :          2 :       if (pv.m_tree)
    5752                 :          4 :         return build1 (ADDR_EXPR,
    5753                 :          2 :                        TREE_TYPE (sval->get_type ()),
    5754                 :          2 :                        pv.m_tree);
    5755                 :            :     }
    5756                 :            : 
    5757                 :         34 :   return maybe_get_constant (sid);
    5758                 :            : }
    5759                 :            : 
    5760                 :            : /* Attempt to return a path_var that represents the region, or return
    5761                 :            :    the NULL path_var.
    5762                 :            :    For example, a region for a field of a local would be a path_var
    5763                 :            :    wrapping a COMPONENT_REF.  */
    5764                 :            : 
    5765                 :            : path_var
    5766                 :     365292 : region_model::get_representative_path_var (region_id rid) const
    5767                 :            : {
    5768                 :     365292 :   region *reg = get_region (rid);
    5769                 :     365292 :   region *parent_reg = get_region (reg->get_parent ());
    5770                 :     365292 :   region_id stack_rid = get_stack_region_id ();
    5771                 :     365292 :   if (!stack_rid.null_p ())
    5772                 :     365201 :     if (parent_reg && parent_reg->get_parent () == stack_rid)
    5773                 :            :       {
    5774                 :      10828 :         frame_region *parent_frame = (frame_region *)parent_reg;
    5775                 :      10828 :         tree t = parent_frame->get_tree_for_child_region (rid);
    5776                 :      10828 :         return path_var (t, parent_frame->get_depth ());
    5777                 :            :     }
    5778                 :     354464 :   if (reg->get_parent () == get_globals_region_id ())
    5779                 :            :     {
    5780                 :        289 :       map_region *globals = get_root_region ()->get_globals_region (this);
    5781                 :        289 :       if (globals)
    5782                 :        212 :         return path_var (globals->get_tree_for_child_region (rid), -1);
    5783                 :            :     }
    5784                 :            : 
    5785                 :            :   /* Handle e.g. fields of a local by recursing.  */
    5786                 :     354252 :   region_id parent_rid = reg->get_parent ();
    5787                 :     354252 :   if (parent_reg)
    5788                 :            :     {
    5789                 :     354161 :       if (reg->is_view_p ())
    5790                 :            :         {
    5791                 :       2105 :           path_var parent_pv = get_representative_path_var (parent_rid);
    5792                 :       2105 :           if (parent_pv.m_tree && reg->get_type ())
    5793                 :        129 :             return path_var (build1 (NOP_EXPR,
    5794                 :            :                                      reg->get_type (),
    5795                 :            :                                      parent_pv.m_tree),
    5796                 :        129 :                              parent_pv.m_stack_depth);
    5797                 :            :         }
    5798                 :            : 
    5799                 :     354032 :       if (parent_reg->get_kind () == RK_STRUCT)
    5800                 :            :         {
    5801                 :        697 :           map_region *parent_map_region = (map_region *)parent_reg;
    5802                 :            :           /* This can fail if we have a view, rather than a field.  */
    5803                 :       1394 :           if (tree child_key
    5804                 :        697 :                 = parent_map_region->get_tree_for_child_region (rid))
    5805                 :            :             {
    5806                 :        697 :               path_var parent_pv = get_representative_path_var (parent_rid);
    5807                 :        697 :               if (parent_pv.m_tree && TREE_CODE (child_key) == FIELD_DECL)
    5808                 :       1248 :                 return path_var (build3 (COMPONENT_REF,
    5809                 :        624 :                                          TREE_TYPE (child_key),
    5810                 :            :                                          parent_pv.m_tree, child_key,
    5811                 :            :                                          NULL_TREE),
    5812                 :        624 :                                  parent_pv.m_stack_depth);
    5813                 :            :             }
    5814                 :            :         }
    5815                 :            : 
    5816                 :            :       /* Handle elements within an array.  */
    5817                 :     353408 :       if (array_region *array_reg = parent_reg->dyn_cast_array_region ())
    5818                 :            :       {
    5819                 :       1696 :         array_region::key_t key;
    5820                 :       1696 :         if (array_reg->get_key_for_child_region (rid, &key))
    5821                 :            :           {
    5822                 :       1335 :             path_var parent_pv = get_representative_path_var (parent_rid);
    5823                 :       1335 :             if (parent_pv.m_tree && reg->get_type ())
    5824                 :            :               {
    5825                 :         65 :                 tree index = array_reg->constant_from_key (key);
    5826                 :         65 :                 return path_var (build4 (ARRAY_REF,
    5827                 :            :                                          reg->get_type (),
    5828                 :            :                                          parent_pv.m_tree, index,
    5829                 :            :                                          NULL_TREE, NULL_TREE),
    5830                 :         65 :                                  parent_pv.m_stack_depth);
    5831                 :            :               }
    5832                 :            :           }
    5833                 :            :       }
    5834                 :            :     }
    5835                 :            : 
    5836                 :            :   /* Handle string literals.  */
    5837                 :     353434 :   svalue_id sid = reg->get_value_direct ();
    5838                 :     353434 :   if (svalue *sval = get_svalue (sid))
    5839                 :       3755 :     if (tree cst = sval->maybe_get_constant ())
    5840                 :         37 :       if (TREE_CODE (cst) == STRING_CST)
    5841                 :         22 :         return path_var (cst, 0);
    5842                 :            : 
    5843                 :     353412 :   return path_var (NULL_TREE, 0);
    5844                 :            : }
    5845                 :            : 
    5846                 :            : /* Locate all regions that directly have value SID and append representative
    5847                 :            :    path_var instances for them into *OUT.  */
    5848                 :            : 
    5849                 :            : void
    5850                 :       4124 : region_model::get_path_vars_for_svalue (svalue_id sid, vec<path_var> *out) const
    5851                 :            : {
    5852                 :       4124 :   unsigned i;
    5853                 :       4124 :   region *region;
    5854                 :      83889 :   FOR_EACH_VEC_ELT (m_regions, i, region)
    5855                 :      79765 :     if (sid == region->get_value_direct ())
    5856                 :            :       {
    5857                 :       6176 :         path_var pv = get_representative_path_var (region_id::from_int (i));
    5858                 :       6176 :         if (pv.m_tree)
    5859                 :       6115 :           out->safe_push (pv);
    5860                 :            :       }
    5861                 :       4124 : }
    5862                 :            : 
    5863                 :            : /* Set DST_RID value to be a new unknown value of type TYPE.  */
    5864                 :            : 
    5865                 :            : svalue_id
    5866                 :       6734 : region_model::set_to_new_unknown_value (region_id dst_rid, tree type,
    5867                 :            :                                         region_model_context *ctxt)
    5868                 :            : {
    5869                 :       6734 :   gcc_assert (!dst_rid.null_p ());
    5870                 :       6734 :   svalue_id new_sid = add_svalue (new unknown_svalue (type));
    5871                 :       6734 :   set_value (dst_rid, new_sid, ctxt);
    5872                 :            : 
    5873                 :            :   // TODO: presumably purge all child regions too (but do this in set_value?)
    5874                 :            : 
    5875                 :       6734 :   return new_sid;
    5876                 :            : }
    5877                 :            : 
    5878                 :            : /* Update this model for any phis in SNODE, assuming we came from
    5879                 :            :    LAST_CFG_SUPEREDGE.  */
    5880                 :            : 
    5881                 :            : void
    5882                 :      10021 : region_model::update_for_phis (const supernode *snode,
    5883                 :            :                                const cfg_superedge *last_cfg_superedge,
    5884                 :            :                                region_model_context *ctxt)
    5885                 :            : {
    5886                 :      10021 :   gcc_assert (last_cfg_superedge);
    5887                 :            : 
    5888                 :      10021 :   for (gphi_iterator gpi = const_cast<supernode *>(snode)->start_phis ();
    5889                 :      15799 :        !gsi_end_p (gpi); gsi_next (&gpi))
    5890                 :            :     {
    5891                 :       5778 :       gphi *phi = gpi.phi ();
    5892                 :            : 
    5893                 :       5778 :       tree src = last_cfg_superedge->get_phi_arg (phi);
    5894                 :       5778 :       tree lhs = gimple_phi_result (phi);
    5895                 :            : 
    5896                 :            :       /* Update next_state based on phi.  */
    5897                 :       5778 :       bool is_back_edge = last_cfg_superedge->back_edge_p ();
    5898                 :       5778 :       handle_phi (phi, lhs, src, is_back_edge, ctxt);
    5899                 :            :     }
    5900                 :      10021 : }
    5901                 :            : 
    5902                 :            : /* Attempt to update this model for taking EDGE (where the last statement
    5903                 :            :    was LAST_STMT), returning true if the edge can be taken, false
    5904                 :            :    otherwise.
    5905                 :            : 
    5906                 :            :    For CFG superedges where LAST_STMT is a conditional or a switch
    5907                 :            :    statement, attempt to add the relevant conditions for EDGE to this
    5908                 :            :    model, returning true if they are feasible, or false if they are
    5909                 :            :    impossible.
    5910                 :            : 
    5911                 :            :    For call superedges, push frame information and store arguments
    5912                 :            :    into parameters.
    5913                 :            : 
    5914                 :            :    For return superedges, pop frame information and store return
    5915                 :            :    values into any lhs.
    5916                 :            : 
    5917                 :            :    Rejection of call/return superedges happens elsewhere, in
    5918                 :            :    program_point::on_edge (i.e. based on program point, rather
    5919                 :            :    than program state).  */
    5920                 :            : 
    5921                 :            : bool
    5922                 :      12884 : region_model::maybe_update_for_edge (const superedge &edge,
    5923                 :            :                                      const gimple *last_stmt,
    5924                 :            :                                      region_model_context *ctxt)
    5925                 :            : {
    5926                 :            :   /* Handle frame updates for interprocedural edges.  */
    5927                 :      12884 :   switch (edge.m_kind)
    5928                 :            :     {
    5929                 :            :     default:
    5930                 :            :       break;
    5931                 :            : 
    5932                 :        693 :     case SUPEREDGE_CALL:
    5933                 :        693 :       {
    5934                 :        693 :         const call_superedge *call_edge = as_a <const call_superedge *> (&edge);
    5935                 :        693 :         update_for_call_superedge (*call_edge, ctxt);
    5936                 :            :       }
    5937                 :        693 :       break;
    5938                 :            : 
    5939                 :        535 :     case SUPEREDGE_RETURN:
    5940                 :        535 :       {
    5941                 :        535 :         const return_superedge *return_edge
    5942                 :        535 :           = as_a <const return_superedge *> (&edge);
    5943                 :        535 :         update_for_return_superedge (*return_edge, ctxt);
    5944                 :            :       }
    5945                 :        535 :       break;
    5946                 :            : 
    5947                 :         13 :     case SUPEREDGE_INTRAPROCEDURAL_CALL:
    5948                 :         13 :       {
    5949                 :         13 :         const callgraph_superedge *cg_sedge
    5950                 :         13 :           = as_a <const callgraph_superedge *> (&edge);
    5951                 :         13 :         update_for_call_summary (*cg_sedge, ctxt);
    5952                 :            :       }
    5953                 :         13 :       break;
    5954                 :            :     }
    5955                 :            : 
    5956                 :      12884 :   if (last_stmt == NULL)
    5957                 :            :     return true;
    5958                 :            : 
    5959                 :            :   /* Apply any constraints for conditionals/switch statements.  */
    5960                 :            : 
    5961                 :       9981 :   if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
    5962                 :            :     {
    5963                 :       3644 :       const cfg_superedge *cfg_sedge = as_a <const cfg_superedge *> (&edge);
    5964                 :       3644 :       return apply_constraints_for_gcond (*cfg_sedge, cond_stmt, ctxt);
    5965                 :            :     }
    5966                 :            : 
    5967                 :       6337 :   if (const gswitch *switch_stmt = dyn_cast <const gswitch *> (last_stmt))
    5968                 :            :     {
    5969                 :       1798 :       const switch_cfg_superedge *switch_sedge
    5970                 :       1798 :         = as_a <const switch_cfg_superedge *> (&edge);
    5971                 :       1798 :       return apply_constraints_for_gswitch (*switch_sedge, switch_stmt, ctxt);
    5972                 :            :     }
    5973                 :            : 
    5974                 :            :   return true;
    5975                 :            : }
    5976                 :            : 
    5977                 :            : /* Push a new frame_region on to the stack region.
    5978                 :            :    Populate the frame_region with child regions for the function call's
    5979                 :            :    parameters, using values from the arguments at the callsite in the
    5980                 :            :    caller's frame.  */
    5981                 :            : 
    5982                 :            : void
    5983                 :        693 : region_model::update_for_call_superedge (const call_superedge &call_edge,
    5984                 :            :                                          region_model_context *ctxt)
    5985                 :            : {
    5986                 :            :   /* Build a vec of argument svalue_id, using the current top
    5987                 :            :      frame for resolving tree expressions.  */
    5988                 :        693 :   const gcall *call_stmt = call_edge.get_call_stmt ();
    5989                 :        693 :   auto_vec<svalue_id> arg_sids (gimple_call_num_args (call_stmt));
    5990                 :            : 
    5991                 :       1568 :   for (unsigned i = 0; i < gimple_call_num_args (call_stmt); i++)
    5992                 :            :     {
    5993                 :        875 :       tree arg = gimple_call_arg (call_stmt, i);
    5994                 :        875 :       arg_sids.quick_push (get_rvalue (arg, ctxt));
    5995                 :            :     }
    5996                 :            : 
    5997                 :        693 :   push_frame (call_edge.get_callee_function (), &arg_sids, ctxt);
    5998                 :        693 : }
    5999                 :            : 
    6000                 :            : /* Pop the top-most frame_region from the stack, and store the svalue
    6001                 :            :    for any returned value into the region for the lvalue of the LHS of
    6002                 :            :    the call (if any).  */
    6003                 :            : 
    6004                 :            : void
    6005                 :        535 : region_model::update_for_return_superedge (const return_superedge &return_edge,
    6006                 :            :                                            region_model_context *ctxt)
    6007                 :            : {
    6008                 :        535 :   purge_stats stats;
    6009                 :        535 :   svalue_id result_sid = pop_frame (true, &stats, ctxt);
    6010                 :            :   // TODO: do something with the stats?
    6011                 :            : 
    6012                 :        535 :   if (result_sid.null_p ())
    6013                 :        307 :     return;
    6014                 :            : 
    6015                 :            :   /* Set the result of the call, within the caller frame.  */
    6016                 :        228 :   const gcall *call_stmt = return_edge.get_call_stmt ();
    6017                 :        228 :   tree lhs = gimple_call_lhs (call_stmt);
    6018                 :        228 :   if (lhs)
    6019                 :        219 :     set_value (get_lvalue (lhs, ctxt), result_sid, ctxt);
    6020                 :            :   else
    6021                 :            :     {
    6022                 :            :       /* This could be a leak; try purging again, but this time,
    6023                 :            :          don't special-case the result_sid.  */
    6024                 :          9 :       purge_stats stats;
    6025                 :          9 :       purge_unused_svalues (&stats, ctxt);
    6026                 :            :     }
    6027                 :            : }
    6028                 :            : 
    6029                 :            : /* Update this region_model with a summary of the effect of calling
    6030                 :            :    and returning from CG_SEDGE.
    6031                 :            : 
    6032                 :            :    TODO: Currently this is extremely simplistic: we merely set the
    6033                 :            :    return value to "unknown".  A proper implementation would e.g. update
    6034                 :            :    sm-state, and presumably be reworked to support multiple outcomes.  */
    6035                 :            : 
    6036                 :            : void
    6037                 :         13 : region_model::update_for_call_summary (const callgraph_superedge &cg_sedge,
    6038                 :            :                                        region_model_context *ctxt)
    6039                 :            : {
    6040                 :            :   /* For now, set any return value to "unknown".  */
    6041                 :         13 :   const gcall *call_stmt = cg_sedge.get_call_stmt ();
    6042                 :         13 :   tree lhs = gimple_call_lhs (call_stmt);
    6043                 :         13 :   if (lhs)
    6044                 :          9 :     set_to_new_unknown_value (get_lvalue (lhs, ctxt), TREE_TYPE (lhs), ctxt);
    6045                 :            : 
    6046                 :            :   // TODO: actually implement some kind of summary here
    6047                 :         13 : }
    6048                 :            : 
    6049                 :            : /* Given a true or false edge guarded by conditional statement COND_STMT,
    6050                 :            :    determine appropriate constraints for the edge to be taken.
    6051                 :            : 
    6052                 :            :    If they are feasible, add the constraints and return true.
    6053                 :            : 
    6054                 :            :    Return false if the constraints contradict existing knowledge
    6055                 :            :    (and so the edge should not be taken).  */
    6056                 :            : 
    6057                 :            : bool
    6058                 :       3644 : region_model::apply_constraints_for_gcond (const cfg_superedge &sedge,
    6059                 :            :                                            const gcond *cond_stmt,
    6060                 :            :                                            region_model_context *ctxt)
    6061                 :            : {
    6062                 :       3644 :   ::edge cfg_edge = sedge.get_cfg_edge ();
    6063                 :       3644 :   gcc_assert (cfg_edge != NULL);
    6064                 :       3644 :   gcc_assert (cfg_edge->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE));
    6065                 :            : 
    6066                 :       3644 :   enum tree_code op = gimple_cond_code (cond_stmt);
    6067                 :       3644 :   tree lhs = gimple_cond_lhs (cond_stmt);
    6068                 :       3644 :   tree rhs = gimple_cond_rhs (cond_stmt);
    6069                 :       3644 :   if (cfg_edge->flags & EDGE_FALSE_VALUE)
    6070                 :       1702 :     op = invert_tree_comparison (op, false /* honor_nans */);
    6071                 :       3644 :   return add_constraint (lhs, op, rhs, ctxt);
    6072                 :            : }
    6073                 :            : 
    6074                 :            : /* Given an EDGE guarded by SWITCH_STMT, determine appropriate constraints
    6075                 :            :    for the edge to be taken.
    6076                 :            : 
    6077                 :            :    If they are feasible, add the constraints and return true.
    6078                 :            : 
    6079                 :            :    Return false if the constraints contradict existing knowledge
    6080                 :            :    (and so the edge should not be taken).  */
    6081                 :            : 
    6082                 :            : bool
    6083                 :       1798 : region_model::apply_constraints_for_gswitch (const switch_cfg_superedge &edge,
    6084                 :            :                                              const gswitch *switch_stmt,
    6085                 :            :                                              region_model_context *ctxt)
    6086                 :            : {
    6087                 :       1798 :   tree index  = gimple_switch_index (switch_stmt);
    6088                 :       1798 :   tree case_label = edge.get_case_label ();
    6089                 :       1798 :   gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
    6090                 :       1798 :   tree lower_bound = CASE_LOW (case_label);
    6091                 :       1798 :   tree upper_bound = CASE_HIGH (case_label);
    6092                 :       1798 :   if (lower_bound)
    6093                 :            :     {
    6094                 :       1522 :       if (upper_bound)
    6095                 :            :         {
    6096                 :            :           /* Range.  */
    6097                 :          7 :           if (!add_constraint (index, GE_EXPR, lower_bound, ctxt))
    6098                 :            :             return false;
    6099                 :          7 :           return add_constraint (index, LE_EXPR, upper_bound, ctxt);
    6100                 :            :         }
    6101                 :            :       else
    6102                 :            :         /* Single-value.  */
    6103                 :       1515 :         return add_constraint (index, EQ_EXPR, lower_bound, ctxt);
    6104                 :            :     }
    6105                 :            :   else
    6106                 :            :     {
    6107                 :            :       /* The default case.
    6108                 :            :          Add exclusions based on the other cases.  */
    6109                 :            :       for (unsigned other_idx = 1;
    6110                 :       2008 :            other_idx < gimple_switch_num_labels (switch_stmt);
    6111                 :            :            other_idx++)
    6112                 :            :         {
    6113                 :       1749 :           tree other_label = gimple_switch_label (switch_stmt,
    6114                 :            :                                                   other_idx);
    6115                 :       1749 :           tree other_lower_bound = CASE_LOW (other_label);
    6116                 :       1749 :           tree other_upper_bound = CASE_HIGH (other_label);
    6117                 :       1749 :           gcc_assert (other_lower_bound);
    6118                 :       1749 :           if (other_upper_bound)
    6119                 :            :             {
    6120                 :            :               /* Exclude this range-valued case.
    6121                 :            :                  For now, we just exclude the boundary values.
    6122                 :            :                  TODO: exclude the values within the region.  */
    6123                 :          7 :               if (!add_constraint (index, NE_EXPR, other_lower_bound, ctxt))
    6124                 :            :                 return false;
    6125                 :          7 :               if (!add_constraint (index, NE_EXPR, other_upper_bound, ctxt))
    6126                 :            :                 return false;
    6127                 :            :             }
    6128                 :            :           else
    6129                 :            :             /* Exclude this single-valued case.  */
    6130                 :       1742 :             if (!add_constraint (index, NE_EXPR, other_lower_bound, ctxt))
    6131                 :            :               return false;
    6132                 :            :         }
    6133                 :            :       return true;
    6134                 :            :     }
    6135                 :            : }
    6136                 :            : 
    6137                 :            : /* Get the root_region within this model (guaranteed to be non-null).  */
    6138                 :            : 
    6139                 :            : root_region *
    6140                 :    3181420 : region_model::get_root_region () const
    6141                 :            : {
    6142                 :    3181420 :   return get_region<root_region> (m_root_rid);
    6143                 :            : }
    6144                 :            : 
    6145                 :            : /* Get the region_id of this model's stack region (if any).  */
    6146                 :            : 
    6147                 :            : region_id
    6148                 :     365292 : region_model::get_stack_region_id () const
    6149                 :            : {
    6150                 :     365292 :   return get_root_region ()->get_stack_region_id ();
    6151                 :            : }
    6152                 :            : 
    6153                 :            : /* Create a new frame_region for a call to FUN and push it onto
    6154                 :            :    the stack.
    6155                 :            : 
    6156                 :            :    If ARG_SIDS is non-NULL, use it to populate the parameters
    6157                 :            :    in the new frame.
    6158                 :            :    Otherwise, populate them with unknown values.
    6159                 :            : 
    6160                 :            :    Return the region_id of the new frame_region.  */
    6161                 :            : 
    6162                 :            : region_id
    6163                 :       2107 : region_model::push_frame (function *fun, vec<svalue_id> *arg_sids,
    6164                 :            :                           region_model_context *ctxt)
    6165                 :            : {
    6166                 :       2107 :   return get_root_region ()->push_frame (this, fun, arg_sids, ctxt);
    6167                 :            : }
    6168                 :            : 
    6169                 :            : /* Get the region_id of the top-most frame in this region_model's stack,
    6170                 :            :    if any.  */
    6171                 :            : 
    6172                 :            : region_id
    6173                 :      29984 : region_model::get_current_frame_id () const
    6174                 :            : {
    6175                 :      29984 :   return get_root_region ()->get_current_frame_id (*this);
    6176                 :            : }
    6177                 :            : 
    6178                 :            : /* Get the function of the top-most frame in this region_model's stack.
    6179                 :            :    There must be such a frame.  */
    6180                 :            : 
    6181                 :            : function *
    6182                 :       1899 : region_model::get_current_function () const
    6183                 :            : {
    6184                 :       1899 :   region_id frame_id = get_current_frame_id ();
    6185                 :       1899 :   frame_region *frame = get_region<frame_region> (frame_id);
    6186                 :       1899 :   return frame->get_function ();
    6187                 :            : }
    6188                 :            : 
    6189                 :            : /* Pop the topmost frame_region from this region_model's stack;
    6190                 :            :    see the comment for stack_region::pop_frame.  */
    6191                 :            : 
    6192                 :            : svalue_id
    6193                 :       1594 : region_model::pop_frame (bool purge, purge_stats *out,
    6194                 :            :                          region_model_context *ctxt)
    6195                 :            : {
    6196                 :       1594 :   return get_root_region ()->pop_frame (this, purge, out, ctxt);
    6197                 :            : }
    6198                 :            : 
    6199                 :            : /* Get the number of frames in this region_model's stack.  */
    6200                 :            : 
    6201                 :            : int
    6202                 :     943193 : region_model::get_stack_depth () const
    6203                 :            : {
    6204                 :     943193 :   stack_region *stack = get_root_region ()->get_stack_region (this);
    6205                 :     943193 :   if (stack)
    6206                 :    1873770 :     return stack->get_num_frames ();
    6207                 :            :   else
    6208                 :            :     return 0;
    6209                 :            : }
    6210                 :            : 
    6211                 :            : /* Get the function * at DEPTH within the call stack.  */
    6212                 :            : 
    6213                 :            : function *
    6214                 :      75782 : region_model::get_function_at_depth (unsigned depth) const
    6215                 :            : {
    6216                 :      75782 :   stack_region *stack = get_root_region ()->get_stack_region (this);
    6217                 :      75782 :   gcc_assert (stack);
    6218                 :      75782 :   region_id frame_rid = stack->get_frame_rid (depth);
    6219                 :      75782 :   frame_region *frame = get_region <frame_region> (frame_rid);
    6220                 :      75782 :   return frame->get_function ();
    6221                 :            : }
    6222                 :            : 
    6223                 :            : /* Get the region_id of this model's globals region (if any).  */
    6224                 :            : 
    6225                 :            : region_id
    6226                 :     355697 : region_model::get_globals_region_id () const
    6227                 :            : {
    6228                 :     355697 :   return get_root_region ()->get_globals_region_id ();
    6229                 :            : }
    6230                 :            : 
    6231                 :            : /* Add SVAL to this model, taking ownership, and returning its new
    6232                 :            :    svalue_id.  */
    6233                 :            : 
    6234                 :            : svalue_id
    6235                 :    1650400 : region_model::add_svalue (svalue *sval)
    6236                 :            : {
    6237                 :    1650400 :   gcc_assert (sval);
    6238                 :    1650400 :   m_svalues.safe_push (sval);
    6239                 :    1650400 :   return svalue_id::from_int (m_svalues.length () - 1);
    6240                 :            : }
    6241                 :            : 
    6242                 :            : /* Change the meaning of SID to be NEW_SVAL
    6243                 :            :    (e.g. when deferencing an unknown pointer, the pointer
    6244                 :            :    becomes a pointer to a symbolic region, so that all users
    6245                 :            :    of the former unknown pointer are now effectively pointing
    6246                 :            :    at the same region).  */
    6247                 :            : 
    6248                 :            : void
    6249                 :        681 : region_model::replace_svalue (svalue_id sid, svalue *new_sval)
    6250                 :            : {
    6251                 :        681 :   gcc_assert (!sid.null_p ());
    6252                 :        681 :   int idx = sid.as_int ();
    6253                 :            : 
    6254                 :        681 :   gcc_assert (m_svalues[idx]);
    6255                 :        681 :   gcc_assert (m_svalues[idx]->get_type () == new_sval->get_type ());
    6256                 :        681 :   delete m_svalues[idx];
    6257                 :            : 
    6258                 :        681 :   m_svalues[idx] = new_sval;
    6259                 :        681 : }
    6260                 :            : 
    6261                 :            : /* Add region R to this model, taking ownership, and returning its new
    6262                 :            :    region_id.  */
    6263                 :            : 
    6264                 :            : region_id
    6265                 :    2208960 : region_model::add_region (region *r)
    6266                 :            : {
    6267                 :    2208960 :   gcc_assert (r);
    6268                 :    2208960 :   m_regions.safe_push (r);
    6269                 :    2208960 :   return region_id::from_int (m_regions.length () - 1);
    6270                 :            : }
    6271                 :            : 
    6272                 :            : /* Return the svalue with id SVAL_ID, or NULL for a null id.  */
    6273                 :            : 
    6274                 :            : svalue *
    6275                 :   10202600 : region_model::get_svalue (svalue_id sval_id) const
    6276                 :            : {
    6277                 :   10202600 :   if (sval_id.null_p ())
    6278                 :            :     return NULL;
    6279                 :    8712510 :   return m_svalues[sval_id.as_int ()];
    6280                 :            : }
    6281                 :            : 
    6282                 :            : /* Return the region with id RID, or NULL for a null id.  */
    6283                 :            : 
    6284                 :            : region *
    6285                 :   15169800 : region_model::get_region (region_id rid) const
    6286                 :            : {
    6287                 :   15169800 :   if (rid.null_p ())
    6288                 :            :     return NULL;
    6289                 :   14677900 :   return m_regions[rid.as_int ()];
    6290                 :            : }
    6291                 :            : 
    6292                 :            : /* Make a region of an appropriate subclass for TYPE,
    6293                 :            :    with parent PARENT_RID, or return NULL for types we don't yet know
    6294                 :            :    how to handle.  */
    6295                 :            : 
    6296                 :            : static region *
    6297                 :    1218360 : make_region_for_type (region_id parent_rid, tree type)
    6298                 :            : {
    6299                 :    1218360 :   gcc_assert (TYPE_P (type));
    6300                 :            : 
    6301                 :    1218360 :   if (INTEGRAL_TYPE_P (type)
    6302                 :            :       || SCALAR_FLOAT_TYPE_P (type)
    6303                 :            :       || POINTER_TYPE_P (type)
    6304                 :    1218360 :       || TREE_CODE (type) == COMPLEX_TYPE
    6305                 :     401946 :       || TREE_CODE (type) == VECTOR_TYPE)
    6306                 :     816420 :     return new primitive_region (parent_rid, type);
    6307                 :            : 
    6308                 :     401937 :   if (TREE_CODE (type) == RECORD_TYPE)
    6309                 :       8894 :     return new struct_region (parent_rid, type);
    6310                 :            : 
    6311                 :     393043 :   if (TREE_CODE (type) == ARRAY_TYPE)
    6312                 :      22136 :     return new array_region (parent_rid, type);
    6313                 :            : 
    6314                 :     370907 :   if (TREE_CODE (type) == UNION_TYPE)
    6315                 :         36 :     return new union_region (parent_rid, type);
    6316                 :            : 
    6317                 :     370871 :   if (FUNC_OR_METHOD_TYPE_P (type))
    6318                 :     370795 :     return new function_region (parent_rid, type);
    6319                 :            : 
    6320                 :            :   /* If we have a void *, make a new symbolic region.  */
    6321                 :         76 :   if (VOID_TYPE_P (type))
    6322                 :         58 :     return new symbolic_region (parent_rid, type, false);
    6323                 :            : 
    6324                 :            :   return NULL;
    6325                 :            : }
    6326                 :            : 
    6327                 :            : /* Add a region with type TYPE and parent PARENT_RID.  */
    6328                 :            : 
    6329                 :            : region_id
    6330                 :    1218360 : region_model::add_region_for_type (region_id parent_rid, tree type,
    6331                 :            :                                    region_model_context *ctxt)
    6332                 :            : {
    6333                 :    1218360 :   gcc_assert (TYPE_P (type));
    6334                 :            : 
    6335                 :    1218360 :   if (region *new_region = make_region_for_type (parent_rid, type))
    6336                 :    1218340 :     return add_region (new_region);
    6337                 :            : 
    6338                 :            :   /* If we can't handle TYPE, return a placeholder region, and stop
    6339                 :            :      exploring this path.  */
    6340                 :         18 :   return make_region_for_unexpected_tree_code (ctxt, type,
    6341                 :         18 :                                                dump_location_t ());
    6342                 :            : }
    6343                 :            : 
    6344                 :            : /* Helper class for region_model::purge_unused_svalues.  */
    6345                 :            : 
    6346                 :      29968 : class restrict_to_used_svalues : public purge_criteria
    6347                 :            : {
    6348                 :            : public:
    6349                 :      29968 :   restrict_to_used_svalues (const auto_sbitmap &used) : m_used (used) {}
    6350                 :            : 
    6351                 :      53867 :   bool should_purge_p (svalue_id sid) const FINAL OVERRIDE
    6352                 :            :   {
    6353                 :      53867 :     gcc_assert (!sid.null_p ());
    6354                 :      53867 :     return !bitmap_bit_p (m_used, sid.as_int ());
    6355                 :            :   }
    6356                 :            : 
    6357                 :            : private:
    6358                 :            :   const auto_sbitmap &m_used;
    6359                 :            : };
    6360                 :            : 
    6361                 :            : /* Remove unused svalues from this model, accumulating stats into STATS.
    6362                 :            :    Unused svalues are deleted.  Doing so could reorder the svalues, and
    6363                 :            :    thus change the meaning of svalue_ids.
    6364                 :            : 
    6365                 :            :    If CTXT is non-NULL, then it is notified about svalue_id remappings,
    6366                 :            :    and about svalue_ids that are about to be deleted.  This allows e.g.
    6367                 :            :    for warning about resource leaks, for the case where the svalue
    6368                 :            :    represents a resource handle in the user code (e.g. a FILE * or a malloc
    6369                 :            :    buffer).
    6370                 :            : 
    6371                 :            :    Amongst other things, removing unused svalues is important for ensuring
    6372                 :            :    that the analysis of loops terminates.  Otherwise, we could generate a
    6373                 :            :    succession of models with unreferenced "unknown" values, where the
    6374                 :            :    number of redundant unknown values could grow without bounds, and each
    6375                 :            :    such model would be treated as distinct.
    6376                 :            : 
    6377                 :            :    If KNOWN_USED is non-NULL, treat *KNOWN_USED as used (this is for
    6378                 :            :    handling values being returned from functions as their frame is popped,
    6379                 :            :    since otherwise we'd have to simultaneously determine both the rvalue
    6380                 :            :    of the return expr in the callee frame and the lvalue for the gcall's
    6381                 :            :    assignment in the caller frame, and it seems cleaner to express all
    6382                 :            :    lvalue and rvalue lookups implicitly relative to a "current" frame).  */
    6383                 :            : 
    6384                 :            : void
    6385                 :      29968 : region_model::purge_unused_svalues (purge_stats *stats,
    6386                 :            :                                     region_model_context *ctxt,
    6387                 :            :                                     svalue_id *known_used_sid)
    6388                 :            : {
    6389                 :            :   // TODO: might want to avoid a vfunc call just to do logging here:
    6390                 :      29968 :   logger *logger = ctxt ? ctxt->get_logger () : NULL;
    6391                 :            : 
    6392                 :      29968 :   LOG_SCOPE (logger);
    6393                 :            : 
    6394                 :      89904 :   auto_sbitmap used (m_svalues.length ());
    6395                 :      29968 :   bitmap_clear (used);
    6396                 :            : 
    6397                 :      29968 :   if (known_used_sid)
    6398                 :       1579 :     if (!known_used_sid->null_p ())
    6399                 :        597 :       bitmap_set_bit (used, known_used_sid->as_int ());
    6400                 :            : 
    6401                 :            :   /* Walk the regions, marking sids that are used.  */
    6402                 :            :   unsigned i;
    6403                 :            :   region *r;
    6404                 :     486146 :   FOR_EACH_VEC_ELT (m_regions, i, r)
    6405                 :            :     {
    6406                 :     456178 :       svalue_id sid = r->get_value_direct ();
    6407                 :     456178 :       if (!sid.null_p ())
    6408                 :     723208 :         bitmap_set_bit (used, sid.as_int ());
    6409                 :            :     }
    6410                 :            : 
    6411                 :            :   /* Now purge any constraints involving svalues we don't care about.  */
    6412                 :      59936 :   restrict_to_used_svalues criterion (used);
    6413                 :      29968 :   m_constraints->purge (criterion, stats);
    6414                 :            : 
    6415                 :            :   /* Mark any sids that are in constraints that survived.  */
    6416                 :      29968 :   {
    6417                 :      29968 :     equiv_class *ec;
    6418                 :     200064 :     FOR_EACH_VEC_ELT (m_constraints->m_equiv_classes, i, ec)
    6419                 :            :       {
    6420                 :            :         int j;
    6421                 :            :         svalue_id *sid;
    6422                 :     264117 :         FOR_EACH_VEC_ELT (ec->m_vars, j, sid)
    6423                 :            :           {
    6424                 :      94021 :             gcc_assert (!sid->null_p ());
    6425                 :      94021 :             bitmap_set_bit (used, sid->as_int ());
    6426                 :            :           }
    6427                 :            :       }
    6428                 :            :   }
    6429                 :            : 
    6430                 :            :   /* Build a mapping from old-sid to new-sid so that we can preserve
    6431                 :            :      order of the used IDs and move all redundant ones to the end.
    6432                 :            :      Iterate though svalue IDs, adding used ones to the front of
    6433                 :            :      the new list, and unused ones to the back.  */
    6434                 :      89904 :   svalue_id_map map (m_svalues.length ());
    6435                 :      29968 :   int next_used_new_sid = 0;
    6436                 :      29968 :   int after_next_unused_new_sid = m_svalues.length ();
    6437                 :     620450 :   for (unsigned i = 0; i < m_svalues.length (); i++)
    6438                 :            :     {
    6439                 :     280257 :       svalue_id src (svalue_id::from_int (i));
    6440                 :     280257 :       if (bitmap_bit_p (used, i))
    6441                 :            :         {
    6442                 :     250811 :           if (logger)
    6443                 :          0 :             logger->log ("sv%i is used", i);
    6444                 :     250811 :           map.put (src, svalue_id::from_int (next_used_new_sid++));
    6445                 :            :         }
    6446                 :            :       else
    6447                 :            :         {
    6448                 :      29446 :           if (logger)
    6449                 :          0 :             logger->log ("sv%i is unused", i);
    6450                 :      29446 :           map.put (src, svalue_id::from_int (--after_next_unused_new_sid));
    6451                 :            :         }
    6452                 :            :     }
    6453                 :            :   /* The two insertion points should have met.  */
    6454                 :      29968 :   gcc_assert (next_used_new_sid == after_next_unused_new_sid);
    6455                 :            : 
    6456                 :            :   /* Now walk the regions and the constraints, remapping sids,
    6457                 :            :      so that all the redundant svalues are at the end.  */
    6458                 :      29968 :   remap_svalue_ids (map);
    6459                 :            : 
    6460                 :      29968 :   if (logger)
    6461                 :            :     {
    6462                 :          0 :       logger->start_log_line ();
    6463                 :          0 :       logger->log_partial ("map: ");
    6464                 :          0 :       map.dump_to_pp (logger->get_printer ());
    6465                 :          0 :       logger->end_log_line ();
    6466                 :            :     }
    6467                 :            : 
    6468                 :            :   /* Notify any client about the remapping and pending deletion.
    6469                 :            :      Potentially this could trigger leak warnings.  */
    6470                 :      29968 :   if (ctxt)
    6471                 :            :     {
    6472                 :      29850 :       ctxt->remap_svalue_ids (map);
    6473                 :      29850 :       int num_client_items_purged
    6474                 :      29850 :         = ctxt->on_svalue_purge (svalue_id::from_int (next_used_new_sid), map);
    6475                 :      29850 :       if (stats)
    6476                 :      29841 :         stats->m_num_client_items += num_client_items_purged;
    6477                 :            :     }
    6478                 :            : 
    6479                 :            :   /* Drop the redundant svalues from the end of the vector.  */
    6480                 :     118828 :   while ((signed)m_svalues.length () > next_used_new_sid)
    6481                 :            :     {
    6482                 :      29446 :       if (logger)
    6483                 :            :         {
    6484                 :          0 :           svalue_id victim = svalue_id::from_int (m_svalues.length () - 1);
    6485                 :          0 :           logger->log ("deleting sv%i (was sv%i)",
    6486                 :            :                        victim.as_int (),
    6487                 :          0 :                        map.get_src_for_dst (victim).as_int ());
    6488                 :            :         }
    6489                 :      29446 :       delete m_svalues.pop ();
    6490                 :      29446 :       if (stats)
    6491                 :      29432 :         stats->m_num_svalues++;
    6492                 :            :     }
    6493                 :            : 
    6494                 :      29968 :   if (known_used_sid)
    6495                 :       1579 :     map.update (known_used_sid);
    6496                 :            : 
    6497                 :      29968 :   validate ();
    6498                 :      29968 : }
    6499                 :            : 
    6500                 :            : /* Renumber the svalues within this model according to MAP.  */
    6501                 :            : 
    6502                 :            : void
    6503                 :      89913 : region_model::remap_svalue_ids (const svalue_id_map &map)
    6504                 :            : {
    6505                 :            :   /* Update IDs within regions.  */
    6506                 :      89913 :   unsigned i;
    6507                 :      89913 :   region *r;
    6508                 :    1453530 :   FOR_EACH_VEC_ELT (m_regions, i, r)
    6509                 :    1363620 :     r->remap_svalue_ids (map);
    6510                 :            : 
    6511                 :            :   /* Update IDs within ECs within constraints.  */
    6512                 :      89913 :   m_constraints->remap_svalue_ids (map);
    6513                 :            : 
    6514                 :            :   /* Build a reordered svalues vector.  */
    6515                 :      89913 :   auto_vec<svalue *> new_svalues (m_svalues.length ());
    6516                 :    1765130 :   for (unsigned i = 0; i < m_svalues.length (); i++)
    6517                 :            :     {
    6518                 :     792839 :       svalue_id dst (svalue_id::from_int (i));
    6519                 :     792839 :       svalue_id src = map.get_src_for_dst (dst);
    6520                 :     792839 :       new_svalues.quick_push (get_svalue (src));
    6521                 :            :     }
    6522                 :            : 
    6523                 :            :   /* Copy over the reordered vec to m_svalues.  */
    6524                 :      89913 :   m_svalues.truncate (0);
    6525                 :     269362 :   gcc_assert (m_svalues.space (new_svalues.length ()));
    6526                 :            :   svalue *sval;
    6527                 :     972288 :   FOR_EACH_VEC_ELT (new_svalues, i, sval)
    6528                 :     792839 :     m_svalues.quick_push (sval);
    6529                 :      89913 : }
    6530                 :            : 
    6531                 :            : /* Renumber the regions within this model according to MAP.  */
    6532                 :            : 
    6533                 :            : void
    6534                 :      89714 : region_model::remap_region_ids (const region_id_map &map)
    6535                 :            : {
    6536                 :            :   /* Update IDs within regions.  */
    6537                 :      89714 :   unsigned i;
    6538                 :      89714 :   region *r;
    6539                 :    1473940 :   FOR_EACH_VEC_ELT (m_regions, i, r)
    6540                 :    1384230 :     r->remap_region_ids (map);
    6541                 :            : 
    6542                 :            :   /* Update IDs within svalues.  */
    6543                 :            :   svalue *sval;
    6544                 :     881116 :   FOR_EACH_VEC_ELT (m_svalues, i, sval)
    6545                 :     791402 :     sval->remap_region_ids (map);
    6546                 :            : 
    6547                 :            :   /* Build a reordered regions vector.  */
    6548                 :      89714 :   auto_vec<region *> new_regions (m_regions.length ());
    6549                 :    2947880 :   for (unsigned i = 0; i < m_regions.length (); i++)
    6550                 :            :     {
    6551                 :    1384230 :       region_id dst (region_id::from_int (i));
    6552                 :    1384230 :       region_id src = map.get_src_for_dst (dst);
    6553                 :    1384230 :       new_regions.quick_push (get_region (src));
    6554                 :            :     }
    6555                 :            : 
    6556                 :            :   /* Copy over the reordered vec to m_regions.  */
    6557                 :      89714 :   m_regions.truncate (0);
    6558                 :     269142 :   gcc_assert (m_regions.space (new_regions.length ()));
    6559                 :    1563660 :   FOR_EACH_VEC_ELT (new_regions, i, r)
    6560                 :    1384230 :     m_regions.quick_push (r);
    6561                 :      89714 : }
    6562                 :            : 
    6563                 :            : /* Delete all regions within SET_TO_PURGE, remapping region IDs for
    6564                 :            :    other regions.  It's required that there are no uses of the
    6565                 :            :    regions within the set (or the region IDs will become invalid).
    6566                 :            : 
    6567                 :            :    Accumulate stats to STATS.  */
    6568                 :            : 
    6569                 :            : void
    6570                 :      29769 : region_model::purge_regions (const region_id_set &set_to_purge,
    6571                 :            :                              purge_stats *stats,
    6572                 :            :                              logger *)
    6573                 :            : {
    6574                 :            :   /* Build a mapping from old-rid to new-rid so that we can preserve
    6575                 :            :      order of the used IDs and move all redundant ones to the end.
    6576                 :            :      Iterate though region IDs, adding used ones to the front of
    6577                 :            :      the new list, and unused ones to the back.  */
    6578                 :      89307 :   region_id_map map (m_regions.length ());
    6579                 :      29769 :   int next_used_new_rid = 0;
    6580                 :      29769 :   int after_next_unused_new_rid = m_regions.length ();
    6581                 :    1013110 :   for (unsigned i = 0; i < m_regions.length (); i++)
    6582                 :            :     {
    6583                 :     476788 :       region_id src (region_id::from_int (i));
    6584                 :     476788 :       if (set_to_purge.region_p (src))
    6585                 :      23238 :         map.put (src, region_id::from_int (--after_next_unused_new_rid));
    6586                 :            :       else
    6587                 :     453550 :         map.put (src, region_id::from_int (next_used_new_rid++));
    6588                 :            :     }
    6589                 :            :   /* The two insertion points should have met.  */
    6590                 :      29769 :   gcc_assert (next_used_new_rid == after_next_unused_new_rid);
    6591                 :            : 
    6592                 :            :   /* Now walk the regions and svalues, remapping rids,
    6593                 :            :      so that all the redundant regions are at the end.  */
    6594                 :      29769 :   remap_region_ids (map);
    6595                 :            : 
    6596                 :            :   /* Drop the redundant regions from the end of the vector.  */
    6597                 :     106014 :   while ((signed)m_regions.length () > next_used_new_rid)
    6598                 :            :     {
    6599                 :      23238 :       delete m_regions.pop ();
    6600                 :      23238 :       if (stats)
    6601                 :      23210 :         stats->m_num_regions++;
    6602                 :            :     }
    6603                 :      29769 : }
    6604                 :            : 
    6605                 :            : /* Populate *OUT with RID and all of its descendents.
    6606                 :            :    If EXCLUDE_RID is non-null, then don't add it or its descendents.  */
    6607                 :            : 
    6608                 :            : void
    6609                 :       4217 : region_model::get_descendents (region_id rid, region_id_set *out,
    6610                 :            :                                region_id exclude_rid) const
    6611                 :            : {
    6612                 :       4217 :   out->add_region (rid);
    6613                 :            : 
    6614                 :       4217 :   bool changed = true;
    6615                 :      10763 :   while (changed)
    6616                 :            :     {
    6617                 :            :       changed = false;
    6618                 :            :       unsigned i;
    6619                 :            :       region *r;
    6620                 :     175105 :       FOR_EACH_VEC_ELT (m_regions, i, r)
    6621                 :            :         {
    6622                 :     164342 :           region_id iter_rid = region_id::from_int (i);
    6623                 :     164342 :           if (iter_rid == exclude_rid)
    6624                 :        490 :             continue;
    6625                 :     163852 :           if (!out->region_p (iter_rid))
    6626                 :            :             {
    6627                 :     150287 :               region_id parent_rid = r->get_parent ();
    6628                 :     150287 :               if (!parent_rid.null_p ())
    6629                 :     143741 :                 if (out->region_p (parent_rid))
    6630                 :            :                   {
    6631                 :       6831 :                     out->add_region (iter_rid);
    6632                 :       6831 :                     changed = true;
    6633                 :            :                   }
    6634                 :            :             }
    6635                 :            :         }
    6636                 :            :     }
    6637                 :       4217 : }
    6638                 :            : 
    6639                 :            : /* Delete RID and all descendent regions.
    6640                 :            :    Find any pointers to such regions; convert them to
    6641                 :            :    poisoned values of kind PKIND.
    6642                 :            :    Accumulate stats on purged entities into STATS.  */
    6643                 :            : 
    6644                 :            : void
    6645                 :       1698 : region_model::delete_region_and_descendents (region_id rid,
    6646                 :            :                                              enum poison_kind pkind,
    6647                 :            :                                              purge_stats *stats,
    6648                 :            :                                              logger *logger)
    6649                 :            : {
    6650                 :            :   /* Find all child and descendent regions.  */
    6651                 :       1698 :   region_id_set descendents (this);
    6652                 :       1698 :   get_descendents (rid, &descendents, region_id::null ());
    6653                 :            : 
    6654                 :            :   /* Find any pointers to such regions; convert to poisoned.  */
    6655                 :       1698 :   poison_any_pointers_to_bad_regions (descendents, pkind);
    6656                 :            : 
    6657                 :            :   /* Delete all such regions.  */
    6658                 :       1698 :   purge_regions (descendents, stats, logger);
    6659                 :       1698 : }
    6660                 :            : 
    6661                 :            : /* Find any pointers to regions within BAD_REGIONS; convert them to
    6662                 :            :    poisoned values of kind PKIND.  */
    6663                 :            : 
    6664                 :            : void
    6665                 :       1698 : region_model::poison_any_pointers_to_bad_regions (const region_id_set &
    6666                 :            :                                                     bad_regions,
    6667                 :            :                                                   enum poison_kind pkind)
    6668                 :            : {
    6669                 :       1698 :   int i;
    6670                 :       1698 :   svalue *sval;
    6671                 :      12943 :   FOR_EACH_VEC_ELT (m_svalues, i, sval)
    6672                 :      11245 :     if (region_svalue *ptr_sval = sval->dyn_cast_region_svalue ())
    6673                 :            :       {
    6674                 :       1232 :         region_id ptr_dst = ptr_sval->get_pointee ();
    6675                 :       1232 :         if (!ptr_dst.null_p ())
    6676                 :       1232 :           if (bad_regions.region_p (ptr_dst))
    6677                 :        143 :             replace_svalue
    6678                 :        143 :               (svalue_id::from_int (i),
    6679                 :        143 :                new poisoned_svalue (pkind, sval->get_type ()));
    6680                 :            :       }
    6681                 :       1698 : }
    6682                 :            : 
    6683                 :            : /* Attempt to merge THIS with OTHER_MODEL, writing the result
    6684                 :            :    to OUT_MODEL, and populating SID_MAPPING.  */
    6685                 :            : 
    6686                 :            : bool
    6687                 :     173457 : region_model::can_merge_with_p (const region_model &other_model,
    6688                 :            :                                 region_model *out_model,
    6689                 :            :                                 svalue_id_merger_mapping *sid_mapping) const
    6690                 :            : {
    6691                 :     173457 :   gcc_assert (m_root_rid == other_model.m_root_rid);
    6692                 :     173457 :   gcc_assert (m_root_rid.as_int () == 0);
    6693                 :     173457 :   gcc_assert (sid_mapping);
    6694                 :     173457 :   gcc_assert (out_model);
    6695                 :            : 
    6696                 :     346914 :   model_merger merger (this, &other_model, out_model, sid_mapping);
    6697                 :            : 
    6698                 :     346914 :   if (!root_region::can_merge_p (get_root_region (),
    6699                 :     173457 :                                  other_model.get_root_region (),
    6700                 :            :                                  out_model->get_root_region (),
    6701                 :            :                                  &merger))
    6702                 :            :     return false;
    6703                 :            : 
    6704                 :            :   /* Merge constraints.  */
    6705                 :     165347 :   constraint_manager::merge (*m_constraints,
    6706                 :     165347 :                              *other_model.m_constraints,
    6707                 :            :                              out_model->m_constraints,
    6708                 :            :                              merger);
    6709                 :            : 
    6710                 :     165347 :   out_model->validate ();
    6711                 :            : 
    6712                 :            :   /* The merged model should be simpler (or as simple) as the inputs.  */
    6713                 :            : #if 0
    6714                 :            :   gcc_assert (out_model->m_svalues.length () <= m_svalues.length ());
    6715                 :            :   gcc_assert (out_model->m_svalues.length ()
    6716                 :            :               <= other_model.m_svalues.length ());
    6717                 :            : #endif
    6718                 :     496041 :   gcc_assert (out_model->m_regions.length () <= m_regions.length ());
    6719                 :     330694 :   gcc_assert (out_model->m_regions.length ()
    6720                 :            :               <= other_model.m_regions.length ());
    6721                 :            :   // TODO: same, for constraints
    6722                 :            : 
    6723                 :            :   return true;
    6724                 :            : }
    6725                 :            : 
    6726                 :            : /* As above, but supply a placeholder svalue_id_merger_mapping
    6727                 :            :    instance to be used and receive output.  For use in selftests.  */
    6728                 :            : 
    6729                 :            : bool
    6730                 :        114 : region_model::can_merge_with_p (const region_model &other_model,
    6731                 :            :                                 region_model *out_model) const
    6732                 :            : {
    6733                 :        228 :   svalue_id_merger_mapping sid_mapping (*this, other_model);
    6734                 :        114 :   return can_merge_with_p (other_model, out_model, &sid_mapping);
    6735                 :            : }
    6736                 :            : 
    6737                 :            : /* For debugging purposes: look for a region within this region_model
    6738                 :            :    for a decl named NAME (or an SSA_NAME for such a decl),
    6739                 :            :    returning its value, or svalue_id::null if none are found.  */
    6740                 :            : 
    6741                 :            : svalue_id
    6742                 :          4 : region_model::get_value_by_name (const char *name) const
    6743                 :            : {
    6744                 :          4 :   gcc_assert (name);
    6745                 :          4 :   tree identifier = get_identifier (name);
    6746                 :          4 :   return get_root_region ()->get_value_by_name (identifier, *this);
    6747                 :            : }
    6748                 :            : 
    6749                 :            : /* Generate or reuse an svalue_id within this model for an index
    6750                 :            :    into an array of type PTR_TYPE, based on OFFSET_SID.  */
    6751                 :            : 
    6752                 :            : svalue_id
    6753                 :        591 : region_model::convert_byte_offset_to_array_index (tree ptr_type,
    6754                 :            :                                                   svalue_id offset_sid)
    6755                 :            : {
    6756                 :        591 :   gcc_assert (POINTER_TYPE_P (ptr_type));
    6757                 :            : 
    6758                 :        591 :   if (tree offset_cst = maybe_get_constant (offset_sid))
    6759                 :            :     {
    6760                 :        402 :       tree elem_type = TREE_TYPE (ptr_type);
    6761                 :            : 
    6762                 :            :       /* Arithmetic on void-pointers is a GNU C extension, treating the size
    6763                 :            :          of a void as 1.
    6764                 :            :          https://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html  */
    6765                 :        402 :       if (TREE_CODE (elem_type) == VOID_TYPE)
    6766                 :         14 :         return offset_sid;
    6767                 :            : 
    6768                 :            :       /* First, use int_size_in_bytes, to reject the case where we have an
    6769                 :            :          incomplete type, or a non-constant value.  */
    6770                 :        388 :       HOST_WIDE_INT hwi_byte_size = int_size_in_bytes (elem_type);
    6771                 :        388 :       if (hwi_byte_size > 0)
    6772                 :            :         {
    6773                 :            :           /* Now call size_in_bytes to get the answer in tree form.  */
    6774                 :        378 :           tree byte_size = size_in_bytes (elem_type);
    6775                 :        378 :           gcc_assert (byte_size);
    6776                 :            :           /* Try to get a constant by dividing, ensuring that we're in a
    6777                 :            :              signed representation first.  */
    6778                 :        378 :           tree index
    6779                 :        378 :             = fold_binary (TRUNC_DIV_EXPR, ssizetype,
    6780                 :            :                            fold_convert (ssizetype, offset_cst),
    6781                 :            :                            fold_convert (ssizetype, byte_size));
    6782                 :        378 :           if (index && TREE_CODE (index) == INTEGER_CST)
    6783                 :        378 :             return get_or_create_constant_svalue (index);
    6784                 :            :         }
    6785                 :            :     }
    6786                 :            : 
    6787                 :            :   /* Otherwise, we don't know the array index; generate a new unknown value.
    6788                 :            :      TODO: do we need to capture the relationship between two unknown
    6789                 :            :      values (the offset and the index)?  */
    6790                 :        199 :   return add_svalue (new unknown_svalue (integer_type_node));
    6791                 :            : }
    6792                 :            : 
    6793                 :            : /* Get a region of type TYPE for PTR_SID[OFFSET_SID/sizeof (*PTR_SID)].
    6794                 :            : 
    6795                 :            :    If OFFSET_SID is known to be zero, then dereference PTR_SID.
    6796                 :            :    Otherwise, impose a view of "typeof(*PTR_SID)[]" on *PTR_SID,
    6797                 :            :    and then get a view of type TYPE on the relevant array element.  */
    6798                 :            : 
    6799                 :            : region_id
    6800                 :       2087 : region_model::get_or_create_mem_ref (tree type,
    6801                 :            :                                      svalue_id ptr_sid,
    6802                 :            :                                      svalue_id offset_sid,
    6803                 :            :                                      region_model_context *ctxt)
    6804                 :            : {
    6805                 :       2087 :   svalue *ptr_sval = get_svalue (ptr_sid);
    6806                 :       2087 :   tree ptr_type = ptr_sval->get_type ();
    6807                 :       2087 :   gcc_assert (ptr_type);
    6808                 :            : 
    6809                 :       2087 :   region_id raw_rid = deref_rvalue (ptr_sid, ctxt);
    6810                 :            : 
    6811                 :       2087 :   svalue *offset_sval = get_svalue (offset_sid);
    6812                 :       2087 :   tree offset_type = offset_sval->get_type ();
    6813                 :       2087 :   gcc_assert (offset_type);
    6814                 :            : 
    6815                 :       2087 :   if (constant_svalue *cst_sval = offset_sval->dyn_cast_constant_svalue ())
    6816                 :            :     {
    6817                 :       1898 :       if (zerop (cst_sval->get_constant ()))
    6818                 :            :         {
    6819                 :            :           /* Handle the zero offset case.  */
    6820                 :       1533 :           return get_or_create_view (raw_rid, type, ctxt);
    6821                 :            :         }
    6822                 :            : 
    6823                 :            :       /* If we're already within an array of the correct type,
    6824                 :            :          then we want to reuse that array, rather than starting
    6825                 :            :          a new view.
    6826                 :            :          If so, figure out our raw_rid's offset from its parent,
    6827                 :            :          if we can, and use that to offset OFFSET_SID, and create
    6828                 :            :          the element within the parent region.  */
    6829                 :        402 :       region *raw_reg = get_region (raw_rid);
    6830                 :        402 :       region_id parent_rid = raw_reg->get_parent ();
    6831                 :        402 :       tree parent_type = get_region (parent_rid)->get_type ();
    6832                 :        402 :       if (parent_type
    6833                 :         56 :           && TREE_CODE (parent_type) == ARRAY_TYPE)
    6834                 :            :         {
    6835                 :            :           // TODO: check we have the correct parent type
    6836                 :         46 :           array_region *parent_array = get_region <array_region> (parent_rid);
    6837                 :         46 :           array_region::key_t key_for_raw_rid;
    6838                 :         46 :           if (parent_array->get_key_for_child_region (raw_rid,
    6839                 :            :                                                       &key_for_raw_rid))
    6840                 :            :             {
    6841                 :            :               /* Convert from offset to index.  */
    6842                 :         37 :               svalue_id index_sid
    6843                 :         37 :                 = convert_byte_offset_to_array_index (ptr_type, offset_sid);
    6844                 :         74 :               if (tree index_cst
    6845                 :         37 :                     = get_svalue (index_sid)->maybe_get_constant ())
    6846                 :            :                 {
    6847                 :         37 :                   array_region::key_t index_offset
    6848                 :         37 :                     = array_region::key_from_constant (index_cst);
    6849                 :         37 :                   array_region::key_t index_rel_to_parent
    6850                 :         37 :                     = key_for_raw_rid + index_offset;
    6851                 :         37 :                   tree index_rel_to_parent_cst
    6852                 :         37 :                     = wide_int_to_tree (integer_type_node,
    6853                 :            :                                         index_rel_to_parent);
    6854                 :         37 :                   svalue_id index_sid
    6855                 :         37 :                     = get_or_create_constant_svalue (index_rel_to_parent_cst);
    6856                 :            : 
    6857                 :            :                   /* Carry on, using the parent region and adjusted index.  */
    6858                 :         37 :                   region_id element_rid
    6859                 :            :                     = parent_array->get_element (this, raw_rid, index_sid,
    6860                 :         37 :                                                  ctxt);
    6861                 :         37 :                   return get_or_create_view (element_rid, type, ctxt);
    6862                 :            :                 }
    6863                 :            :             }
    6864                 :            :         }
    6865                 :            :     }
    6866                 :            : 
    6867                 :        554 :   tree array_type = build_array_type (TREE_TYPE (ptr_type),
    6868                 :            :                                       integer_type_node);
    6869                 :        554 :   region_id array_view_rid = get_or_create_view (raw_rid, array_type, ctxt);
    6870                 :        554 :   array_region *array_reg = get_region <array_region> (array_view_rid);
    6871                 :            : 
    6872                 :        554 :   svalue_id index_sid
    6873                 :        554 :     = convert_byte_offset_to_array_index (ptr_type, offset_sid);
    6874                 :            : 
    6875                 :        554 :   region_id element_rid
    6876                 :        554 :     = array_reg->get_element (this, array_view_rid, index_sid, ctxt);
    6877                 :            : 
    6878                 :        554 :   return get_or_create_view (element_rid, type, ctxt);
    6879                 :            : }
    6880                 :            : 
    6881                 :            : /* Get a region of type TYPE for PTR_SID + OFFSET_SID.
    6882                 :            : 
    6883                 :            :    If OFFSET_SID is known to be zero, then dereference PTR_SID.
    6884                 :            :    Otherwise, impose a view of "typeof(*PTR_SID)[]" on *PTR_SID,
    6885                 :            :    and then get a view of type TYPE on the relevant array element.  */
    6886                 :            : 
    6887                 :            : region_id
    6888                 :        386 : region_model::get_or_create_pointer_plus_expr (tree type,
    6889                 :            :                                                svalue_id ptr_sid,
    6890                 :            :                                                svalue_id offset_in_bytes_sid,
    6891                 :            :                                                region_model_context *ctxt)
    6892                 :            : {
    6893                 :        386 :   return get_or_create_mem_ref (type,
    6894                 :            :                                 ptr_sid,
    6895                 :            :                                 offset_in_bytes_sid,
    6896                 :        386 :                                 ctxt);
    6897                 :            : }
    6898                 :            : 
    6899                 :            : /* Get or create a view of type TYPE of the region with id RAW_ID.
    6900                 :            :    Return the id of the view (or RAW_ID if it of the same type).  */
    6901                 :            : 
    6902                 :            : region_id
    6903                 :       6283 : region_model::get_or_create_view (region_id raw_rid, tree type,
    6904                 :            :                                   region_model_context *ctxt)
    6905                 :            : {
    6906                 :       6283 :   region *raw_region = get_region (raw_rid);
    6907                 :            : 
    6908                 :       6283 :   gcc_assert (TYPE_P (type));
    6909                 :       6283 :   if (type != raw_region->get_type ())
    6910                 :            :     {
    6911                 :            :       /* If the region already has a view of the requested type,
    6912                 :            :          reuse it.  */
    6913                 :       2287 :       region_id existing_view_rid = raw_region->get_view (type, this);
    6914                 :       2287 :       if (!existing_view_rid.null_p ())
    6915                 :       1010 :         return existing_view_rid;
    6916                 :            : 
    6917                 :            :       /* Otherwise, make one (adding it to the region_model and
    6918                 :            :          to the viewed region).  */
    6919                 :       1277 :       region_id view_rid = add_region_for_type (raw_rid, type, ctxt);
    6920                 :       1277 :       raw_region->add_view (view_rid, this);
    6921                 :            :       // TODO: something to signify that this is a "view"
    6922                 :       1277 :       return view_rid;
    6923                 :            :     }
    6924                 :            : 
    6925                 :       3996 :   return raw_rid;
    6926                 :            : }
    6927                 :            : 
    6928                 :            : /* Attempt to get the fndecl used at CALL, if known, or NULL_TREE
    6929                 :            :    otherwise.  */
    6930                 :            : 
    6931                 :            : tree
    6932                 :      36000 : region_model::get_fndecl_for_call (const gcall *call,
    6933                 :            :                                    region_model_context *ctxt)
    6934                 :            : {
    6935                 :      36000 :   tree fn_ptr = gimple_call_fn (call);
    6936                 :      36000 :   if (fn_ptr == NULL_TREE)
    6937                 :            :     return NULL_TREE;
    6938                 :      35934 :   svalue_id fn_ptr_sid = get_rvalue (fn_ptr, ctxt);
    6939                 :      35934 :   svalue *fn_ptr_sval = get_svalue (fn_ptr_sid);
    6940                 :      35934 :   if (region_svalue *fn_ptr_ptr = fn_ptr_sval->dyn_cast_region_svalue ())
    6941                 :            :     {
    6942                 :      35725 :       region_id fn_rid = fn_ptr_ptr->get_pointee ();
    6943                 :      35725 :       code_region *code = get_root_region ()->get_code_region (this);
    6944                 :      35725 :       if (code)
    6945                 :            :         {
    6946                 :      35725 :           tree fn_decl = code->get_tree_for_child_region (fn_rid);
    6947                 :      35725 :           if (!fn_decl)
    6948                 :      35725 :             return NULL_TREE;
    6949                 :      35714 :           cgraph_node *node = cgraph_node::get (fn_decl);
    6950                 :      35714 :           if (!node)
    6951                 :            :             return NULL_TREE;
    6952                 :      35714 :           const cgraph_node *ultimate_node = node->ultimate_alias_target ();
    6953                 :      35714 :           if (ultimate_node)
    6954                 :      35714 :             return ultimate_node->decl;
    6955                 :            :         }
    6956                 :            :     }
    6957                 :            : 
    6958                 :            :   return NULL_TREE;
    6959                 :            : }
    6960                 :            : 
    6961                 :            : /* struct model_merger.  */
    6962                 :            : 
    6963                 :            : /* Dump a multiline representation of this merger to PP.  */
    6964                 :            : 
    6965                 :            : void
    6966                 :          0 : model_merger::dump_to_pp (pretty_printer *pp) const
    6967                 :            : {
    6968                 :          0 :   pp_string (pp, "model A:");
    6969                 :          0 :   pp_newline (pp);
    6970                 :          0 :   m_model_a->dump_to_pp (pp, false);
    6971                 :          0 :   pp_newline (pp);
    6972                 :            : 
    6973                 :          0 :   pp_string (pp, "model B:");
    6974                 :          0 :   pp_newline (pp);
    6975                 :          0 :   m_model_b->dump_to_pp (pp, false);
    6976                 :          0 :   pp_newline (pp);
    6977                 :            : 
    6978                 :          0 :   pp_string (pp, "merged model:");
    6979                 :          0 :   pp_newline (pp);
    6980                 :          0 :   m_merged_model->dump_to_pp (pp, false);
    6981                 :          0 :   pp_newline (pp);
    6982                 :            : 
    6983                 :          0 :   pp_string (pp, "region map: model A to merged model:");
    6984                 :          0 :   pp_newline (pp);
    6985                 :          0 :   m_map_regions_from_a_to_m.dump_to_pp (pp);
    6986                 :          0 :   pp_newline (pp);
    6987                 :            : 
    6988                 :          0 :   pp_string (pp, "region map: model B to merged model:");
    6989                 :          0 :   pp_newline (pp);
    6990                 :          0 :   m_map_regions_from_b_to_m.dump_to_pp (pp);
    6991                 :          0 :   pp_newline (pp);
    6992                 :            : 
    6993                 :          0 :   m_sid_mapping->dump_to_pp (pp);
    6994                 :          0 : }
    6995                 :            : 
    6996                 :            : /* Dump a multiline representation of this merger to FILE.  */
    6997                 :            : 
    6998                 :            : void
    6999                 :          0 : model_merger::dump (FILE *fp) const
    7000                 :            : {
    7001                 :          0 :   pretty_printer pp;
    7002                 :          0 :   pp_format_decoder (&pp) = default_tree_printer;
    7003                 :          0 :   pp_show_color (&pp) = pp_show_color (global_dc->printer);
    7004                 :          0 :   pp.buffer->stream = fp;
    7005                 :          0 :   dump_to_pp (&pp);
    7006                 :          0 :   pp_flush (&pp);
    7007                 :          0 : }
    7008                 :            : 
    7009                 :            : /* Dump a multiline representation of this merger to stderr.  */
    7010                 :            : 
    7011                 :            : DEBUG_FUNCTION void
    7012                 :          0 : model_merger::dump () const
    7013                 :            : {
    7014                 :          0 :   dump (stderr);
    7015                 :          0 : }
    7016                 :            : 
    7017                 :            : /* Attempt to merge the svalues of SID_A and SID_B (from their
    7018                 :            :    respective models), writing the id of the resulting svalue
    7019                 :            :    into *MERGED_SID.
    7020                 :            :    Return true if the merger is possible, false otherwise.  */
    7021                 :            : 
    7022                 :            : bool
    7023                 :    1195280 : model_merger::can_merge_values_p (svalue_id sid_a,
    7024                 :            :                                   svalue_id sid_b,
    7025                 :            :                                   svalue_id *merged_sid)
    7026                 :            : {
    7027                 :    1195280 :   gcc_assert (merged_sid);
    7028                 :    1195280 :   svalue *sval_a = m_model_a->get_svalue (sid_a);
    7029                 :    1195280 :   svalue *sval_b = m_model_b->get_svalue (sid_b);
    7030                 :            : 
    7031                 :            :   /* If both are NULL, then the "values" are trivially mergeable.  */
    7032                 :    1195280 :   if (!sval_a && !sval_b)
    7033                 :            :     return true;
    7034                 :            : 
    7035                 :            :   /* If one is NULL and the other non-NULL, then the "values"
    7036                 :            :      are not mergeable.  */
    7037                 :     814767 :   if (!(sval_a && sval_b))
    7038                 :            :     return false;
    7039                 :            : 
    7040                 :            :   /* Have they both already been mapped to the same new svalue_id?
    7041                 :            :      If so, use it.  */
    7042                 :     813040 :   svalue_id sid_a_in_m
    7043                 :     813040 :     = m_sid_mapping->m_map_from_a_to_m.get_dst_for_src (sid_a);
    7044                 :     813040 :   svalue_id sid_b_in_m
    7045                 :     813040 :     = m_sid_mapping->m_map_from_b_to_m.get_dst_for_src (sid_b);
    7046                 :     813040 :   if (!sid_a_in_m.null_p ()
    7047                 :      60967 :       && !sid_b_in_m.null_p ()
    7048                 :     873448 :       && sid_a_in_m == sid_b_in_m)
    7049                 :            :     {
    7050                 :      60382 :       *merged_sid = sid_a_in_m;
    7051                 :      60382 :       return true;
    7052                 :            :     }
    7053                 :            : 
    7054                 :     752658 :   tree type = sval_a->get_type ();
    7055                 :     752658 :   if (type == NULL_TREE)
    7056                 :          0 :     type = sval_b->get_type ();
    7057                 :            : 
    7058                 :            :   /* If the values have different kinds, or are both unknown,
    7059                 :            :      then merge as "unknown".  */
    7060                 :     752658 :   if (sval_a->get_kind () != sval_b->get_kind ()
    7061                 :     752658 :       || sval_a->get_kind () == SK_UNKNOWN)
    7062                 :            :     {
    7063                 :     556442 :       svalue *merged_sval = new unknown_svalue (type);
    7064                 :     556442 :       *merged_sid = m_merged_model->add_svalue (merged_sval);
    7065                 :     556442 :       record_svalues (sid_a, sid_b, *merged_sid);
    7066                 :     556442 :       return true;
    7067                 :            :     }
    7068                 :            : 
    7069                 :     196216 :   gcc_assert (sval_a->get_kind () == sval_b->get_kind ());
    7070                 :            : 
    7071                 :     196216 :   switch (sval_a->get_kind ())
    7072                 :            :     {
    7073                 :          0 :     default:
    7074                 :          0 :     case SK_UNKNOWN: /* SK_UNKNOWN handled above.  */
    7075                 :          0 :        gcc_unreachable ();
    7076                 :            : 
    7077                 :     176878 :     case SK_REGION:
    7078                 :     176878 :       {
    7079                 :            :         /* If we have two region pointers, then we can merge (possibly to
    7080                 :            :            "unknown").  */
    7081                 :     176878 :         const region_svalue &region_sval_a = *as_a <region_svalue *> (sval_a);
    7082                 :     176878 :         const region_svalue &region_sval_b = *as_a <region_svalue *> (sval_b);
    7083                 :     176878 :         region_svalue::merge_values (region_sval_a, region_sval_b,
    7084                 :            :                                      merged_sid, type,
    7085                 :            :                                      this);
    7086                 :     176878 :         record_svalues (sid_a, sid_b, *merged_sid);
    7087                 :     176878 :         return true;
    7088                 :            :       }
    7089                 :      12955 :       break;
    7090                 :      12955 :     case SK_CONSTANT:
    7091                 :      12955 :       {
    7092                 :            :         /* If we have two constants, then we can merge.  */
    7093                 :      12955 :         const constant_svalue &cst_sval_a = *as_a <constant_svalue *> (sval_a);
    7094                 :      12955 :         const constant_svalue &cst_sval_b = *as_a <constant_svalue *> (sval_b);
    7095                 :      12955 :         constant_svalue::merge_values (cst_sval_a, cst_sval_b,
    7096                 :            :                                        merged_sid, this);
    7097                 :      12955 :         record_svalues (sid_a, sid_b, *merged_sid);
    7098                 :      12955 :         return true;
    7099                 :            :       }
    7100                 :            :       break;
    7101                 :            : 
    7102                 :            :     case SK_POISONED:
    7103                 :            :     case SK_SETJMP:
    7104                 :            :       return false;
    7105                 :            :     }
    7106                 :            : }
    7107                 :            : 
    7108                 :            : /* Record that A_RID in model A and B_RID in model B
    7109                 :            :    correspond to MERGED_RID in the merged model, so
    7110                 :            :    that pointers can be accurately merged.  */
    7111                 :            : 
    7112                 :            : void
    7113                 :     154836 : model_merger::record_regions (region_id a_rid,
    7114                 :            :                               region_id b_rid,
    7115                 :            :                               region_id merged_rid)
    7116                 :            : {
    7117                 :     154836 :   m_map_regions_from_a_to_m.put (a_rid, merged_rid);
    7118                 :     154836 :   m_map_regions_from_b_to_m.put (b_rid, merged_rid);
    7119                 :     154836 : }
    7120                 :            : 
    7121                 :            : /* Record that A_SID in model A and B_SID in model B
    7122                 :            :    correspond to MERGED_SID in the merged model.  */
    7123                 :            : 
    7124                 :            : void
    7125                 :     746275 : model_merger::record_svalues (svalue_id a_sid,
    7126                 :            :                               svalue_id b_sid,
    7127                 :            :                               svalue_id merged_sid)
    7128                 :            : {
    7129                 :     746275 :   gcc_assert (m_sid_mapping);
    7130                 :     746275 :   m_sid_mapping->m_map_from_a_to_m.put (a_sid, merged_sid);
    7131                 :     746275 :   m_sid_mapping->m_map_from_b_to_m.put (b_sid, merged_sid);
    7132                 :     746275 : }
    7133                 :            : 
    7134                 :            : /* struct svalue_id_merger_mapping.  */
    7135                 :            : 
    7136                 :            : /* svalue_id_merger_mapping's ctor.  */
    7137                 :            : 
    7138                 :     173457 : svalue_id_merger_mapping::svalue_id_merger_mapping (const region_model &a,
    7139                 :     173457 :                                                     const region_model &b)
    7140                 :     173457 : : m_map_from_a_to_m (a.get_num_svalues ()),
    7141                 :     520359 :   m_map_from_b_to_m (b.get_num_svalues ())
    7142                 :            : {
    7143                 :     173457 : }
    7144                 :            : 
    7145                 :            : /* Dump a multiline representation of this to PP.  */
    7146                 :            : 
    7147                 :            : void
    7148                 :          0 : svalue_id_merger_mapping::dump_to_pp (pretty_printer *pp) const
    7149                 :            : {
    7150                 :          0 :   pp_string (pp, "svalue_id map: model A to merged model:");
    7151                 :          0 :   pp_newline (pp);
    7152                 :          0 :   m_map_from_a_to_m.dump_to_pp (pp);
    7153                 :          0 :   pp_newline (pp);
    7154                 :            : 
    7155                 :          0 :   pp_string (pp, "svalue_id map: model B to merged model:");
    7156                 :          0 :   pp_newline (pp);
    7157                 :          0 :   m_map_from_b_to_m.dump_to_pp (pp);
    7158                 :          0 :   pp_newline (pp);
    7159                 :          0 : }
    7160                 :            : 
    7161                 :            : /* Dump a multiline representation of this to FILE.  */
    7162                 :            : 
    7163                 :            : void
    7164                 :          0 : svalue_id_merger_mapping::dump (FILE *fp) const
    7165                 :            : {
    7166                 :          0 :   pretty_printer pp;
    7167                 :          0 :   pp_format_decoder (&pp) = default_tree_printer;
    7168                 :          0 :   pp_show_color (&pp) = pp_show_color (global_dc->printer);
    7169                 :          0 :   pp.buffer->stream = fp;
    7170                 :          0 :   dump_to_pp (&pp);
    7171                 :          0 :   pp_flush (&pp);
    7172                 :          0 : }
    7173                 :            : 
    7174                 :            : /* Dump a multiline representation of this to stderr.  */
    7175                 :            : 
    7176                 :            : DEBUG_FUNCTION void
    7177                 :          0 : svalue_id_merger_mapping::dump () const
    7178                 :            : {
    7179                 :          0 :   dump (stderr);
    7180                 :          0 : }
    7181                 :            : 
    7182                 :            : /* struct canonicalization.  */
    7183                 :            : 
    7184                 :            : /* canonicalization's ctor.  */
    7185                 :            : 
    7186                 :      59945 : canonicalization::canonicalization (const region_model &model)
    7187                 :            : : m_model (model),
    7188                 :      59945 :   m_rid_map (model.get_num_regions ()),
    7189                 :      59945 :   m_sid_map (model.get_num_svalues ()),
    7190                 :            :   m_next_rid_int (0),
    7191                 :     179458 :   m_next_sid_int (0)
    7192                 :            : {
    7193                 :      59945 : }
    7194                 :            : 
    7195                 :            : /* If we've not seen RID yet, assign it a canonicalized region_id,
    7196                 :            :    and walk the region's svalue and then the region.  */
    7197                 :            : 
    7198                 :            : void
    7199                 :    1848610 : canonicalization::walk_rid (region_id rid)
    7200                 :            : {
    7201                 :            :   /* Stop if we've already seen RID.  */
    7202                 :    1848610 :   if (!m_rid_map.get_dst_for_src (rid).null_p ())
    7203                 :            :     return;
    7204                 :            : 
    7205                 :    1019540 :   region *region = m_model.get_region (rid);
    7206                 :    1019540 :   if (region)
    7207                 :            :     {
    7208                 :     907440 :       m_rid_map.put (rid, region_id::from_int (m_next_rid_int++));
    7209                 :     907440 :       walk_sid (region->get_value_direct ());
    7210                 :     907440 :       region->walk_for_canonicalization (this);
    7211                 :            :     }
    7212                 :            : }
    7213                 :            : 
    7214                 :            : /* If we've not seen SID yet, assign it a canonicalized svalue_id,
    7215                 :            :    and walk the svalue (and potentially regions e.g. for ptr values).  */
    7216                 :            : 
    7217                 :            : void
    7218                 :    1555840 : canonicalization::walk_sid (svalue_id sid)
    7219                 :            : {
    7220                 :            :   /* Stop if we've already seen SID.  */
    7221                 :    1555840 :   if (!m_sid_map.get_dst_for_src (sid).null_p ())
    7222                 :            :     return;
    7223                 :            : 
    7224                 :     889584 :   svalue *sval = m_model.get_svalue (sid);
    7225                 :     889584 :   if (sval)
    7226                 :            :     {
    7227                 :     512582 :       m_sid_map.put (sid, svalue_id::from_int (m_next_sid_int++));
    7228                 :            :       /* Potentially walk regions e.g. for ptrs.  */
    7229                 :     512582 :       sval->walk_for_canonicalization (this);
    7230                 :            :     }
    7231                 :            : }
    7232                 :            : 
    7233                 :            : /* Dump a multiline representation of this to PP.  */
    7234                 :            : 
    7235                 :            : void
    7236                 :          0 : canonicalization::dump_to_pp (pretty_printer *pp) const
    7237                 :            : {
    7238                 :          0 :   pp_string (pp, "region_id map:");
    7239                 :          0 :   pp_newline (pp);
    7240                 :          0 :   m_rid_map.dump_to_pp (pp);
    7241                 :          0 :   pp_newline (pp);
    7242                 :            : 
    7243                 :          0 :   pp_string (pp, "svalue_id map:");
    7244                 :          0 :   pp_newline (pp);
    7245                 :          0 :   m_sid_map.dump_to_pp (pp);
    7246                 :          0 :   pp_newline (pp);
    7247                 :          0 : }
    7248                 :            : 
    7249                 :            : /* Dump a multiline representation of this to FILE.  */
    7250                 :            : 
    7251                 :            : void
    7252                 :          0 : canonicalization::dump (FILE *fp) const
    7253                 :            : {
    7254                 :          0 :   pretty_printer pp;
    7255                 :          0 :   pp_format_decoder (&pp) = default_tree_printer;
    7256                 :          0 :   pp_show_color (&pp) = pp_show_color (global_dc->printer);
    7257                 :          0 :   pp.buffer->stream = fp;
    7258                 :          0 :   dump_to_pp (&pp);
    7259                 :          0 :   pp_flush (&pp);
    7260                 :          0 : }
    7261                 :            : 
    7262                 :            : /* Dump a multiline representation of this to stderr.  */
    7263                 :            : 
    7264                 :            : DEBUG_FUNCTION void
    7265                 :          0 : canonicalization::dump () const
    7266                 :            : {
    7267                 :          0 :   dump (stderr);
    7268                 :          0 : }
    7269                 :            : 
    7270                 :            : } // namespace ana
    7271                 :            : 
    7272                 :            : /* Update HSTATE with a hash of SID.  */
    7273                 :            : 
    7274                 :            : void
    7275                 :    1991600 : inchash::add (svalue_id sid, inchash::hash &hstate)
    7276                 :            : {
    7277                 :    1991600 :   hstate.add_int (sid.as_int ());
    7278                 :    1991600 : }
    7279                 :            : 
    7280                 :            : /* Update HSTATE with a hash of RID.  */
    7281                 :            : 
    7282                 :            : void
    7283                 :    1993600 : inchash::add (region_id rid, inchash::hash &hstate)
    7284                 :            : {
    7285                 :    1993600 :   hstate.add_int (rid.as_int ());
    7286                 :    1993600 : }
    7287                 :            : 
    7288                 :            : /* Dump RMODEL fully to stderr (i.e. without summarization).  */
    7289                 :            : 
    7290                 :            : DEBUG_FUNCTION void
    7291                 :          0 : debug (const region_model &rmodel)
    7292                 :            : {
    7293                 :          0 :   rmodel.dump (false);
    7294                 :          0 : }
    7295                 :            : 
    7296                 :            : namespace ana {
    7297                 :            : 
    7298                 :            : #if CHECKING_P
    7299                 :            : 
    7300                 :            : namespace selftest {
    7301                 :            : 
    7302                 :            : /* Build a constant tree of the given type from STR.  */
    7303                 :            : 
    7304                 :            : static tree
    7305                 :         32 : build_real_cst_from_string (tree type, const char *str)
    7306                 :            : {
    7307                 :         32 :   REAL_VALUE_TYPE real;
    7308                 :          0 :   real_from_string (&real, str);
    7309                 :         32 :   return build_real (type, real);
    7310                 :            : }
    7311                 :            : 
    7312                 :            : /* Append various "interesting" constants to OUT (e.g. NaN).  */
    7313                 :            : 
    7314                 :            : static void
    7315                 :          4 : append_interesting_constants (auto_vec<tree> *out)
    7316                 :            : {
    7317                 :          4 :   out->safe_push (build_int_cst (integer_type_node, 0));
    7318                 :          4 :   out->safe_push (build_int_cst (integer_type_node, 42));
    7319                 :          4 :   out->safe_push (build_int_cst (unsigned_type_node, 0));
    7320                 :          4 :   out->safe_push (build_int_cst (unsigned_type_node, 42));
    7321                 :          8 :   out->safe_push (build_real_cst_from_string (float_type_node, "QNaN"));
    7322                 :          8 :   out->safe_push (build_real_cst_from_string (float_type_node, "-QNaN"));
    7323                 :          8 :   out->safe_push (build_real_cst_from_string (float_type_node, "SNaN"));
    7324                 :          8 :   out->safe_push (build_real_cst_from_string (float_type_node, "-SNaN"));
    7325                 :          8 :   out->safe_push (build_real_cst_from_string (float_type_node, "0.0"));
    7326                 :          8 :   out->safe_push (build_real_cst_from_string (float_type_node, "-0.0"));
    7327                 :          8 :   out->safe_push (build_real_cst_from_string (float_type_node, "Inf"));
    7328                 :          8 :   out->safe_push (build_real_cst_from_string (float_type_node, "-Inf"));
    7329                 :          4 : }
    7330                 :            : 
    7331                 :            : /* Verify that tree_cmp is a well-behaved comparator for qsort, even
    7332                 :            :    if the underlying constants aren't comparable.  */
    7333                 :            : 
    7334                 :            : static void
    7335                 :          2 : test_tree_cmp_on_constants ()
    7336                 :            : {
    7337                 :          2 :   auto_vec<tree> csts;
    7338                 :          2 :   append_interesting_constants (&csts);
    7339                 :            : 
    7340                 :            :   /* Try sorting every triple. */
    7341                 :          2 :   const unsigned num = csts.length ();
    7342                 :         26 :   for (unsigned i = 0; i < num; i++)
    7343                 :        312 :     for (unsigned j = 0; j < num; j++)
    7344                 :       3744 :       for (unsigned k = 0; k < num; k++)
    7345                 :            :         {
    7346                 :       6912 :           auto_vec<tree> v (3);
    7347                 :       3456 :           v.quick_push (csts[i]);
    7348                 :       3456 :           v.quick_push (csts[j]);
    7349                 :       3456 :           v.quick_push (csts[k]);
    7350                 :       6912 :           v.qsort (tree_cmp);
    7351                 :            :         }
    7352                 :          2 : }
    7353                 :            : 
    7354                 :            : /* Implementation detail of the ASSERT_CONDITION_* macros.  */
    7355                 :            : 
    7356                 :            : void
    7357                 :       1448 : assert_condition (const location &loc,
    7358                 :            :                   region_model &model,
    7359                 :            :                   tree lhs, tree_code op, tree rhs,
    7360                 :            :                   tristate expected)
    7361                 :            : {
    7362                 :       1448 :   tristate actual = model.eval_condition (lhs, op, rhs, NULL);
    7363                 :       1448 :   ASSERT_EQ_AT (loc, actual, expected);
    7364                 :       1448 : }
    7365                 :            : 
    7366                 :            : /* Implementation detail of ASSERT_DUMP_TREE_EQ.  */
    7367                 :            : 
    7368                 :            : static void
    7369                 :          2 : assert_dump_tree_eq (const location &loc, tree t, const char *expected)
    7370                 :            : {
    7371                 :          4 :   auto_fix_quotes sentinel;
    7372                 :          4 :   pretty_printer pp;
    7373                 :          2 :   pp_format_decoder (&pp) = default_tree_printer;
    7374                 :          2 :   dump_tree (&pp, t);
    7375                 :          2 :   ASSERT_STREQ_AT (loc, pp_formatted_text (&pp), expected);
    7376                 :          2 : }
    7377                 :            : 
    7378                 :            : /* Assert that dump_tree (T) is EXPECTED.  */
    7379                 :            : 
    7380                 :            : #define ASSERT_DUMP_TREE_EQ(T, EXPECTED) \
    7381                 :            :   SELFTEST_BEGIN_STMT                                                   \
    7382                 :            :   assert_dump_tree_eq ((SELFTEST_LOCATION), (T), (EXPECTED)); \
    7383                 :            :   SELFTEST_END_STMT
    7384                 :            : 
    7385                 :            : /* Implementation detail of ASSERT_DUMP_EQ.  */
    7386                 :            : 
    7387                 :            : static void
    7388                 :         16 : assert_dump_eq (const location &loc,
    7389                 :            :                 const region_model &model,
    7390                 :            :                 bool summarize,
    7391                 :            :                 const char *expected)
    7392                 :            : {
    7393                 :         32 :   auto_fix_quotes sentinel;
    7394                 :         32 :   pretty_printer pp;
    7395                 :         16 :   pp_format_decoder (&pp) = default_tree_printer;
    7396                 :         16 :   model.dump_to_pp (&pp, summarize);
    7397                 :         16 :   ASSERT_STREQ_AT (loc, pp_formatted_text (&pp), expected);
    7398                 :         16 : }
    7399                 :            : 
    7400                 :            : /* Assert that MODEL.dump_to_pp (SUMMARIZE) is EXPECTED.  */
    7401                 :            : 
    7402                 :            : #define ASSERT_DUMP_EQ(MODEL, SUMMARIZE, EXPECTED) \
    7403                 :            :   SELFTEST_BEGIN_STMT                                                   \
    7404                 :            :   assert_dump_eq ((SELFTEST_LOCATION), (MODEL), (SUMMARIZE), (EXPECTED)); \
    7405                 :            :   SELFTEST_END_STMT
    7406                 :            : 
    7407                 :            : /* Smoketest for region_model::dump_to_pp.  */
    7408                 :            : 
    7409                 :            : static void
    7410                 :          2 : test_dump ()
    7411                 :            : {
    7412                 :          2 :   region_model model;
    7413                 :          2 :   model.get_root_region ()->ensure_stack_region (&model);
    7414                 :          2 :   model.get_root_region ()->ensure_globals_region (&model);
    7415                 :          2 :   model.get_root_region ()->ensure_heap_region (&model);
    7416                 :            : 
    7417                 :          2 :   ASSERT_DUMP_EQ (model, false,
    7418                 :            :                   "r0: {kind: `root', parent: null, sval: null}\n"
    7419                 :            :                   "|-stack: r1: {kind: `stack', parent: r0, sval: sv0}\n"
    7420                 :            :                   "|  |: sval: sv0: {poisoned: uninit}\n"
    7421                 :            :                   "|-globals: r2: {kind: `globals', parent: r0, sval: null, map: {}}\n"
    7422                 :            :                   "`-heap: r3: {kind: `heap', parent: r0, sval: sv1}\n"
    7423                 :            :                   "  |: sval: sv1: {poisoned: uninit}\n"
    7424                 :            :                   "svalues:\n"
    7425                 :            :                   "  sv0: {poisoned: uninit}\n"
    7426                 :            :                   "  sv1: {poisoned: uninit}\n"
    7427                 :            :                   "constraint manager:\n"
    7428                 :            :                   "  equiv classes:\n"
    7429                 :            :                   "  constraints:\n");
    7430                 :          2 :   ASSERT_DUMP_EQ (model, true, "");
    7431                 :          2 : }
    7432                 :            : 
    7433                 :            : /* Helper function for selftests.  Create a struct or union type named NAME,
    7434                 :            :    with the fields given by the FIELD_DECLS in FIELDS.
    7435                 :            :    If IS_STRUCT is true create a RECORD_TYPE (aka a struct), otherwise
    7436                 :            :    create a UNION_TYPE.  */
    7437                 :            : 
    7438                 :            : static tree
    7439                 :          2 : make_test_compound_type (const char *name, bool is_struct,
    7440                 :            :                          const auto_vec<tree> *fields)
    7441                 :            : {
    7442                 :          2 :   tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
    7443                 :          2 :   TYPE_NAME (t) = get_identifier (name);
    7444                 :          2 :   TYPE_SIZE (t) = 0;
    7445                 :            : 
    7446                 :          2 :   tree fieldlist = NULL;
    7447                 :          2 :   int i;
    7448                 :          2 :   tree field;
    7449                 :          6 :   FOR_EACH_VEC_ELT (*fields, i, field)
    7450                 :            :     {
    7451                 :          4 :       gcc_assert (TREE_CODE (field) == FIELD_DECL);
    7452                 :          4 :       DECL_CONTEXT (field) = t;
    7453                 :          4 :       fieldlist = chainon (field, fieldlist);
    7454                 :            :     }
    7455                 :          2 :   fieldlist = nreverse (fieldlist);
    7456                 :          2 :   TYPE_FIELDS (t) = fieldlist;
    7457                 :            : 
    7458                 :          2 :   layout_type (t);
    7459                 :          2 :   return t;
    7460                 :            : }
    7461                 :            : 
    7462                 :            : /* Verify that dumps can show struct fields.  */
    7463                 :            : 
    7464                 :            : static void
    7465                 :          2 : test_dump_2 ()
    7466                 :            : {
    7467                 :          2 :   auto_vec<tree> fields;
    7468                 :          2 :   tree x_field = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
    7469                 :          2 :                              get_identifier ("x"), integer_type_node);
    7470                 :          2 :   fields.safe_push (x_field);
    7471                 :          2 :   tree y_field = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
    7472                 :          2 :                              get_identifier ("y"), integer_type_node);
    7473                 :          2 :   fields.safe_push (y_field);
    7474                 :          2 :   tree coord_type = make_test_compound_type ("coord", true, &fields);
    7475                 :            : 
    7476                 :          2 :   tree c = build_global_decl ("c", coord_type);
    7477                 :          2 :   tree c_x = build3 (COMPONENT_REF, TREE_TYPE (x_field),
    7478                 :            :                      c, x_field, NULL_TREE);
    7479                 :          2 :   tree c_y = build3 (COMPONENT_REF, TREE_TYPE (y_field),
    7480                 :            :                      c, y_field, NULL_TREE);
    7481                 :            : 
    7482                 :          2 :   tree int_17 = build_int_cst (integer_type_node, 17);
    7483                 :          2 :   tree int_m3 = build_int_cst (integer_type_node, -3);
    7484                 :            : 
    7485                 :          4 :   region_model model;
    7486                 :          2 :   model.set_value (c_x, int_17, NULL);
    7487                 :          2 :   model.set_value (c_y, int_m3, NULL);
    7488                 :            : 
    7489                 :            :   /* Simplified dump.  */
    7490                 :          2 :   ASSERT_DUMP_EQ (model, true, "c.x: 17, c.y: -3");
    7491                 :            : 
    7492                 :            :   /* Full dump.  */
    7493                 :          2 :   ASSERT_DUMP_EQ
    7494                 :            :     (model, false,
    7495                 :            :      "r0: {kind: `root', parent: null, sval: null}\n"
    7496                 :            :      "`-globals: r1: {kind: `globals', parent: r0, sval: null, map: {`c': r2}}\n"
    7497                 :            :      "  `-`c': r2: {kind: `struct', parent: r1, sval: null, type: `struct coord', map: {`x': r3, `y': r4}}\n"
    7498                 :            :      "    |: type: `struct coord'\n"
    7499                 :            :      "    |-`x': r3: {kind: `primitive', parent: r2, sval: sv0, type: `int'}\n"
    7500                 :            :      "    |  |: sval: sv0: {type: `int', `17'}\n"
    7501                 :            :      "    |  |: type: `int'\n"
    7502                 :            :      "    `-`y': r4: {kind: `primitive', parent: r2, sval: sv1, type: `int'}\n"
    7503                 :            :      "      |: sval: sv1: {type: `int', `-3'}\n"
    7504                 :            :      "      |: type: `int'\n"
    7505                 :            :      "svalues:\n"
    7506                 :            :      "  sv0: {type: `int', `17'}\n"
    7507                 :            :      "  sv1: {type: `int', `-3'}\n"
    7508                 :            :      "constraint manager:\n"
    7509                 :            :      "  equiv classes:\n"
    7510                 :            :      "  constraints:\n");
    7511                 :          2 : }
    7512                 :            : 
    7513                 :            : /* Verify that dumps can show array elements.  */
    7514                 :            : 
    7515                 :            : static void
    7516                 :          2 : test_dump_3 ()
    7517                 :            : {
    7518                 :          2 :   tree tlen = size_int (10);
    7519                 :          2 :   tree arr_type = build_array_type (char_type_node, build_index_type (tlen));
    7520                 :            : 
    7521                 :          2 :   tree a = build_global_decl ("a", arr_type);
    7522                 :            : 
    7523                 :          2 :   region_model model;
    7524                 :          2 :   tree int_0 = build_int_cst (integer_type_node, 0);
    7525                 :          2 :   tree a_0 = build4 (ARRAY_REF, char_type_node,
    7526                 :            :                      a, int_0, NULL_TREE, NULL_TREE);
    7527                 :          2 :   tree char_A = build_int_cst (char_type_node, 'A');
    7528                 :          2 :   model.set_value (a_0, char_A, NULL);
    7529                 :            : 
    7530                 :            :   /* Simplified dump.  */
    7531                 :          2 :   ASSERT_DUMP_EQ (model, true, "a[0]: 65");
    7532                 :            : 
    7533                 :            :   /* Full dump.  */
    7534                 :          2 :   ASSERT_DUMP_EQ
    7535                 :            :     (model, false,
    7536                 :            :      "r0: {kind: `root', parent: null, sval: null}\n"
    7537                 :            :      "`-globals: r1: {kind: `globals', parent: r0, sval: null, map: {`a': r2}}\n"
    7538                 :            :      "  `-`a': r2: {kind: `array', parent: r1, sval: null, type: `char[11]', array: {[0]: r3}}\n"
    7539                 :            :      "    |: type: `char[11]'\n"
    7540                 :            :      "    `-[0]: r3: {kind: `primitive', parent: r2, sval: sv1, type: `char'}\n"
    7541                 :            :      "      |: sval: sv1: {type: `char', `65'}\n"
    7542                 :            :      "      |: type: `char'\n"
    7543                 :            :      "svalues:\n"
    7544                 :            :      "  sv0: {type: `int', `0'}\n"
    7545                 :            :      "  sv1: {type: `char', `65'}\n"
    7546                 :            :      "constraint manager:\n"
    7547                 :            :      "  equiv classes:\n"
    7548                 :            :      "  constraints:\n");
    7549                 :          2 : }
    7550                 :            : 
    7551                 :            : /* Verify that region_model::get_representative_tree works as expected.  */
    7552                 :            : 
    7553                 :            : static void
    7554                 :          2 : test_get_representative_tree ()
    7555                 :            : {
    7556                 :            :   /* STRING_CST.  */
    7557                 :          2 :   {
    7558                 :          2 :     tree string_cst = build_string (4, "foo");
    7559                 :          2 :     region_model m;
    7560                 :          2 :     svalue_id str_sid = m.get_rvalue (string_cst, NULL);
    7561                 :          2 :     tree rep = m.get_representative_tree (str_sid);
    7562                 :          2 :     ASSERT_EQ (rep, string_cst);
    7563                 :            :   }
    7564                 :            : 
    7565                 :            :   /* String literal.  */
    7566                 :          2 :   {
    7567                 :          2 :     tree string_cst_ptr = build_string_literal (4, "foo");
    7568                 :          2 :     region_model m;
    7569                 :          2 :     svalue_id str_sid = m.get_rvalue (string_cst_ptr, NULL);
    7570                 :          2 :     tree rep = m.get_representative_tree (str_sid);
    7571                 :          2 :     ASSERT_DUMP_TREE_EQ (rep, "&\"foo\"[0]");
    7572                 :            :   }
    7573                 :          2 : }
    7574                 :            : 
    7575                 :            : /* Verify that calling region_model::get_rvalue repeatedly on the same
    7576                 :            :    tree constant retrieves the same svalue_id.  */
    7577                 :            : 
    7578                 :            : static void
    7579                 :          2 : test_unique_constants ()
    7580                 :            : {
    7581                 :          2 :   tree int_0 = build_int_cst (integer_type_node, 0);
    7582                 :          2 :   tree int_42 = build_int_cst (integer_type_node, 42);
    7583                 :            : 
    7584                 :          2 :   test_region_model_context ctxt;
    7585                 :          4 :   region_model model;
    7586                 :          2 :   ASSERT_EQ (model.get_rvalue (int_0, &ctxt), model.get_rvalue (int_0, &ctxt));
    7587                 :          2 :   ASSERT_EQ (model.get_rvalue (int_42, &ctxt),
    7588                 :            :              model.get_rvalue (int_42, &ctxt));
    7589                 :          2 :   ASSERT_NE (model.get_rvalue (int_0, &ctxt), model.get_rvalue (int_42, &ctxt));
    7590                 :          2 :   ASSERT_EQ (ctxt.get_num_diagnostics (), 0);
    7591                 :          2 : }
    7592                 :            : 
    7593                 :            : /* Check that operator== and hashing works as expected for the
    7594                 :            :    various svalue subclasses.  */
    7595                 :            : 
    7596                 :            : static void
    7597                 :          2 : test_svalue_equality ()
    7598                 :            : {
    7599                 :          2 :   tree int_42 = build_int_cst (integer_type_node, 42);
    7600                 :          2 :   tree int_0 = build_int_cst (integer_type_node, 0);
    7601                 :            : 
    7602                 :            :   /* Create pairs instances of the various subclasses of svalue,
    7603                 :            :      testing for hash and equality between (this, this) and
    7604                 :            :      (this, other of same subclass). */
    7605                 :          2 :   svalue *ptr_to_r0
    7606                 :          2 :     = new region_svalue (ptr_type_node, region_id::from_int (0));
    7607                 :          2 :   svalue *ptr_to_r1
    7608                 :          2 :     = new region_svalue (ptr_type_node, region_id::from_int (1));
    7609                 :            : 
    7610                 :          2 :   ASSERT_EQ (ptr_to_r0->hash (), ptr_to_r0->hash ());
    7611                 :          2 :   ASSERT_EQ (*ptr_to_r0, *ptr_to_r0);
    7612                 :            : 
    7613                 :          2 :   ASSERT_NE (ptr_to_r0->hash (), ptr_to_r1->hash ());
    7614                 :          2 :   ASSERT_NE (*ptr_to_r0, *ptr_to_r1);
    7615                 :            : 
    7616                 :          2 :   svalue *cst_int_42 = new constant_svalue (int_42);
    7617                 :          2 :   svalue *cst_int_0 = new constant_svalue (int_0);
    7618                 :            : 
    7619                 :          2 :   ASSERT_EQ (cst_int_42->hash (), cst_int_42->hash ());
    7620                 :          2 :   ASSERT_EQ (*cst_int_42, *cst_int_42);
    7621                 :            : 
    7622                 :          2 :   ASSERT_NE (cst_int_42->hash (), cst_int_0->hash ());
    7623                 :          2 :   ASSERT_NE (*cst_int_42, *cst_int_0);
    7624                 :            : 
    7625                 :          2 :   svalue *uninit = new poisoned_svalue (POISON_KIND_UNINIT, NULL_TREE);
    7626                 :          2 :   svalue *freed = new poisoned_svalue (POISON_KIND_FREED, NULL_TREE);
    7627                 :            : 
    7628                 :          2 :   ASSERT_EQ (uninit->hash (), uninit->hash ());
    7629                 :          2 :   ASSERT_EQ (*uninit, *uninit);
    7630                 :            : 
    7631                 :          2 :   ASSERT_NE (uninit->hash (), freed->hash ());
    7632                 :          2 :   ASSERT_NE (*uninit, *freed);
    7633                 :            : 
    7634                 :          2 :   svalue *unknown_0 = new unknown_svalue (ptr_type_node);
    7635                 :          2 :   svalue *unknown_1 = new unknown_svalue (ptr_type_node);
    7636                 :          2 :   ASSERT_EQ (unknown_0->hash (), unknown_0->hash ());
    7637                 :          2 :   ASSERT_EQ (*unknown_0, *unknown_0);
    7638                 :          2 :   ASSERT_EQ (*unknown_1, *unknown_1);
    7639                 :            : 
    7640                 :            :   /* Comparisons between different kinds of svalue.  */
    7641                 :          2 :   ASSERT_NE (*ptr_to_r0, *cst_int_42);
    7642                 :          2 :   ASSERT_NE (*ptr_to_r0, *uninit);
    7643                 :          2 :   ASSERT_NE (*ptr_to_r0, *unknown_0);
    7644                 :          2 :   ASSERT_NE (*cst_int_42, *ptr_to_r0);
    7645                 :          2 :   ASSERT_NE (*cst_int_42, *uninit);
    7646                 :          2 :   ASSERT_NE (*cst_int_42, *unknown_0);
    7647                 :          2 :   ASSERT_NE (*uninit, *ptr_to_r0);
    7648                 :          2 :   ASSERT_NE (*uninit, *cst_int_42);
    7649                 :          2 :   ASSERT_NE (*uninit, *unknown_0);
    7650                 :          2 :   ASSERT_NE (*unknown_0, *ptr_to_r0);
    7651                 :          2 :   ASSERT_NE (*unknown_0, *cst_int_42);
    7652                 :          2 :   ASSERT_NE (*unknown_0, *uninit);
    7653                 :            : 
    7654                 :          2 :   delete ptr_to_r0;
    7655                 :          2 :   delete ptr_to_r1;
    7656                 :          2 :   delete cst_int_42;
    7657                 :          2 :   delete cst_int_0;
    7658                 :          2 :   delete uninit;
    7659                 :          2 :   delete freed;
    7660                 :          2 :   delete unknown_0;
    7661                 :          2 :   delete unknown_1;
    7662                 :          2 : }
    7663                 :            : 
    7664                 :            : /* Check that operator== and hashing works as expected for the
    7665                 :            :    various region subclasses.  */
    7666                 :            : 
    7667                 :            : static void
    7668                 :          2 : test_region_equality ()
    7669                 :            : {
    7670                 :          2 :   region *r0
    7671                 :          2 :     = new primitive_region (region_id::from_int (3), integer_type_node);
    7672                 :          2 :   region *r1
    7673                 :          2 :     = new primitive_region (region_id::from_int (4), integer_type_node);
    7674                 :            : 
    7675                 :          2 :   ASSERT_EQ (*r0, *r0);
    7676                 :          2 :   ASSERT_EQ (r0->hash (), r0->hash ());
    7677                 :          2 :   ASSERT_NE (*r0, *r1);
    7678                 :          2 :   ASSERT_NE (r0->hash (), r1->hash ());
    7679                 :            : 
    7680                 :          2 :   delete r0;
    7681                 :          2 :   delete r1;
    7682                 :            : 
    7683                 :            :   // TODO: test coverage for the map within a map_region
    7684                 :          2 : }
    7685                 :            : 
    7686                 :            : /* A subclass of purge_criteria for selftests: purge all svalue_id instances.  */
    7687                 :            : 
    7688                 :          2 : class purge_all_svalue_ids : public purge_criteria
    7689                 :            : {
    7690                 :            : public:
    7691                 :          4 :   bool should_purge_p (svalue_id) const FINAL OVERRIDE
    7692                 :            :   {
    7693                 :          4 :     return true;
    7694                 :            :   }
    7695                 :            : };
    7696                 :            : 
    7697                 :            : /* A subclass of purge_criteria: purge a specific svalue_id.  */
    7698                 :            : 
    7699                 :          8 : class purge_one_svalue_id : public purge_criteria
    7700                 :            : {
    7701                 :            : public:
    7702                 :          2 :   purge_one_svalue_id (svalue_id victim) : m_victim (victim) {}
    7703                 :            : 
    7704                 :          8 :   purge_one_svalue_id (region_model model, tree expr)
    7705                 :          8 :   : m_victim (model.get_rvalue (expr, NULL)) {}
    7706                 :            : 
    7707                 :         12 :   bool should_purge_p (svalue_id sid) const FINAL OVERRIDE
    7708                 :            :   {
    7709                 :         12 :     return sid == m_victim;
    7710                 :            :   }
    7711                 :            : 
    7712                 :            : private:
    7713                 :            :   svalue_id m_victim;
    7714                 :            : };
    7715                 :            : 
    7716                 :            : /* Check that constraint_manager::purge works for individual svalue_ids.  */
    7717                 :            : 
    7718                 :            : static void
    7719                 :          2 : test_purging_by_criteria ()
    7720                 :            : {
    7721                 :          2 :   tree int_42 = build_int_cst (integer_type_node, 42);
    7722                 :          2 :   tree int_0 = build_int_cst (integer_type_node, 0);
    7723                 :            : 
    7724                 :          2 :   tree x = build_global_decl ("x", integer_type_node);
    7725                 :          2 :   tree y = build_global_decl ("y", integer_type_node);
    7726                 :            : 
    7727                 :          2 :   {
    7728                 :          4 :     region_model model0;
    7729                 :          2 :     region_model model1;
    7730                 :            : 
    7731                 :          2 :     ADD_SAT_CONSTRAINT (model1, x, EQ_EXPR, y);
    7732                 :          2 :     ASSERT_NE (model0, model1);
    7733                 :            : 
    7734                 :          2 :     purge_stats stats_for_px;
    7735                 :          2 :     purge_one_svalue_id px (model1, x);
    7736                 :          2 :     model1.get_constraints ()->purge (px, &stats_for_px);
    7737                 :          2 :     ASSERT_EQ (stats_for_px.m_num_equiv_classes, 0);
    7738                 :            : 
    7739                 :          2 :     purge_stats stats_for_py;
    7740                 :          4 :     purge_one_svalue_id py (model1.get_rvalue (y, NULL));
    7741                 :          2 :     model1.get_constraints ()->purge (py, &stats_for_py);
    7742                 :          2 :     ASSERT_EQ (stats_for_py.m_num_equiv_classes, 1);
    7743                 :            : 
    7744                 :          2 :     ASSERT_EQ (*model0.get_constraints (), *model1.get_constraints ());
    7745                 :            :   }
    7746                 :            : 
    7747                 :          2 :   {
    7748                 :          4 :     region_model model0;
    7749                 :          2 :     region_model model1;
    7750                 :            : 
    7751                 :          2 :     ADD_SAT_CONSTRAINT (model1, x, EQ_EXPR, int_42);
    7752                 :          2 :     ASSERT_NE (model0, model1);
    7753                 :          2 :     ASSERT_CONDITION_TRUE (model1, x, EQ_EXPR, int_42);
    7754                 :            : 
    7755                 :          2 :     purge_stats stats;
    7756                 :          2 :     model1.get_constraints ()->purge (purge_one_svalue_id (model1, x), &stats);
    7757                 :            : 
    7758                 :          2 :     ASSERT_CONDITION_UNKNOWN (model1, x, EQ_EXPR, int_42);
    7759                 :            :   }
    7760                 :            : 
    7761                 :          2 :   {
    7762                 :          4 :     region_model model0;
    7763                 :          2 :     region_model model1;
    7764                 :            : 
    7765                 :          2 :     ADD_SAT_CONSTRAINT (model1, x, GE_EXPR, int_0);
    7766                 :          2 :     ADD_SAT_CONSTRAINT (model1, x, LE_EXPR, int_42);
    7767                 :          2 :     ASSERT_NE (model0, model1);
    7768                 :            : 
    7769                 :          2 :     ASSERT_CONDITION_TRUE (model1, x, GE_EXPR, int_0);
    7770                 :          2 :     ASSERT_CONDITION_TRUE (model1, x, LE_EXPR, int_42);
    7771                 :            : 
    7772                 :          2 :     purge_stats stats;
    7773                 :          2 :     model1.get_constraints ()->purge (purge_one_svalue_id (model1, x), &stats);
    7774                 :            : 
    7775                 :          2 :     ASSERT_CONDITION_UNKNOWN (model1, x, GE_EXPR, int_0);
    7776                 :          2 :     ASSERT_CONDITION_UNKNOWN (model1, x, LE_EXPR, int_42);
    7777                 :            :   }
    7778                 :            : 
    7779                 :          2 :   {
    7780                 :          4 :     region_model model0;
    7781                 :          2 :     region_model model1;
    7782                 :            : 
    7783                 :          2 :     ADD_SAT_CONSTRAINT (model1, x, NE_EXPR, int_42);
    7784                 :          2 :     ADD_SAT_CONSTRAINT (model1, y, NE_EXPR, int_0);
    7785                 :          2 :     ASSERT_NE (model0, model1);
    7786                 :          2 :     ASSERT_CONDITION_TRUE (model1, x, NE_EXPR, int_42);
    7787                 :          2 :     ASSERT_CONDITION_TRUE (model1, y, NE_EXPR, int_0);
    7788                 :            : 
    7789                 :          2 :     purge_stats stats;
    7790                 :          2 :     model1.get_constraints ()->purge (purge_one_svalue_id (model1, x), &stats);
    7791                 :          2 :     ASSERT_NE (model0, model1);
    7792                 :            : 
    7793                 :          2 :     ASSERT_CONDITION_UNKNOWN (model1, x, NE_EXPR, int_42);
    7794                 :          2 :     ASSERT_CONDITION_TRUE (model1, y, NE_EXPR, int_0);
    7795                 :            :   }
    7796                 :            : 
    7797                 :          2 :   {
    7798                 :          4 :     region_model model0;
    7799                 :          2 :     region_model model1;
    7800                 :            : 
    7801                 :          2 :     ADD_SAT_CONSTRAINT (model1, x, NE_EXPR, int_42);
    7802                 :          2 :     ADD_SAT_CONSTRAINT (model1, y, NE_EXPR, int_0);
    7803                 :          2 :     ASSERT_NE (model0, model1);
    7804                 :          2 :     ASSERT_CONDITION_TRUE (model1, x, NE_EXPR, int_42);
    7805                 :          2 :     ASSERT_CONDITION_TRUE (model1, y, NE_EXPR, int_0);
    7806                 :            : 
    7807                 :          2 :     purge_stats stats;
    7808                 :          2 :     model1.get_constraints ()->purge (purge_all_svalue_ids (), &stats);
    7809                 :          2 :     ASSERT_CONDITION_UNKNOWN (model1, x, NE_EXPR, int_42);
    7810                 :          2 :     ASSERT_CONDITION_UNKNOWN (model1, y, NE_EXPR, int_0);
    7811                 :            :   }
    7812                 :            : 
    7813                 :          2 : }
    7814                 :            : 
    7815                 :            : /* Test that region_model::purge_unused_svalues works as expected.  */
    7816                 :            : 
    7817                 :            : static void
    7818                 :          2 : test_purge_unused_svalues ()
    7819                 :            : {
    7820                 :          2 :   tree int_42 = build_int_cst (integer_type_node, 42);
    7821                 :          2 :   tree int_0 = build_int_cst (integer_type_node, 0);
    7822                 :          2 :   tree x = build_global_decl ("x", integer_type_node);
    7823                 :          2 :   tree y = build_global_decl ("y", integer_type_node);
    7824                 :            : 
    7825                 :          2 :   test_region_model_context ctxt;
    7826                 :          4 :   region_model model;
    7827                 :          2 :   model.set_to_new_unknown_value (model.get_lvalue (x, &ctxt), TREE_TYPE (x),
    7828                 :          2 :                                   &ctxt);
    7829                 :          2 :   model.set_to_new_unknown_value (model.get_lvalue (x, &ctxt), TREE_TYPE (x),
    7830                 :          2 :                                   &ctxt);
    7831                 :          2 :   model.set_to_new_unknown_value (model.get_lvalue (x, &ctxt), TREE_TYPE (x),
    7832                 :          2 :                                   &ctxt);
    7833                 :          2 :   model.add_constraint (x, NE_EXPR, int_42, &ctxt);
    7834                 :            : 
    7835                 :          2 :   model.set_value (model.get_lvalue (x, &ctxt),
    7836                 :            :                    model.get_rvalue (int_42, &ctxt),
    7837                 :            :                    &ctxt);
    7838                 :          2 :   model.add_constraint (y, GT_EXPR, int_0, &ctxt);
    7839                 :            : 
    7840                 :            :   /* The redundant unknown values should have been purged.  */
    7841                 :          2 :   purge_stats purged;
    7842                 :          2 :   model.purge_unused_svalues (&purged, NULL);
    7843                 :          2 :   ASSERT_EQ (purged.m_num_svalues, 3);
    7844                 :            : 
    7845                 :            :   /* and the redundant constraint on an old, unknown value for x should
    7846                 :            :      have been purged.  */
    7847                 :          2 :   ASSERT_EQ (purged.m_num_equiv_classes, 1);
    7848                 :          2 :   ASSERT_EQ (purged.m_num_constraints, 1);
    7849                 :          2 :   ASSERT_EQ (model.get_constraints ()->m_constraints.length (), 2);
    7850                 :            : 
    7851                 :            :   /* ...but we should still have x == 42.  */
    7852                 :          2 :   ASSERT_EQ (model.eval_condition (x, EQ_EXPR, int_42, &ctxt),
    7853                 :            :              tristate::TS_TRUE);
    7854                 :            : 
    7855                 :            :   /* ...and we should still have the constraint on y.  */
    7856                 :          2 :   ASSERT_EQ (model.eval_condition (y, GT_EXPR, int_0, &ctxt),
    7857                 :            :              tristate::TS_TRUE);
    7858                 :            : 
    7859                 :          2 :   ASSERT_EQ (ctxt.get_num_diagnostics (), 0);
    7860                 :          2 : }
    7861                 :            : 
    7862                 :            : /* Verify that simple assignments work as expected.  */
    7863                 :            : 
    7864                 :            : static void
    7865                 :          2 : test_assignment ()
    7866                 :            : {
    7867                 :          2 :   tree int_0 = build_int_cst (integer_type_node, 0);
    7868                 :          2 :   tree x = build_global_decl ("x", integer_type_node);
    7869                 :          2 :   tree y = build_global_decl ("y", integer_type_node);
    7870                 :            : 
    7871                 :            :   /* "x == 0", then use of y, then "y = 0;".  */
    7872                 :          2 :   region_model model;
    7873                 :          2 :   ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, int_0);
    7874                 :          2 :   ASSERT_CONDITION_UNKNOWN (model, y, EQ_EXPR, int_0);
    7875                 :          2 :   model.set_value (model.get_lvalue (y, NULL),
    7876                 :            :                    model.get_rvalue (int_0, NULL),
    7877                 :            :                    NULL);
    7878                 :          2 :   ASSERT_CONDITION_TRUE (model, y, EQ_EXPR, int_0);
    7879                 :          2 :   ASSERT_CONDITION_TRUE (model, y, EQ_EXPR, x);
    7880                 :            : 
    7881                 :          2 :   ASSERT_DUMP_EQ (model, true, "y: 0, {x}: unknown, x == y");
    7882                 :          2 : }
    7883                 :            : 
    7884                 :            : /* Verify the details of pushing and popping stack frames.  */
    7885                 :            : 
    7886                 :            : static void
    7887                 :          2 : test_stack_frames ()
    7888                 :            : {
    7889                 :          2 :   tree int_42 = build_int_cst (integer_type_node, 42);
    7890                 :          2 :   tree int_10 = build_int_cst (integer_type_node, 10);
    7891                 :          2 :   tree int_5 = build_int_cst (integer_type_node, 5);
    7892                 :          2 :   tree int_0 = build_int_cst (integer_type_node, 0);
    7893                 :            : 
    7894                 :          2 :   auto_vec <tree> param_types;
    7895                 :          2 :   tree parent_fndecl = make_fndecl (integer_type_node,
    7896                 :            :                                     "parent_fn",
    7897                 :            :                                     param_types);
    7898                 :          2 :   allocate_struct_function (parent_fndecl, true);
    7899                 :            : 
    7900                 :          2 :   tree child_fndecl = make_fndecl (integer_type_node,
    7901                 :            :                                    "child_fn",
    7902                 :            :                                    param_types);
    7903                 :          2 :   allocate_struct_function (child_fndecl, true);
    7904                 :            : 
    7905                 :            :   /* "a" and "b" in the parent frame.  */
    7906                 :          2 :   tree a = build_decl (UNKNOWN_LOCATION, PARM_DECL,
    7907                 :            :                        get_identifier ("a"),
    7908                 :            :                        integer_type_node);
    7909                 :          2 :   tree b = build_decl (UNKNOWN_LOCATION, PARM_DECL,
    7910                 :            :                        get_identifier ("b"),
    7911                 :            :                        integer_type_node);
    7912                 :            :   /* "x" and "y" in a child frame.  */
    7913                 :          2 :   tree x = build_decl (UNKNOWN_LOCATION, PARM_DECL,
    7914                 :            :                        get_identifier ("x"),
    7915                 :            :                        integer_type_node);
    7916                 :          2 :   tree y = build_decl (UNKNOWN_LOCATION, PARM_DECL,
    7917                 :            :                        get_identifier ("y"),
    7918                 :            :                        integer_type_node);
    7919                 :            : 
    7920                 :            :   /* "p" global.  */
    7921                 :          2 :   tree p = build_global_decl ("p", ptr_type_node);
    7922                 :            : 
    7923                 :            :   /* "q" global.  */
    7924                 :          2 :   tree q = build_global_decl ("q", ptr_type_node);
    7925                 :            : 
    7926                 :          4 :   test_region_model_context ctxt;
    7927                 :          4 :   region_model model;
    7928                 :            : 
    7929                 :            :   /* Push stack frame for "parent_fn".  */
    7930                 :          2 :   region_id parent_frame_rid
    7931                 :          2 :     = model.push_frame (DECL_STRUCT_FUNCTION (parent_fndecl), NULL, &ctxt);
    7932                 :          2 :   ASSERT_EQ (model.get_current_frame_id (), parent_frame_rid);
    7933                 :          2 :   region_id a_in_parent_rid = model.get_lvalue (a, &ctxt);
    7934                 :          2 :   model.set_value (a_in_parent_rid, model.get_rvalue (int_42, &ctxt), &ctxt);
    7935                 :          2 :   model.set_to_new_unknown_value (model.get_lvalue (b, &ctxt),
    7936                 :          2 :                                   integer_type_node, &ctxt);
    7937                 :          2 :   model.add_constraint (b, LT_EXPR, int_10, &ctxt);
    7938                 :          2 :   ASSERT_EQ (model.eval_condition (b, LT_EXPR, int_10, &ctxt),
    7939                 :            :              tristate (tristate::TS_TRUE));
    7940                 :            : 
    7941                 :            :   /* Push stack frame for "child_fn".  */
    7942                 :          2 :   region_id child_frame_rid
    7943                 :          2 :     = model.push_frame (DECL_STRUCT_FUNCTION (child_fndecl), NULL, &ctxt);
    7944                 :          2 :   ASSERT_EQ (model.get_current_frame_id (), child_frame_rid);
    7945                 :          2 :   region_id x_in_child_rid = model.get_lvalue (x, &ctxt);
    7946                 :          2 :   model.set_value (x_in_child_rid, model.get_rvalue (int_0, &ctxt), &ctxt);
    7947                 :          2 :   model.set_to_new_unknown_value (model.get_lvalue (y, &ctxt),
    7948                 :          2 :                                   integer_type_node, &ctxt);
    7949                 :          2 :   model.add_constraint (y, NE_EXPR, int_5, &ctxt);
    7950                 :          2 :   ASSERT_EQ (model.eval_condition (y, NE_EXPR, int_5, &ctxt),
    7951                 :            :              tristate (tristate::TS_TRUE));
    7952                 :            : 
    7953                 :            :   /* Point a global pointer at a local in the child frame:  p = &x.