LCOV - code coverage report
Current view: top level - gcc/analyzer - call-summary.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 61.5 % 524 322
Test Date: 2026-02-28 14:20:25 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         1677 : call_summary::get_state () const
      34              : {
      35         1677 :   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         1629 : call_summary_replay::call_summary_replay (const call_details &cd,
     159              :                                           const function &called_fn,
     160              :                                           call_summary &summary,
     161         1629 :                                           const extrinsic_state &ext_state)
     162         1629 : : m_cd (cd),
     163         1629 :   m_summary (summary),
     164         1629 :   m_ext_state (ext_state)
     165              : {
     166         1629 :   region_model_manager *mgr = cd.get_manager ();
     167              : 
     168              :   // populate params based on args
     169         1629 :   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         1629 :   const frame_region *summary_frame
     175         1629 :     = mgr->get_frame_region (nullptr, called_fn);
     176              : 
     177         1629 :   unsigned idx = 0;
     178         2959 :   for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
     179         1330 :        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         1330 :       if (idx >= cd.num_args ())
     185              :         break;
     186         1330 :       const svalue *caller_arg_sval = cd.get_arg_svalue (idx);
     187         1330 :       tree parm_lval = iter_parm;
     188         1330 :       if (tree parm_default_ssa = get_ssa_default_def (called_fn, iter_parm))
     189         1319 :         parm_lval = parm_default_ssa;
     190         1330 :       const region *summary_parm_reg
     191         1330 :         = summary_frame->get_region_for_local (mgr, parm_lval, cd.get_ctxt ());
     192         1330 :       const svalue *summary_initial_parm_reg
     193         1330 :         = mgr->get_or_create_initial_value (summary_parm_reg);
     194         1330 :       add_svalue_mapping (summary_initial_parm_reg, caller_arg_sval);
     195              :     }
     196              : 
     197              :   /* Handle any variadic args.  */
     198              :   unsigned va_arg_idx = 0;
     199         1635 :   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         1629 : }
     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        48234 : call_summary_replay::convert_svalue_from_summary (const svalue *summary_sval)
     217              : {
     218        48234 :   gcc_assert (summary_sval);
     219              : 
     220        96468 :   if (const svalue **slot
     221        48234 :         = m_map_svalue_from_summary_to_caller.get (summary_sval))
     222        28270 :     return *slot;
     223              : 
     224        19964 :   const svalue *caller_sval = convert_svalue_from_summary_1 (summary_sval);
     225              : 
     226        19964 :   if (caller_sval)
     227        19538 :     if (summary_sval->get_type () && caller_sval->get_type ())
     228        18474 :       gcc_assert (types_compatible_p (summary_sval->get_type (),
     229              :                                       caller_sval->get_type ()));
     230              : 
     231              :   /* Add to cache.  */
     232        19964 :   add_svalue_mapping (summary_sval, caller_sval);
     233              : 
     234        19964 :   return caller_sval;
     235              : }
     236              : 
     237              : /* Implementation of call_summary_replay::convert_svalue_from_summary.  */
     238              : 
     239              : const svalue *
     240        19964 : call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval)
     241              : {
     242        19964 :   gcc_assert (summary_sval);
     243              : 
     244        19964 :   switch (summary_sval->get_kind ())
     245              :     {
     246            0 :     default:
     247            0 :       gcc_unreachable ();
     248         2168 :     case SK_REGION:
     249         2168 :       {
     250         2168 :         const region_svalue *region_summary_sval
     251         2168 :           = as_a <const region_svalue *> (summary_sval);
     252         2168 :         const region *summary_reg = region_summary_sval->get_pointee ();
     253         2168 :         const region *caller_reg = convert_region_from_summary (summary_reg);
     254         2168 :         if (!caller_reg)
     255              :           return nullptr;
     256         2168 :         region_model_manager *mgr = get_manager ();
     257         2168 :         const svalue *caller_ptr
     258         2168 :           = mgr->get_ptr_svalue (summary_sval->get_type (),
     259              :                                  caller_reg);
     260         2168 :         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         4106 :     case SK_INITIAL:
     274         4106 :       {
     275         4106 :         const initial_svalue *initial_summary_sval
     276         4106 :           = as_a <const initial_svalue *> (summary_sval);
     277              :         /* Params should already be in the cache, courtesy of the ctor.  */
     278         4106 :         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         4106 :         const region *summary_reg = initial_summary_sval->get_region ();
     283         4106 :         const region *caller_reg = convert_region_from_summary (summary_reg);
     284         4106 :         if (!caller_reg)
     285              :           return nullptr;
     286         4094 :         const svalue *caller_sval
     287         4094 :           = m_cd.get_model ()->get_store_value (caller_reg, m_cd.get_ctxt ());
     288         4094 :         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         2237 :       break;
     305         2237 :     case SK_BINOP:
     306         2237 :       {
     307         2237 :         const binop_svalue *binop_summary_sval
     308         2237 :           = as_a <const binop_svalue *> (summary_sval);
     309         2237 :         const svalue *summary_arg0 = binop_summary_sval->get_arg0 ();
     310         2237 :         const svalue *caller_arg0 = convert_svalue_from_summary (summary_arg0);
     311         2237 :         if (!caller_arg0)
     312              :           return nullptr;
     313         2237 :         const svalue *summary_arg1 = binop_summary_sval->get_arg1 ();
     314         2237 :         const svalue *caller_arg1 = convert_svalue_from_summary (summary_arg1);
     315         2237 :         if (!caller_arg1)
     316              :           return nullptr;
     317         2237 :         region_model_manager *mgr = get_manager ();
     318         2237 :         return mgr->get_or_create_binop (summary_sval->get_type (),
     319              :                                          binop_summary_sval->get_op (),
     320              :                                          caller_arg0,
     321         2237 :                                          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           38 :       break;
     340           38 :     case SK_REPEATED:
     341           38 :       {
     342           38 :         const repeated_svalue *repeated_summary_sval
     343           38 :           = as_a <const repeated_svalue *> (summary_sval);
     344           38 :         const svalue *summary_outer_size
     345           38 :           = repeated_summary_sval->get_outer_size ();
     346           38 :         const svalue *caller_outer_size
     347           38 :           = convert_svalue_from_summary (summary_outer_size);
     348           38 :         if (!caller_outer_size)
     349              :           return nullptr;
     350           38 :         const svalue *summary_inner_sval
     351           38 :           = repeated_summary_sval->get_inner_svalue ();
     352           38 :         const svalue *caller_inner_sval
     353           38 :           = convert_svalue_from_summary (summary_inner_sval);
     354           38 :         if (!caller_inner_sval)
     355              :           return nullptr;
     356           38 :         region_model_manager *mgr = get_manager ();
     357           38 :         return mgr->get_or_create_repeated_svalue (summary_sval->get_type (),
     358              :                                                    caller_outer_size,
     359           38 :                                                    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          218 :       break;
     419          218 :     case SK_COMPOUND:
     420          218 :       {
     421          218 :         const compound_svalue *compound_summary_sval
     422          218 :           = as_a <const compound_svalue *> (summary_sval);
     423          218 :         region_model_manager *mgr = get_manager ();
     424          218 :         store_manager *store_mgr = mgr->get_store_manager ();
     425          218 :         binding_map caller_map (*store_mgr);
     426          218 :         auto_vec <const binding_key *> summary_keys;
     427          716 :         for (auto kv : *compound_summary_sval)
     428          498 :           summary_keys.safe_push (kv.m_key);
     429          218 :         summary_keys.qsort (binding_key::cmp_ptrs);
     430         1152 :         for (auto key : summary_keys)
     431              :           {
     432          498 :             gcc_assert (key->concrete_p ());
     433              :             /* No remapping is needed for concrete binding keys.  */
     434              : 
     435          498 :             const svalue *bound_summary_sval
     436          498 :               = compound_summary_sval->get_map ().get (key);
     437          498 :             const svalue *caller_sval
     438          498 :               = convert_svalue_from_summary (bound_summary_sval);
     439          498 :             if (!caller_sval)
     440            8 :               caller_sval = mgr->get_or_create_unknown_svalue (NULL_TREE);
     441              : 
     442          996 :             if (const compound_svalue *inner_compound_sval
     443          498 :                 = caller_sval->dyn_cast_compound_svalue ())
     444              :               {
     445            0 :                 const concrete_binding *outer_key
     446            0 :                   = as_a <const concrete_binding *> (key);
     447            0 :                 for (auto inner_kv : *inner_compound_sval)
     448              :                   {
     449              :                     // These should already be mapped to the caller.
     450            0 :                     const binding_key *inner_key = inner_kv.m_key;
     451            0 :                     const svalue *inner_sval = inner_kv.m_sval;
     452            0 :                     gcc_assert (inner_key->concrete_p ());
     453            0 :                     const concrete_binding *concrete_key
     454            0 :                       = as_a <const concrete_binding *> (inner_key);
     455            0 :                     bit_offset_t effective_start
     456            0 :                       = (concrete_key->get_start_bit_offset ()
     457            0 :                          + outer_key->get_start_bit_offset ());
     458            0 :                     const concrete_binding *effective_concrete_key
     459              :                       = store_mgr->get_concrete_binding
     460            0 :                           (effective_start,
     461              :                            concrete_key->get_size_in_bits ());
     462            0 :                     caller_map.put (effective_concrete_key, inner_sval);
     463              :                   }
     464              :               }
     465              :             else
     466          498 :               caller_map.put (key, caller_sval);
     467              :           }
     468          218 :         return mgr->get_or_create_compound_svalue (summary_sval->get_type (),
     469              :                                                    caller_map);
     470          218 :       }
     471           26 :       break;
     472           26 :     case SK_CONJURED:
     473           26 :       {
     474           26 :         region_model_manager *mgr = get_manager ();
     475           26 :         return mgr->get_or_create_unknown_svalue (summary_sval->get_type ());
     476              :       }
     477            8 :       break;
     478            8 :     case SK_ASM_OUTPUT:
     479            8 :       {
     480            8 :         const asm_output_svalue *asm_output_summary_sval
     481            8 :           = as_a <const asm_output_svalue *> (summary_sval);
     482            8 :         const char *asm_string = asm_output_summary_sval->get_asm_string ();
     483            8 :         unsigned output_idx = asm_output_summary_sval->get_output_idx ();
     484            8 :         unsigned num_inputs = asm_output_summary_sval->get_num_inputs ();
     485            8 :         unsigned num_outputs = asm_output_summary_sval->get_num_outputs ();
     486            8 :         auto_vec<const svalue *> inputs (num_inputs);
     487            8 :         for (unsigned idx = 0; idx < num_inputs; idx++)
     488              :           {
     489            0 :             const svalue *summary_input
     490            0 :               = asm_output_summary_sval->get_input (idx);
     491            0 :             const svalue *caller_input
     492            0 :               = convert_svalue_from_summary (summary_input);
     493            0 :             if (!caller_input)
     494            0 :               return nullptr;
     495            0 :             inputs.safe_push (caller_input);
     496              :           }
     497            8 :         region_model_manager *mgr = get_manager ();
     498            8 :         return mgr->get_or_create_asm_output_svalue (summary_sval->get_type (),
     499              :                                                      asm_string,
     500              :                                                      output_idx,
     501              :                                                      num_outputs,
     502            8 :                                                      inputs);
     503            8 :       }
     504            2 :       break;
     505            2 :     case SK_CONST_FN_RESULT:
     506            2 :       {
     507            2 :         const const_fn_result_svalue *const_fn_result_summary_sval
     508            2 :           = as_a <const const_fn_result_svalue *> (summary_sval);
     509            2 :         tree fndecl = const_fn_result_summary_sval->get_fndecl ();
     510            2 :         unsigned num_inputs = const_fn_result_summary_sval->get_num_inputs ();
     511            2 :         auto_vec<const svalue *> inputs (num_inputs);
     512            4 :         for (unsigned idx = 0; idx < num_inputs; idx++)
     513              :           {
     514            2 :             const svalue *summary_input
     515            2 :               = const_fn_result_summary_sval->get_input (idx);
     516            2 :             const svalue *caller_input
     517            2 :               = convert_svalue_from_summary (summary_input);
     518            2 :             if (!caller_input)
     519            0 :               return nullptr;
     520            2 :             inputs.safe_push (caller_input);
     521              :           }
     522            2 :         region_model_manager *mgr = get_manager ();
     523            2 :         return mgr->get_or_create_const_fn_result_svalue
     524            2 :           (summary_sval->get_type (),
     525              :            fndecl,
     526            2 :            inputs);
     527            2 :       }
     528              :       break;
     529              :     }
     530              : }
     531              : 
     532              : /* Try to convert SUMMARY_REG in the summary to a corresponding region
     533              :    in the caller, caching the result.
     534              : 
     535              :    Return nullptr if the conversion is not possible.  */
     536              : 
     537              : const region *
     538        22853 : call_summary_replay::convert_region_from_summary (const region *summary_reg)
     539              : {
     540        22853 :   gcc_assert (summary_reg);
     541              : 
     542        45706 :   if (const region **slot
     543        22853 :         = m_map_region_from_summary_to_caller.get (summary_reg))
     544         7839 :     return *slot;
     545              : 
     546        15014 :   const region *caller_reg = convert_region_from_summary_1 (summary_reg);
     547              : 
     548        15014 :   if (caller_reg)
     549        14761 :     if (summary_reg->get_type () && caller_reg->get_type ())
     550        12858 :       gcc_assert (types_compatible_p (summary_reg->get_type (),
     551              :                                       caller_reg->get_type ()));
     552              : 
     553              :   /* Add to cache.  */
     554        15014 :   add_region_mapping (summary_reg, caller_reg);
     555              : 
     556        15014 :   return caller_reg;
     557              : }
     558              : 
     559              : /* Implementation of call_summary_replay::convert_region_from_summary.  */
     560              : 
     561              : const region *
     562        15014 : call_summary_replay::convert_region_from_summary_1 (const region *summary_reg)
     563              : {
     564        15014 :   gcc_assert (summary_reg);
     565              : 
     566        15014 :   region_model_manager *mgr = get_manager ();
     567        15014 :   switch (summary_reg->get_kind ())
     568              :     {
     569            0 :     default:
     570            0 :       gcc_unreachable ();
     571              :       /* Top-level regions.  */
     572            0 :     case RK_FRAME:
     573            0 :     case RK_GLOBALS:
     574            0 :     case RK_CODE:
     575            0 :     case RK_STACK:
     576            0 :     case RK_HEAP:
     577            0 :     case RK_THREAD_LOCAL:
     578            0 :     case RK_ROOT:
     579              :       /* These should never be pointed to by a region_svalue.  */
     580            0 :       gcc_unreachable ();
     581              : 
     582              :     case RK_FUNCTION:
     583              :     case RK_LABEL:
     584              :     case RK_STRING:
     585              :     case RK_ERRNO:
     586              :     case RK_UNKNOWN:
     587              :     case RK_PRIVATE:
     588              :       /* We can reuse these regions directly.  */
     589              :       return summary_reg;
     590              : 
     591         2693 :     case RK_SYMBOLIC:
     592         2693 :       {
     593         2693 :         const symbolic_region *summary_symbolic_reg
     594         2693 :           = as_a <const symbolic_region *> (summary_reg);
     595         2693 :         const svalue *summary_ptr_sval = summary_symbolic_reg->get_pointer ();
     596         2693 :         const svalue *caller_ptr_sval
     597         2693 :           = convert_svalue_from_summary (summary_ptr_sval);
     598         2693 :         if (!caller_ptr_sval)
     599              :           return nullptr;
     600         2693 :         const region *caller_reg
     601         2693 :           = get_caller_model ()->deref_rvalue (caller_ptr_sval,
     602              :                                                NULL_TREE,
     603              :                                                get_ctxt ());
     604         2693 :         caller_reg = mgr->get_cast_region (caller_reg,
     605              :                                            summary_reg->get_type ());
     606         2693 :         return caller_reg;
     607              :       }
     608         8098 :       break;
     609              : 
     610         8098 :     case RK_DECL:
     611         8098 :       {
     612         8098 :         const decl_region *summary_decl_reg
     613         8098 :           = as_a <const decl_region *> (summary_reg);
     614         8098 :         tree decl = summary_decl_reg->get_decl ();
     615         8098 :         switch (TREE_CODE (decl))
     616              :           {
     617            0 :           default:
     618            0 :             gcc_unreachable ();
     619              :           case SSA_NAME:
     620              :             /* We don't care about writes to locals within
     621              :                the summary.  */
     622              :             return nullptr;
     623         6968 :           case VAR_DECL:
     624              :             /* We don't care about writes to locals within
     625              :                the summary.  */
     626         6968 :             if (is_global_var (decl))
     627              :               /* If it's a global, we can reuse the region directly.  */
     628              :               return summary_reg;
     629              :             else
     630              :               /* Otherwise, we don't care about locals.  */
     631              :               return nullptr;
     632          921 :           case RESULT_DECL:
     633          921 :             return m_cd.get_lhs_region ();
     634              :           case PARM_DECL:
     635              :             /* Writes (by value) to parms should be visible to the caller.  */
     636              :             return nullptr;
     637              :           }
     638              :       }
     639         1014 :       break;
     640         1014 :     case RK_FIELD:
     641         1014 :       {
     642         1014 :         const field_region *summary_field_reg
     643         1014 :           = as_a <const field_region *> (summary_reg);
     644         1014 :         const region *summary_parent_reg = summary_reg->get_parent_region ();
     645         1014 :         const region *caller_parent_reg
     646         1014 :           = convert_region_from_summary (summary_parent_reg);
     647         1014 :         if (!caller_parent_reg)
     648              :           return nullptr;
     649         1006 :         tree field = summary_field_reg->get_field ();
     650         1006 :         return mgr->get_field_region (caller_parent_reg, field);
     651              :       }
     652           22 :       break;
     653           22 :     case RK_ELEMENT:
     654           22 :       {
     655           22 :         const element_region *summary_element_reg
     656           22 :           = as_a <const element_region *> (summary_reg);
     657           22 :         const region *summary_parent_reg = summary_reg->get_parent_region ();
     658           22 :         const region *caller_parent_reg
     659           22 :           = convert_region_from_summary (summary_parent_reg);
     660           22 :         if (!caller_parent_reg)
     661              :           return nullptr;
     662           12 :         const svalue *summary_index = summary_element_reg->get_index ();
     663           12 :         const svalue *caller_index
     664           12 :           = convert_svalue_from_summary (summary_index);
     665           12 :         if (!caller_index)
     666              :           return nullptr;
     667           12 :         return mgr->get_element_region (caller_parent_reg,
     668              :                                         summary_reg->get_type (),
     669           12 :                                         caller_index);
     670              :       }
     671          580 :       break;
     672          580 :     case RK_OFFSET:
     673          580 :       {
     674          580 :         const offset_region *summary_offset_reg
     675          580 :           = as_a <const offset_region *> (summary_reg);
     676          580 :         const region *summary_parent_reg = summary_reg->get_parent_region ();
     677          580 :         const region *caller_parent_reg
     678          580 :           = convert_region_from_summary (summary_parent_reg);
     679          580 :         if (!caller_parent_reg)
     680              :           return nullptr;
     681          580 :         const svalue *summary_byte_offset
     682          580 :           = summary_offset_reg->get_byte_offset ();
     683          580 :         const svalue *caller_byte_offset
     684          580 :           = convert_svalue_from_summary (summary_byte_offset);
     685          580 :         if (!caller_byte_offset)
     686              :           return nullptr;
     687          580 :         return mgr->get_offset_region (caller_parent_reg,
     688              :                                        summary_reg->get_type (),
     689          580 :                                        caller_byte_offset);
     690              :       }
     691            0 :       break;
     692            0 :     case RK_SIZED:
     693            0 :       {
     694            0 :         const sized_region *summary_sized_reg
     695            0 :           = as_a <const sized_region *> (summary_reg);
     696            0 :         const region *summary_parent_reg = summary_reg->get_parent_region ();
     697            0 :         const region *caller_parent_reg
     698            0 :           = convert_region_from_summary (summary_parent_reg);
     699            0 :         if (!caller_parent_reg)
     700              :           return nullptr;
     701            0 :         const svalue *summary_byte_size
     702            0 :           = summary_sized_reg->get_byte_size_sval (mgr);
     703            0 :         const svalue *caller_byte_size
     704            0 :           = convert_svalue_from_summary (summary_byte_size);
     705            0 :         if (!caller_byte_size)
     706              :           return nullptr;
     707            0 :         return mgr->get_sized_region (caller_parent_reg,
     708              :                                        summary_reg->get_type (),
     709            0 :                                        caller_byte_size);
     710              :       }
     711            0 :       break;
     712            0 :     case RK_CAST:
     713            0 :       {
     714            0 :         const region *summary_parent_reg = summary_reg->get_parent_region ();
     715            0 :         const region *caller_parent_reg
     716            0 :           = convert_region_from_summary (summary_parent_reg);
     717            0 :         if (!caller_parent_reg)
     718              :           return nullptr;
     719            0 :         return mgr->get_cast_region (caller_parent_reg,
     720            0 :                                      summary_reg->get_type ());
     721              :       }
     722         1903 :       break;
     723         1903 :     case RK_HEAP_ALLOCATED:
     724         1903 :       {
     725              :         /* If we have a heap-allocated region in the summary, then
     726              :            it was allocated within the callee.
     727              :            Create a new heap-allocated region to summarize this.  */
     728         1903 :         auto_bitmap heap_regs_in_use;
     729         1903 :         get_caller_model ()->get_referenced_base_regions (heap_regs_in_use);
     730         1903 :         return mgr->get_or_create_region_for_heap_alloc (heap_regs_in_use);
     731         1903 :       }
     732              :       break;
     733              :     case RK_ALLOCA:
     734              :       return nullptr;
     735            0 :     case RK_BIT_RANGE:
     736            0 :       {
     737            0 :         const bit_range_region *summary_bit_range_reg
     738            0 :           = as_a <const bit_range_region *> (summary_reg);
     739            0 :         const region *summary_parent_reg = summary_reg->get_parent_region ();
     740            0 :         const region *caller_parent_reg
     741            0 :           = convert_region_from_summary (summary_parent_reg);
     742            0 :         if (!caller_parent_reg)
     743              :           return nullptr;
     744            0 :         const bit_range &bits = summary_bit_range_reg->get_bits ();
     745            0 :         return mgr->get_bit_range (caller_parent_reg,
     746              :                                    summary_reg->get_type (),
     747            0 :                                    bits);
     748              :       }
     749              :       break;
     750              :     case RK_VAR_ARG:
     751              :       return nullptr;
     752              :     }
     753              : }
     754              : 
     755              : /* Try to convert SUMMARY_KEY in the summary to a corresponding binding key
     756              :    in the caller.
     757              : 
     758              :    Return nullptr if the conversion is not possible.  */
     759              : 
     760              : const binding_key *
     761            0 : call_summary_replay::convert_key_from_summary (const binding_key *summary_key)
     762              : {
     763            0 :   if (summary_key->concrete_p ())
     764              :     return summary_key;
     765              : 
     766            0 :   const symbolic_binding *symbolic_key = (const symbolic_binding *)summary_key;
     767            0 :   const region *summary_reg = symbolic_key->get_region ();
     768            0 :   const region *caller_reg = convert_region_from_summary (summary_reg);
     769            0 :   if (!caller_reg)
     770              :     return nullptr;
     771            0 :   region_model_manager *mgr = get_manager ();
     772            0 :   store_manager *store_mgr = mgr->get_store_manager ();
     773            0 :   return store_mgr->get_symbolic_binding (caller_reg);
     774              : }
     775              : 
     776              : /* Record that SUMMARY_SVAL maps to CALLER_SVAL for this replay.  */
     777              : 
     778              : void
     779        21300 : call_summary_replay::add_svalue_mapping (const svalue *summary_sval,
     780              :                                          const svalue *caller_sval)
     781              : {
     782        21300 :   gcc_assert (summary_sval);
     783              :   // CALLER_SVAL can be nullptr
     784        21300 :   m_map_svalue_from_summary_to_caller.put (summary_sval, caller_sval);
     785        21300 : }
     786              : 
     787              : /* Record that SUMMARY_REG maps to CALLER_REG for this replay.  */
     788              : 
     789              : void
     790        15014 : call_summary_replay::add_region_mapping (const region *summary_reg,
     791              :                                          const region *caller_reg)
     792              : {
     793        15014 :   gcc_assert (summary_reg);
     794              :   // CALLER_REG can be nullptr
     795        15014 :   m_map_region_from_summary_to_caller.put (summary_reg, caller_reg);
     796        15014 : }
     797              : 
     798              : /* Dump a multiline representation of this object to PP.  */
     799              : 
     800              : void
     801            0 : call_summary_replay::dump_to_pp (pretty_printer *pp, bool simple) const
     802              : {
     803            0 :   pp_newline (pp);
     804            0 :   pp_string (pp, "CALL DETAILS:");
     805            0 :   pp_newline (pp);
     806            0 :   m_cd.dump_to_pp (pp, simple);
     807              : 
     808            0 :   pp_newline (pp);
     809            0 :   pp_string (pp, "CALLEE SUMMARY:");
     810            0 :   pp_newline (pp);
     811            0 :   m_summary.dump_to_pp (m_ext_state, pp, simple);
     812              : 
     813              :   /* Current state of caller (could be in mid-update).  */
     814            0 :   pp_newline (pp);
     815            0 :   pp_string (pp, "CALLER:");
     816            0 :   pp_newline (pp);
     817            0 :   m_cd.get_model ()->dump_to_pp (pp, simple, true);
     818              : 
     819            0 :   pp_newline (pp);
     820            0 :   pp_string (pp, "REPLAY STATE:");
     821            0 :   pp_newline (pp);
     822            0 :   pp_string (pp, "svalue mappings from summary to caller:");
     823            0 :   pp_newline (pp);
     824            0 :   auto_vec <const svalue *> summary_svals;
     825            0 :   for (auto kv : m_map_svalue_from_summary_to_caller)
     826            0 :     summary_svals.safe_push (kv.first);
     827            0 :   summary_svals.qsort (svalue::cmp_ptr_ptr);
     828            0 :   for (auto summary_sval : summary_svals)
     829              :     {
     830            0 :       pp_string (pp, "sval in summary: ");
     831            0 :       summary_sval->dump_to_pp (pp, simple);
     832            0 :       pp_newline (pp);
     833              : 
     834            0 :       const svalue *caller_sval
     835              :         = *((const_cast<svalue_map_t &>
     836            0 :              (m_map_svalue_from_summary_to_caller)).get (summary_sval));
     837            0 :       pp_string (pp, " sval in caller: ");
     838            0 :       caller_sval->dump_to_pp (pp, simple);
     839            0 :       pp_newline (pp);
     840              :     }
     841              : 
     842            0 :   pp_newline (pp);
     843            0 :   pp_string (pp, "region mappings from summary to caller:");
     844            0 :   pp_newline (pp);
     845            0 :   auto_vec <const region *> summary_regs;
     846            0 :   for (auto kv : m_map_region_from_summary_to_caller)
     847            0 :     summary_regs.safe_push (kv.first);
     848            0 :   summary_regs.qsort (region::cmp_ptr_ptr);
     849            0 :   for (auto summary_reg : summary_regs)
     850              :     {
     851            0 :       pp_string (pp, "reg in summary: ");
     852            0 :       if (summary_reg)
     853            0 :         summary_reg->dump_to_pp (pp, simple);
     854              :       else
     855            0 :         pp_string (pp, "(null)");
     856            0 :       pp_newline (pp);
     857              : 
     858            0 :       const region *caller_reg
     859              :         = *((const_cast<region_map_t &>
     860            0 :              (m_map_region_from_summary_to_caller)).get (summary_reg));
     861            0 :       pp_string (pp, " reg in caller: ");
     862            0 :       if (caller_reg)
     863            0 :         caller_reg->dump_to_pp (pp, simple);
     864              :       else
     865            0 :         pp_string (pp, "(null)");
     866            0 :       pp_newline (pp);
     867              :     }
     868            0 : }
     869              : 
     870              : /* Dump a multiline representation of this object to FILE.  */
     871              : 
     872              : void
     873            0 : call_summary_replay::dump (FILE *fp, bool simple) const
     874              : {
     875            0 :   tree_dump_pretty_printer pp (fp);
     876            0 :   dump_to_pp (&pp, simple);
     877            0 : }
     878              : 
     879              : /* Dump a multiline representation of this object to stderr.  */
     880              : 
     881              : DEBUG_FUNCTION void
     882            0 : call_summary_replay::dump (bool simple) const
     883              : {
     884            0 :   dump (stderr, simple);
     885            0 : }
     886              : 
     887              : } // namespace ana
     888              : 
     889              : #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.