LCOV - code coverage report
Current view: top level - gcc/analyzer - call-summary.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 61.5 % 514 316
Test Date: 2026-05-11 19:44:49 Functions: 61.1 % 18 11
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Classes for working with summaries of function calls.
       2              :    Copyright (C) 2022 David Malcolm <dmalcolm@redhat.com>.
       3              : 
       4              : This file is part of GCC.
       5              : 
       6              : GCC is free software; you can redistribute it and/or modify it
       7              : under the terms of the GNU General Public License as published by
       8              : the Free Software Foundation; either version 3, or (at your option)
       9              : any later version.
      10              : 
      11              : GCC is distributed in the hope that it will be useful, but
      12              : WITHOUT ANY WARRANTY; without even the implied warranty of
      13              : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14              : General Public License for more details.
      15              : 
      16              : You should have received a copy of the GNU General Public License
      17              : along with GCC; see the file COPYING3.  If not see
      18              : <http://www.gnu.org/licenses/>.  */
      19              : 
      20              : #include "analyzer/common.h"
      21              : 
      22              : #include "analyzer/region-model.h"
      23              : #include "analyzer/call-summary.h"
      24              : #include "analyzer/exploded-graph.h"
      25              : 
      26              : #if ENABLE_ANALYZER
      27              : 
      28              : namespace ana {
      29              : 
      30              : /* class call_summary.  */
      31              : 
      32              : const program_state &
      33         1706 : call_summary::get_state () const
      34              : {
      35         1706 :   return m_enode->get_state ();
      36              : }
      37              : 
      38              : tree
      39           62 : call_summary::get_fndecl () const
      40              : {
      41           62 :   return m_enode->get_function ()->decl;
      42              : }
      43              : 
      44              : label_text
      45           62 : call_summary::get_desc () const
      46              : {
      47           62 :   pretty_printer pp;
      48           62 :   pp_format_decoder (&pp) = default_tree_printer;
      49              : 
      50           62 :   get_user_facing_desc (&pp);
      51           62 :   if (flag_analyzer_verbose_edges)
      52            0 :     pp_printf (&pp, " (call summary; EN: %i)", m_enode->m_index);
      53              : 
      54           62 :   return label_text::take (xstrdup (pp_formatted_text (&pp)));
      55           62 : }
      56              : 
      57              : /* Generate a user-facing description of this call summary.c
      58              :    This has various heuristics for distinguishing between different
      59              :    summaries.
      60              :    This will help with debugging, too.  */
      61              : 
      62              : void
      63           62 : call_summary::get_user_facing_desc (pretty_printer *pp) const
      64              : {
      65           62 :   tree fndecl = get_fndecl ();
      66              : 
      67              :   /* If there are multiple summaries, try to use the return value to
      68              :      distinguish between them.  */
      69           62 :   if (m_per_fn_data->m_summaries.length () > 1)
      70              :     {
      71           24 :       if (tree result = DECL_RESULT (fndecl))
      72              :         {
      73           24 :           const region *result_reg
      74           24 :             = get_state ().m_region_model->get_lvalue (result, nullptr);
      75           24 :           const svalue *result_sval
      76           24 :             = get_state ().m_region_model->get_store_value (result_reg, nullptr);
      77           24 :           switch (result_sval->get_kind ())
      78              :             {
      79              :             default:
      80              :               break;
      81            8 :             case SK_REGION:
      82            8 :               {
      83            8 :                 const region_svalue *region_sval
      84            8 :                   = as_a <const region_svalue *> (result_sval);
      85            8 :                 const region *pointee_reg = region_sval->get_pointee ();
      86            8 :                 switch (pointee_reg->get_kind ())
      87              :                   {
      88              :                   default:
      89              :                     break;
      90            8 :                   case RK_HEAP_ALLOCATED:
      91            8 :                     pp_printf (pp,
      92              :                                "when %qE returns pointer"
      93              :                                " to heap-allocated buffer",
      94              :                                fndecl);
      95            8 :                     return;
      96              :                   }
      97              :               }
      98              :               break;
      99            0 :             case SK_CONSTANT:
     100            0 :               {
     101            0 :                 const constant_svalue *constant_sval
     102            0 :                   = as_a <const constant_svalue *> (result_sval);
     103            0 :                 tree cst = constant_sval->get_constant ();
     104            0 :                 if (POINTER_TYPE_P (TREE_TYPE (result))
     105            0 :                     && zerop (cst))
     106            0 :                   pp_printf (pp, "when %qE returns NULL", fndecl);
     107              :                 else
     108            0 :                   pp_printf (pp, "when %qE returns %qE", fndecl, cst);
     109            0 :                 return;
     110              :               }
     111              :             }
     112              :         }
     113              :     }
     114              : 
     115              :   /* Fallback.  */
     116           54 :   pp_printf (pp, "when %qE returns", fndecl);
     117              : }
     118              : 
     119              : /* Dump a multiline representation of this object to PP.  */
     120              : 
     121              : void
     122            0 : call_summary::dump_to_pp (const extrinsic_state &ext_state,
     123              :                           pretty_printer *pp,
     124              :                           bool simple) const
     125              : {
     126            0 :   label_text desc = get_desc ();
     127            0 :   pp_printf (pp, "desc: %qs", desc.get ());
     128            0 :   pp_newline (pp);
     129              : 
     130            0 :   get_state ().dump_to_pp (ext_state, simple, true, pp);
     131            0 : }
     132              : 
     133              : /* Dump a multiline representation of this object to FILE.  */
     134              : 
     135              : void
     136            0 : call_summary::dump (const extrinsic_state &ext_state,
     137              :                     FILE *fp,
     138              :                     bool simple) const
     139              : {
     140            0 :   tree_dump_pretty_printer pp (fp);
     141            0 :   dump_to_pp (ext_state, &pp, simple);
     142            0 : }
     143              : 
     144              : /* Dump a multiline representation of this object to stderr.  */
     145              : 
     146              : DEBUG_FUNCTION void
     147            0 : call_summary::dump (const extrinsic_state &ext_state, bool simple) const
     148              : {
     149            0 :   dump (ext_state, stderr, simple);
     150            0 : }
     151              : 
     152              : /* class call_summary_replay.  */
     153              : 
     154              : /* call_summary_replay's ctor.
     155              :    Populate the cache with params for the summary based on
     156              :    arguments at the caller. */
     157              : 
     158         1658 : call_summary_replay::call_summary_replay (const call_details &cd,
     159              :                                           const function &called_fn,
     160              :                                           call_summary &summary,
     161         1658 :                                           const extrinsic_state &ext_state)
     162         1658 : : m_cd (cd),
     163         1658 :   m_summary (summary),
     164         1658 :   m_ext_state (ext_state)
     165              : {
     166         1658 :   region_model_manager *mgr = cd.get_manager ();
     167              : 
     168              :   // populate params based on args
     169         1658 :   tree fndecl = called_fn.decl;
     170              : 
     171              :   /* Get a frame_region for use with respect to the summary.
     172              :      This will be a top-level frame, since that's what's in
     173              :      the summary.  */
     174         1658 :   const frame_region *summary_frame
     175         1658 :     = mgr->get_frame_region (nullptr, called_fn);
     176              : 
     177         1658 :   unsigned idx = 0;
     178         3018 :   for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
     179         1360 :        iter_parm = DECL_CHAIN (iter_parm), ++idx)
     180              :     {
     181              :       /* If there's a mismatching declaration, the call stmt might
     182              :          not have enough args.  Handle this case by leaving the
     183              :          rest of the params as uninitialized.  */
     184         1360 :       if (idx >= cd.num_args ())
     185              :         break;
     186         1360 :       const svalue *caller_arg_sval = cd.get_arg_svalue (idx);
     187         1360 :       tree parm_lval = iter_parm;
     188         1360 :       if (tree parm_default_ssa = get_ssa_default_def (called_fn, iter_parm))
     189         1349 :         parm_lval = parm_default_ssa;
     190         1360 :       const region *summary_parm_reg
     191         1360 :         = summary_frame->get_region_for_local (mgr, parm_lval, cd.get_ctxt ());
     192         1360 :       const svalue *summary_initial_parm_reg
     193         1360 :         = mgr->get_or_create_initial_value (summary_parm_reg);
     194         1360 :       add_svalue_mapping (summary_initial_parm_reg, caller_arg_sval);
     195              :     }
     196              : 
     197              :   /* Handle any variadic args.  */
     198              :   unsigned va_arg_idx = 0;
     199         1664 :   for (; idx < cd.num_args (); idx++, va_arg_idx++)
     200              :     {
     201            6 :       const svalue *caller_arg_sval = cd.get_arg_svalue (idx);
     202            6 :       const region *summary_var_arg_reg
     203            6 :         = mgr->get_var_arg_region (summary_frame, va_arg_idx);
     204            6 :       const svalue *summary_initial_var_arg_reg
     205            6 :         = mgr->get_or_create_initial_value (summary_var_arg_reg);
     206            6 :       add_svalue_mapping (summary_initial_var_arg_reg, caller_arg_sval);
     207              :     }
     208         1658 : }
     209              : 
     210              : /* Try to convert SUMMARY_SVAL in the summary to a corresponding svalue
     211              :    in the caller, caching the result.
     212              : 
     213              :    Return nullptr if the conversion is not possible.  */
     214              : 
     215              : const svalue *
     216        48687 : call_summary_replay::convert_svalue_from_summary (const svalue *summary_sval)
     217              : {
     218        48687 :   gcc_assert (summary_sval);
     219              : 
     220        97374 :   if (const svalue **slot
     221        48687 :         = m_map_svalue_from_summary_to_caller.get (summary_sval))
     222        28568 :     return *slot;
     223              : 
     224        20119 :   const svalue *caller_sval = convert_svalue_from_summary_1 (summary_sval);
     225              : 
     226        20119 :   if (caller_sval)
     227        19693 :     if (summary_sval->get_type () && caller_sval->get_type ())
     228        18605 :       gcc_assert (types_compatible_p (summary_sval->get_type (),
     229              :                                       caller_sval->get_type ()));
     230              : 
     231              :   /* Add to cache.  */
     232        20119 :   add_svalue_mapping (summary_sval, caller_sval);
     233              : 
     234        20119 :   return caller_sval;
     235              : }
     236              : 
     237              : /* Implementation of call_summary_replay::convert_svalue_from_summary.  */
     238              : 
     239              : const svalue *
     240        20119 : call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval)
     241              : {
     242        20119 :   gcc_assert (summary_sval);
     243              : 
     244        20119 :   switch (summary_sval->get_kind ())
     245              :     {
     246            0 :     default:
     247            0 :       gcc_unreachable ();
     248         2206 :     case SK_REGION:
     249         2206 :       {
     250         2206 :         const region_svalue *region_summary_sval
     251         2206 :           = as_a <const region_svalue *> (summary_sval);
     252         2206 :         const region *summary_reg = region_summary_sval->get_pointee ();
     253         2206 :         const region *caller_reg = convert_region_from_summary (summary_reg);
     254         2206 :         if (!caller_reg)
     255              :           return nullptr;
     256         2206 :         region_model_manager *mgr = get_manager ();
     257         2206 :         const svalue *caller_ptr
     258         2206 :           = mgr->get_ptr_svalue (summary_sval->get_type (),
     259              :                                  caller_reg);
     260         2206 :         return caller_ptr;
     261              :       }
     262              :       break;
     263              : 
     264              :     case SK_CONSTANT:
     265              :     case SK_PLACEHOLDER:
     266              :     case SK_POISONED:
     267              :     case SK_UNKNOWN:
     268              :       return summary_sval;
     269              : 
     270              :     case SK_SETJMP:
     271              :       return nullptr; // TODO
     272              : 
     273         4134 :     case SK_INITIAL:
     274         4134 :       {
     275         4134 :         const initial_svalue *initial_summary_sval
     276         4134 :           = as_a <const initial_svalue *> (summary_sval);
     277              :         /* Params should already be in the cache, courtesy of the ctor.  */
     278         4134 :         gcc_assert (!initial_summary_sval->initial_value_of_param_p ());
     279              : 
     280              :         /* Initial value of region within the summary is the value of the
     281              :            region at the point of the call.  */
     282         4134 :         const region *summary_reg = initial_summary_sval->get_region ();
     283         4134 :         const region *caller_reg = convert_region_from_summary (summary_reg);
     284         4134 :         if (!caller_reg)
     285              :           return nullptr;
     286         4122 :         const svalue *caller_sval
     287         4122 :           = m_cd.get_model ()->get_store_value (caller_reg, m_cd.get_ctxt ());
     288         4122 :         return caller_sval;
     289              :       }
     290          101 :       break;
     291          101 :     case SK_UNARYOP:
     292          101 :       {
     293          101 :         const unaryop_svalue *unaryop_summary_sval
     294          101 :           = as_a <const unaryop_svalue *> (summary_sval);
     295          101 :         const svalue *summary_arg = unaryop_summary_sval->get_arg ();
     296          101 :         const svalue *caller_arg = convert_svalue_from_summary (summary_arg);
     297          101 :         if (!caller_arg)
     298              :           return nullptr;
     299          101 :         region_model_manager *mgr = get_manager ();
     300          101 :         return mgr->get_or_create_unaryop (summary_sval->get_type (),
     301              :                                            unaryop_summary_sval->get_op (),
     302          101 :                                            caller_arg);
     303              :       }
     304         2249 :       break;
     305         2249 :     case SK_BINOP:
     306         2249 :       {
     307         2249 :         const binop_svalue *binop_summary_sval
     308         2249 :           = as_a <const binop_svalue *> (summary_sval);
     309         2249 :         const svalue *summary_arg0 = binop_summary_sval->get_arg0 ();
     310         2249 :         const svalue *caller_arg0 = convert_svalue_from_summary (summary_arg0);
     311         2249 :         if (!caller_arg0)
     312              :           return nullptr;
     313         2249 :         const svalue *summary_arg1 = binop_summary_sval->get_arg1 ();
     314         2249 :         const svalue *caller_arg1 = convert_svalue_from_summary (summary_arg1);
     315         2249 :         if (!caller_arg1)
     316              :           return nullptr;
     317         2249 :         region_model_manager *mgr = get_manager ();
     318         2249 :         return mgr->get_or_create_binop (summary_sval->get_type (),
     319              :                                          binop_summary_sval->get_op (),
     320              :                                          caller_arg0,
     321         2249 :                                          caller_arg1);
     322              :       }
     323            0 :       break;
     324            0 :     case SK_SUB:
     325            0 :       {
     326            0 :         const sub_svalue *sub_summary_sval
     327            0 :           = as_a <const sub_svalue *> (summary_sval);
     328            0 :         region_model_manager *mgr = get_manager ();
     329            0 :         const svalue *summary_parent_sval = sub_summary_sval->get_parent ();
     330            0 :         if (!summary_parent_sval)
     331              :           return nullptr;
     332            0 :         const region *summary_subregion = sub_summary_sval->get_subregion ();
     333            0 :         if (!summary_subregion)
     334              :           return nullptr;
     335            0 :         return mgr->get_or_create_sub_svalue (summary_sval->get_type (),
     336              :                                               summary_parent_sval,
     337            0 :                                               summary_subregion);
     338              :       }
     339           42 :       break;
     340           42 :     case SK_REPEATED:
     341           42 :       {
     342           42 :         const repeated_svalue *repeated_summary_sval
     343           42 :           = as_a <const repeated_svalue *> (summary_sval);
     344           42 :         const svalue *summary_outer_size
     345           42 :           = repeated_summary_sval->get_outer_size ();
     346           42 :         const svalue *caller_outer_size
     347           42 :           = convert_svalue_from_summary (summary_outer_size);
     348           42 :         if (!caller_outer_size)
     349              :           return nullptr;
     350           42 :         const svalue *summary_inner_sval
     351           42 :           = repeated_summary_sval->get_inner_svalue ();
     352           42 :         const svalue *caller_inner_sval
     353           42 :           = convert_svalue_from_summary (summary_inner_sval);
     354           42 :         if (!caller_inner_sval)
     355              :           return nullptr;
     356           42 :         region_model_manager *mgr = get_manager ();
     357           42 :         return mgr->get_or_create_repeated_svalue (summary_sval->get_type (),
     358              :                                                    caller_outer_size,
     359           42 :                                                    caller_inner_sval);
     360              :       }
     361            0 :       break;
     362            0 :     case SK_BITS_WITHIN:
     363            0 :       {
     364            0 :         const bits_within_svalue *bits_within_summary_sval
     365            0 :           = as_a <const bits_within_svalue *> (summary_sval);
     366            0 :         const bit_range &bits = bits_within_summary_sval->get_bits ();
     367            0 :         const svalue *summary_inner_sval
     368            0 :           = bits_within_summary_sval->get_inner_svalue ();
     369            0 :         const svalue *caller_inner_sval
     370            0 :           = convert_svalue_from_summary (summary_inner_sval);
     371            0 :         if (!caller_inner_sval)
     372              :           return nullptr;
     373            0 :         region_model_manager *mgr = get_manager ();
     374            0 :         return mgr->get_or_create_bits_within (summary_sval->get_type (),
     375              :                                                bits,
     376            0 :                                                caller_inner_sval);
     377              :       }
     378            0 :       break;
     379            0 :     case SK_UNMERGEABLE:
     380            0 :       {
     381            0 :         const unmergeable_svalue *unmergeable_summary_sval
     382            0 :           = as_a <const unmergeable_svalue *> (summary_sval);
     383            0 :         const svalue *summary_arg_sval = unmergeable_summary_sval->get_arg ();
     384            0 :         const svalue *caller_arg_sval
     385            0 :           = convert_svalue_from_summary (summary_arg_sval);
     386            0 :         if (!caller_arg_sval)
     387              :           return nullptr;
     388            0 :         region_model_manager *mgr = get_manager ();
     389            0 :         return mgr->get_or_create_unmergeable (caller_arg_sval);
     390              :       }
     391          454 :       break;
     392          454 :     case SK_WIDENING:
     393          454 :       {
     394          454 :         const widening_svalue *widening_summary_sval
     395          454 :           = as_a <const widening_svalue *> (summary_sval);
     396          454 :         const supernode *snode = widening_summary_sval->get_snode ();
     397          454 :         const svalue *summary_base_sval
     398          454 :           = widening_summary_sval->get_base_svalue ();
     399          454 :         const svalue *caller_base_sval
     400          454 :           = convert_svalue_from_summary (summary_base_sval);
     401          908 :         if (!(caller_base_sval
     402          454 :               && caller_base_sval->can_have_associated_state_p ()))
     403          414 :           return nullptr;
     404           40 :         const svalue *summary_iter_sval
     405           40 :           = widening_summary_sval->get_iter_svalue ();
     406           40 :         const svalue *caller_iter_sval
     407           40 :           = convert_svalue_from_summary (summary_iter_sval);
     408           80 :         if (!(caller_iter_sval
     409           40 :               && caller_iter_sval->can_have_associated_state_p ()))
     410            0 :           return nullptr;
     411           40 :         region_model_manager *mgr = get_manager ();
     412           40 :         return mgr->get_or_create_widening_svalue
     413           40 :           (summary_iter_sval->get_type (),
     414              :            snode,
     415              :            caller_base_sval,
     416           40 :            caller_iter_sval);
     417              :       }
     418          229 :       break;
     419          229 :     case SK_COMPOUND:
     420          229 :       {
     421          229 :         const compound_svalue *compound_summary_sval
     422          229 :           = as_a <const compound_svalue *> (summary_sval);
     423          229 :         region_model_manager *mgr = get_manager ();
     424          229 :         concrete_binding_map caller_map;
     425          744 :         for (auto iter_summary : *compound_summary_sval)
     426              :           {
     427              :             /* No remapping is needed for concrete binding keys.  */
     428          515 :             const bit_range &summary_bits = iter_summary.first;
     429          515 :             const svalue *bound_summary_sval = iter_summary.second;
     430          515 :             const svalue *caller_sval
     431          515 :               = convert_svalue_from_summary (bound_summary_sval);
     432          515 :             if (!caller_sval)
     433            8 :               caller_sval = mgr->get_or_create_unknown_svalue (NULL_TREE);
     434              : 
     435         1030 :             if (const compound_svalue *inner_compound_sval
     436          515 :                 = caller_sval->dyn_cast_compound_svalue ())
     437              :               {
     438            0 :                 const bit_range &outer_key = summary_bits;
     439            0 :                 for (auto inner_kv : *inner_compound_sval)
     440              :                   {
     441              :                     // These should already be mapped to the caller.
     442            0 :                     const bit_range &inner_key = inner_kv.first;
     443            0 :                     const svalue *inner_sval = inner_kv.second;
     444            0 :                     bit_offset_t effective_start
     445            0 :                       = (inner_key.get_start_bit_offset ()
     446            0 :                          + outer_key.get_start_bit_offset ());
     447            0 :                     const bit_range effective_concrete_key
     448              :                       (effective_start,
     449            0 :                        summary_bits.m_size_in_bits);
     450            0 :                     caller_map.insert (effective_concrete_key, inner_sval);
     451              :                   }
     452              :               }
     453              :             else
     454          515 :               caller_map.insert (summary_bits, caller_sval);
     455              :           }
     456          229 :         return mgr->get_or_create_compound_svalue (summary_sval->get_type (),
     457              :                                                    std::move (caller_map));
     458          229 :       }
     459           26 :       break;
     460           26 :     case SK_CONJURED:
     461           26 :       {
     462           26 :         region_model_manager *mgr = get_manager ();
     463           26 :         return mgr->get_or_create_unknown_svalue (summary_sval->get_type ());
     464              :       }
     465            8 :       break;
     466            8 :     case SK_ASM_OUTPUT:
     467            8 :       {
     468            8 :         const asm_output_svalue *asm_output_summary_sval
     469            8 :           = as_a <const asm_output_svalue *> (summary_sval);
     470            8 :         const char *asm_string = asm_output_summary_sval->get_asm_string ();
     471            8 :         unsigned output_idx = asm_output_summary_sval->get_output_idx ();
     472            8 :         unsigned num_inputs = asm_output_summary_sval->get_num_inputs ();
     473            8 :         unsigned num_outputs = asm_output_summary_sval->get_num_outputs ();
     474            8 :         auto_vec<const svalue *> inputs (num_inputs);
     475            8 :         for (unsigned idx = 0; idx < num_inputs; idx++)
     476              :           {
     477            0 :             const svalue *summary_input
     478            0 :               = asm_output_summary_sval->get_input (idx);
     479            0 :             const svalue *caller_input
     480            0 :               = convert_svalue_from_summary (summary_input);
     481            0 :             if (!caller_input)
     482            0 :               return nullptr;
     483            0 :             inputs.safe_push (caller_input);
     484              :           }
     485            8 :         region_model_manager *mgr = get_manager ();
     486            8 :         return mgr->get_or_create_asm_output_svalue (summary_sval->get_type (),
     487              :                                                      asm_string,
     488              :                                                      output_idx,
     489              :                                                      num_outputs,
     490            8 :                                                      inputs);
     491            8 :       }
     492            2 :       break;
     493            2 :     case SK_CONST_FN_RESULT:
     494            2 :       {
     495            2 :         const const_fn_result_svalue *const_fn_result_summary_sval
     496            2 :           = as_a <const const_fn_result_svalue *> (summary_sval);
     497            2 :         tree fndecl = const_fn_result_summary_sval->get_fndecl ();
     498            2 :         unsigned num_inputs = const_fn_result_summary_sval->get_num_inputs ();
     499            2 :         auto_vec<const svalue *> inputs (num_inputs);
     500            4 :         for (unsigned idx = 0; idx < num_inputs; idx++)
     501              :           {
     502            2 :             const svalue *summary_input
     503            2 :               = const_fn_result_summary_sval->get_input (idx);
     504            2 :             const svalue *caller_input
     505            2 :               = convert_svalue_from_summary (summary_input);
     506            2 :             if (!caller_input)
     507            0 :               return nullptr;
     508            2 :             inputs.safe_push (caller_input);
     509              :           }
     510            2 :         region_model_manager *mgr = get_manager ();
     511            2 :         return mgr->get_or_create_const_fn_result_svalue
     512            2 :           (summary_sval->get_type (),
     513              :            fndecl,
     514            2 :            inputs);
     515            2 :       }
     516              :       break;
     517              :     }
     518              : }
     519              : 
     520              : /* Try to convert SUMMARY_REG in the summary to a corresponding region
     521              :    in the caller, caching the result.
     522              : 
     523              :    Return nullptr if the conversion is not possible.  */
     524              : 
     525              : const region *
     526        23086 : call_summary_replay::convert_region_from_summary (const region *summary_reg)
     527              : {
     528        23086 :   gcc_assert (summary_reg);
     529              : 
     530        46172 :   if (const region **slot
     531        23086 :         = m_map_region_from_summary_to_caller.get (summary_reg))
     532         7919 :     return *slot;
     533              : 
     534        15167 :   const region *caller_reg = convert_region_from_summary_1 (summary_reg);
     535              : 
     536        15167 :   if (caller_reg)
     537        14903 :     if (summary_reg->get_type () && caller_reg->get_type ())
     538        12966 :       gcc_assert (types_compatible_p (summary_reg->get_type (),
     539              :                                       caller_reg->get_type ()));
     540              : 
     541              :   /* Add to cache.  */
     542        15167 :   add_region_mapping (summary_reg, caller_reg);
     543              : 
     544        15167 :   return caller_reg;
     545              : }
     546              : 
     547              : /* Implementation of call_summary_replay::convert_region_from_summary.  */
     548              : 
     549              : const region *
     550        15167 : call_summary_replay::convert_region_from_summary_1 (const region *summary_reg)
     551              : {
     552        15167 :   gcc_assert (summary_reg);
     553              : 
     554        15167 :   region_model_manager *mgr = get_manager ();
     555        15167 :   switch (summary_reg->get_kind ())
     556              :     {
     557            0 :     default:
     558            0 :       gcc_unreachable ();
     559              :       /* Top-level regions.  */
     560            0 :     case RK_FRAME:
     561            0 :     case RK_GLOBALS:
     562            0 :     case RK_CODE:
     563            0 :     case RK_STACK:
     564            0 :     case RK_HEAP:
     565            0 :     case RK_THREAD_LOCAL:
     566            0 :     case RK_ROOT:
     567              :       /* These should never be pointed to by a region_svalue.  */
     568            0 :       gcc_unreachable ();
     569              : 
     570              :     case RK_FUNCTION:
     571              :     case RK_LABEL:
     572              :     case RK_STRING:
     573              :     case RK_ERRNO:
     574              :     case RK_UNKNOWN:
     575              :     case RK_PRIVATE:
     576              :       /* We can reuse these regions directly.  */
     577              :       return summary_reg;
     578              : 
     579         2715 :     case RK_SYMBOLIC:
     580         2715 :       {
     581         2715 :         const symbolic_region *summary_symbolic_reg
     582         2715 :           = as_a <const symbolic_region *> (summary_reg);
     583         2715 :         const svalue *summary_ptr_sval = summary_symbolic_reg->get_pointer ();
     584         2715 :         const svalue *caller_ptr_sval
     585         2715 :           = convert_svalue_from_summary (summary_ptr_sval);
     586         2715 :         if (!caller_ptr_sval)
     587              :           return nullptr;
     588         2715 :         const region *caller_reg
     589         2715 :           = get_caller_model ()->deref_rvalue (caller_ptr_sval,
     590              :                                                NULL_TREE,
     591              :                                                get_ctxt ());
     592         2715 :         caller_reg = mgr->get_cast_region (caller_reg,
     593              :                                            summary_reg->get_type ());
     594         2715 :         return caller_reg;
     595              :       }
     596         8175 :       break;
     597              : 
     598         8175 :     case RK_DECL:
     599         8175 :       {
     600         8175 :         const decl_region *summary_decl_reg
     601         8175 :           = as_a <const decl_region *> (summary_reg);
     602         8175 :         tree decl = summary_decl_reg->get_decl ();
     603         8175 :         switch (TREE_CODE (decl))
     604              :           {
     605            0 :           default:
     606            0 :             gcc_unreachable ();
     607              :           case SSA_NAME:
     608              :             /* We don't care about writes to locals within
     609              :                the summary.  */
     610              :             return nullptr;
     611         7018 :           case VAR_DECL:
     612              :             /* We don't care about writes to locals within
     613              :                the summary.  */
     614         7018 :             if (is_global_var (decl))
     615              :               /* If it's a global, we can reuse the region directly.  */
     616              :               return summary_reg;
     617              :             else
     618              :               /* Otherwise, we don't care about locals.  */
     619              :               return nullptr;
     620          938 :           case RESULT_DECL:
     621          938 :             return m_cd.get_lhs_region ();
     622              :           case PARM_DECL:
     623              :             /* Writes (by value) to parms should be visible to the caller.  */
     624              :             return nullptr;
     625              :           }
     626              :       }
     627         1026 :       break;
     628         1026 :     case RK_FIELD:
     629         1026 :       {
     630         1026 :         const field_region *summary_field_reg
     631         1026 :           = as_a <const field_region *> (summary_reg);
     632         1026 :         const region *summary_parent_reg = summary_reg->get_parent_region ();
     633         1026 :         const region *caller_parent_reg
     634         1026 :           = convert_region_from_summary (summary_parent_reg);
     635         1026 :         if (!caller_parent_reg)
     636              :           return nullptr;
     637         1018 :         tree field = summary_field_reg->get_field ();
     638         1018 :         return mgr->get_field_region (caller_parent_reg, field);
     639              :       }
     640           26 :       break;
     641           26 :     case RK_ELEMENT:
     642           26 :       {
     643           26 :         const element_region *summary_element_reg
     644           26 :           = as_a <const element_region *> (summary_reg);
     645           26 :         const region *summary_parent_reg = summary_reg->get_parent_region ();
     646           26 :         const region *caller_parent_reg
     647           26 :           = convert_region_from_summary (summary_parent_reg);
     648           26 :         if (!caller_parent_reg)
     649              :           return nullptr;
     650           16 :         const svalue *summary_index = summary_element_reg->get_index ();
     651           16 :         const svalue *caller_index
     652           16 :           = convert_svalue_from_summary (summary_index);
     653           16 :         if (!caller_index)
     654              :           return nullptr;
     655           16 :         return mgr->get_element_region (caller_parent_reg,
     656              :                                         summary_reg->get_type (),
     657           16 :                                         caller_index);
     658              :       }
     659          584 :       break;
     660          584 :     case RK_OFFSET:
     661          584 :       {
     662          584 :         const offset_region *summary_offset_reg
     663          584 :           = as_a <const offset_region *> (summary_reg);
     664          584 :         const region *summary_parent_reg = summary_reg->get_parent_region ();
     665          584 :         const region *caller_parent_reg
     666          584 :           = convert_region_from_summary (summary_parent_reg);
     667          584 :         if (!caller_parent_reg)
     668              :           return nullptr;
     669          584 :         const svalue *summary_byte_offset
     670          584 :           = summary_offset_reg->get_byte_offset ();
     671          584 :         const svalue *caller_byte_offset
     672          584 :           = convert_svalue_from_summary (summary_byte_offset);
     673          584 :         if (!caller_byte_offset)
     674              :           return nullptr;
     675          584 :         return mgr->get_offset_region (caller_parent_reg,
     676              :                                        summary_reg->get_type (),
     677          584 :                                        caller_byte_offset);
     678              :       }
     679            0 :       break;
     680            0 :     case RK_SIZED:
     681            0 :       {
     682            0 :         const sized_region *summary_sized_reg
     683            0 :           = as_a <const sized_region *> (summary_reg);
     684            0 :         const region *summary_parent_reg = summary_reg->get_parent_region ();
     685            0 :         const region *caller_parent_reg
     686            0 :           = convert_region_from_summary (summary_parent_reg);
     687            0 :         if (!caller_parent_reg)
     688              :           return nullptr;
     689            0 :         const svalue *summary_byte_size
     690            0 :           = summary_sized_reg->get_byte_size_sval (mgr);
     691            0 :         const svalue *caller_byte_size
     692            0 :           = convert_svalue_from_summary (summary_byte_size);
     693            0 :         if (!caller_byte_size)
     694              :           return nullptr;
     695            0 :         return mgr->get_sized_region (caller_parent_reg,
     696              :                                        summary_reg->get_type (),
     697            0 :                                        caller_byte_size);
     698              :       }
     699            0 :       break;
     700            0 :     case RK_CAST:
     701            0 :       {
     702            0 :         const region *summary_parent_reg = summary_reg->get_parent_region ();
     703            0 :         const region *caller_parent_reg
     704            0 :           = convert_region_from_summary (summary_parent_reg);
     705            0 :         if (!caller_parent_reg)
     706              :           return nullptr;
     707            0 :         return mgr->get_cast_region (caller_parent_reg,
     708            0 :                                      summary_reg->get_type ());
     709              :       }
     710         1937 :       break;
     711         1937 :     case RK_HEAP_ALLOCATED:
     712         1937 :       {
     713              :         /* If we have a heap-allocated region in the summary, then
     714              :            it was allocated within the callee.
     715              :            Create a new heap-allocated region to summarize this.  */
     716         1937 :         auto_bitmap heap_regs_in_use;
     717         1937 :         get_caller_model ()->get_referenced_base_regions (heap_regs_in_use);
     718         1937 :         return mgr->get_or_create_region_for_heap_alloc (heap_regs_in_use);
     719         1937 :       }
     720              :       break;
     721              :     case RK_ALLOCA:
     722              :       return nullptr;
     723            0 :     case RK_BIT_RANGE:
     724            0 :       {
     725            0 :         const bit_range_region *summary_bit_range_reg
     726            0 :           = as_a <const bit_range_region *> (summary_reg);
     727            0 :         const region *summary_parent_reg = summary_reg->get_parent_region ();
     728            0 :         const region *caller_parent_reg
     729            0 :           = convert_region_from_summary (summary_parent_reg);
     730            0 :         if (!caller_parent_reg)
     731              :           return nullptr;
     732            0 :         const bit_range &bits = summary_bit_range_reg->get_bits ();
     733            0 :         return mgr->get_bit_range (caller_parent_reg,
     734              :                                    summary_reg->get_type (),
     735            0 :                                    bits);
     736              :       }
     737              :       break;
     738              :     case RK_VAR_ARG:
     739              :       return nullptr;
     740              :     }
     741              : }
     742              : 
     743              : /* Try to convert SUMMARY_KEY in the summary to a corresponding binding key
     744              :    in the caller.
     745              : 
     746              :    Return nullptr if the conversion is not possible.  */
     747              : 
     748              : const binding_key *
     749            0 : call_summary_replay::convert_key_from_summary (const binding_key *summary_key)
     750              : {
     751            0 :   if (summary_key->concrete_p ())
     752              :     return summary_key;
     753              : 
     754            0 :   const symbolic_binding *symbolic_key = (const symbolic_binding *)summary_key;
     755            0 :   const region *summary_reg = symbolic_key->get_region ();
     756            0 :   const region *caller_reg = convert_region_from_summary (summary_reg);
     757            0 :   if (!caller_reg)
     758              :     return nullptr;
     759            0 :   region_model_manager *mgr = get_manager ();
     760            0 :   store_manager *store_mgr = mgr->get_store_manager ();
     761            0 :   return store_mgr->get_symbolic_binding (caller_reg);
     762              : }
     763              : 
     764              : /* Record that SUMMARY_SVAL maps to CALLER_SVAL for this replay.  */
     765              : 
     766              : void
     767        21485 : call_summary_replay::add_svalue_mapping (const svalue *summary_sval,
     768              :                                          const svalue *caller_sval)
     769              : {
     770        21485 :   gcc_assert (summary_sval);
     771              :   // CALLER_SVAL can be nullptr
     772        21485 :   m_map_svalue_from_summary_to_caller.put (summary_sval, caller_sval);
     773        21485 : }
     774              : 
     775              : /* Record that SUMMARY_REG maps to CALLER_REG for this replay.  */
     776              : 
     777              : void
     778        15167 : call_summary_replay::add_region_mapping (const region *summary_reg,
     779              :                                          const region *caller_reg)
     780              : {
     781        15167 :   gcc_assert (summary_reg);
     782              :   // CALLER_REG can be nullptr
     783        15167 :   m_map_region_from_summary_to_caller.put (summary_reg, caller_reg);
     784        15167 : }
     785              : 
     786              : /* Dump a multiline representation of this object to PP.  */
     787              : 
     788              : void
     789            0 : call_summary_replay::dump_to_pp (pretty_printer *pp, bool simple) const
     790              : {
     791            0 :   pp_newline (pp);
     792            0 :   pp_string (pp, "CALL DETAILS:");
     793            0 :   pp_newline (pp);
     794            0 :   m_cd.dump_to_pp (pp, simple);
     795              : 
     796            0 :   pp_newline (pp);
     797            0 :   pp_string (pp, "CALLEE SUMMARY:");
     798            0 :   pp_newline (pp);
     799            0 :   m_summary.dump_to_pp (m_ext_state, pp, simple);
     800              : 
     801              :   /* Current state of caller (could be in mid-update).  */
     802            0 :   pp_newline (pp);
     803            0 :   pp_string (pp, "CALLER:");
     804            0 :   pp_newline (pp);
     805            0 :   m_cd.get_model ()->dump_to_pp (pp, simple, true);
     806              : 
     807            0 :   pp_newline (pp);
     808            0 :   pp_string (pp, "REPLAY STATE:");
     809            0 :   pp_newline (pp);
     810            0 :   pp_string (pp, "svalue mappings from summary to caller:");
     811            0 :   pp_newline (pp);
     812            0 :   auto_vec <const svalue *> summary_svals;
     813            0 :   for (auto kv : m_map_svalue_from_summary_to_caller)
     814            0 :     summary_svals.safe_push (kv.first);
     815            0 :   summary_svals.qsort (svalue::cmp_ptr_ptr);
     816            0 :   for (auto summary_sval : summary_svals)
     817              :     {
     818            0 :       pp_string (pp, "sval in summary: ");
     819            0 :       summary_sval->dump_to_pp (pp, simple);
     820            0 :       pp_newline (pp);
     821              : 
     822            0 :       const svalue *caller_sval
     823              :         = *((const_cast<svalue_map_t &>
     824            0 :              (m_map_svalue_from_summary_to_caller)).get (summary_sval));
     825            0 :       pp_string (pp, " sval in caller: ");
     826            0 :       caller_sval->dump_to_pp (pp, simple);
     827            0 :       pp_newline (pp);
     828              :     }
     829              : 
     830            0 :   pp_newline (pp);
     831            0 :   pp_string (pp, "region mappings from summary to caller:");
     832            0 :   pp_newline (pp);
     833            0 :   auto_vec <const region *> summary_regs;
     834            0 :   for (auto kv : m_map_region_from_summary_to_caller)
     835            0 :     summary_regs.safe_push (kv.first);
     836            0 :   summary_regs.qsort (region::cmp_ptr_ptr);
     837            0 :   for (auto summary_reg : summary_regs)
     838              :     {
     839            0 :       pp_string (pp, "reg in summary: ");
     840            0 :       if (summary_reg)
     841            0 :         summary_reg->dump_to_pp (pp, simple);
     842              :       else
     843            0 :         pp_string (pp, "(null)");
     844            0 :       pp_newline (pp);
     845              : 
     846            0 :       const region *caller_reg
     847              :         = *((const_cast<region_map_t &>
     848            0 :              (m_map_region_from_summary_to_caller)).get (summary_reg));
     849            0 :       pp_string (pp, " reg in caller: ");
     850            0 :       if (caller_reg)
     851            0 :         caller_reg->dump_to_pp (pp, simple);
     852              :       else
     853            0 :         pp_string (pp, "(null)");
     854            0 :       pp_newline (pp);
     855              :     }
     856            0 : }
     857              : 
     858              : /* Dump a multiline representation of this object to FILE.  */
     859              : 
     860              : void
     861            0 : call_summary_replay::dump (FILE *fp, bool simple) const
     862              : {
     863            0 :   tree_dump_pretty_printer pp (fp);
     864            0 :   dump_to_pp (&pp, simple);
     865            0 : }
     866              : 
     867              : /* Dump a multiline representation of this object to stderr.  */
     868              : 
     869              : DEBUG_FUNCTION void
     870            0 : call_summary_replay::dump (bool simple) const
     871              : {
     872            0 :   dump (stderr, simple);
     873            0 : }
     874              : 
     875              : } // namespace ana
     876              : 
     877              : #endif /* #if ENABLE_ANALYZER */
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.