LCOV - code coverage report
Current view: top level - gcc - ipa-fnsummary.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 90.6 % 64 58
Test Date: 2026-02-28 14:20:25 Functions: 85.7 % 7 6
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* IPA function body analysis.
       2              :    Copyright (C) 2003-2026 Free Software Foundation, Inc.
       3              :    Contributed by Jan Hubicka
       4              : 
       5              : This file is part of GCC.
       6              : 
       7              : GCC is free software; you can redistribute it and/or modify it under
       8              : the terms of the GNU General Public License as published by the Free
       9              : Software Foundation; either version 3, or (at your option) any later
      10              : version.
      11              : 
      12              : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      13              : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      15              : for more details.
      16              : 
      17              : You should have received a copy of the GNU General Public License
      18              : along with GCC; see the file COPYING3.  If not see
      19              : <http://www.gnu.org/licenses/>.  */
      20              : 
      21              : #ifndef GCC_IPA_SUMMARY_H
      22              : #define GCC_IPA_SUMMARY_H
      23              : 
      24              : #include "sreal.h"
      25              : #include "ipa-predicate.h"
      26              : 
      27              : 
      28              : /* Hints are reasons why IPA heuristics should prefer specializing given
      29              :    function.  They are represented as bitmap of the following values.  */
      30              : enum ipa_hints_vals {
      31              :   /* When specialization turns indirect call into a direct call,
      32              :      it is good idea to do so.  */
      33              :   INLINE_HINT_indirect_call = 1,
      34              :   /* Inlining may make loop iterations or loop stride known.  It is good idea
      35              :      to do so because it enables loop optimizations.  */
      36              :   INLINE_HINT_loop_iterations = 2,
      37              :   INLINE_HINT_loop_stride = 4,
      38              :   /* Inlining within same strongly connected component of callgraph is often
      39              :      a loss due to increased stack frame usage and prologue setup costs.  */
      40              :   INLINE_HINT_same_scc = 8,
      41              :   /* Inlining functions in strongly connected component is not such a great
      42              :      win.  */
      43              :   INLINE_HINT_in_scc = 16,
      44              :   /* If function is declared inline by user, it may be good idea to inline
      45              :      it.  Set by simple_edge_hints in ipa-inline-analysis.cc.  */
      46              :   INLINE_HINT_declared_inline = 32,
      47              :   /* Programs are usually still organized for non-LTO compilation and thus
      48              :      if functions are in different modules, inlining may not be so important.
      49              :      Set by simple_edge_hints in ipa-inline-analysis.cc.   */
      50              :   INLINE_HINT_cross_module = 64,
      51              :   /* We know that the callee is hot by profile.  */
      52              :   INLINE_HINT_known_hot = 128,
      53              :   /* There is builtin_constant_p dependent on parameter which is usually
      54              :      a strong hint to inline.  */
      55              :   INLINE_HINT_builtin_constant_p = 256
      56              : };
      57              : 
      58              : typedef int ipa_hints;
      59              : 
      60              : /* Simple description of whether a memory load or a condition refers to a load
      61              :    from an aggregate and if so, how and where from in the aggregate.
      62              :    Individual fields have the same meaning like fields with the same name in
      63              :    struct condition.  */
      64              : 
      65              : struct agg_position_info
      66              : {
      67              :   HOST_WIDE_INT offset;
      68              :   bool agg_contents;
      69              :   bool by_ref;
      70              : };
      71              : 
      72              : /* Representation of function body size and time depending on the call
      73              :    context.  We keep simple array of record, every containing of predicate
      74              :    and time/size to account.  */
      75     29345048 : class size_time_entry
      76              : {
      77              : public:
      78              :   /* Predicate for code to be executed.  */
      79              :   ipa_predicate exec_predicate;
      80              :   /* Predicate for value to be constant and optimized out in a specialized copy.
      81              :      When deciding on specialization this makes it possible to see how much
      82              :      the executed code paths will simplify.  */
      83              :   ipa_predicate nonconst_predicate;
      84              :   int size;
      85              :   sreal time;
      86              : };
      87              : 
      88              : /* Summary about function and stack frame sizes.  We keep this info
      89              :    for inline clones and also for WPA streaming. For this reason this is not
      90              :    part of ipa_fn_summary which exists only for offline functions.  */
      91              : class ipa_size_summary
      92              : {
      93              : public:
      94              :   /* Estimated stack frame consumption by the function.  */
      95              :   HOST_WIDE_INT estimated_self_stack_size;
      96              :   /* Size of the function body.  */
      97              :   int self_size;
      98              :   /* Estimated size of the function after inlining.  */
      99              :   int size;
     100              : 
     101      7404247 :   ipa_size_summary ()
     102      7404247 :   : estimated_self_stack_size (0), self_size (0), size (0)
     103              :   {
     104              :   }
     105              : };
     106              : 
     107              : /* Structure to capture how frequently some interesting events occur given a
     108              :    particular predicate.  The structure is used to estimate how often we
     109              :    encounter loops with known iteration count or stride in various
     110              :    contexts.  */
     111              : 
     112        69891 : struct GTY(()) ipa_freqcounting_predicate
     113              : {
     114              :   /* The described event happens with this frequency... */
     115              :   sreal freq;
     116              :   /* ...when this predicate evaluates to false. */
     117              :   ipa_predicate * GTY((skip)) predicate;
     118              : };
     119              : 
     120              : /* Function inlining information.  */
     121              : class GTY(()) ipa_fn_summary
     122              : {
     123              : public:
     124              :   /* Keep all field empty so summary dumping works during its computation.
     125              :      This is useful for debugging.  */
     126      9837559 :   ipa_fn_summary ()
     127      9837559 :     : min_size (0),
     128      9837559 :       inlinable (false), single_caller (false),
     129      9837559 :       fp_expressions (false), safe_to_inline_to_always_inline (0),
     130      9837559 :       target_info (0), estimated_stack_size (false),
     131      9837559 :       time (0), conds (NULL),
     132      9837559 :       size_time_table (), call_size_time_table (vNULL),
     133      9837559 :       loop_iterations (NULL), loop_strides (NULL),
     134      9837559 :       builtin_constant_p_parms (vNULL),
     135      9837559 :       growth (0), scc_no (0)
     136              :   {
     137      9837559 :   }
     138              : 
     139              :   /* Copy constructor.  */
     140      2624050 :   ipa_fn_summary (const ipa_fn_summary &s)
     141      2624050 :     : min_size (s.min_size),
     142      2624050 :     inlinable (s.inlinable), single_caller (s.single_caller),
     143      2624050 :     fp_expressions (s.fp_expressions),
     144      2624050 :     target_info (s.target_info),
     145      2624050 :     estimated_stack_size (s.estimated_stack_size),
     146      2624050 :     time (s.time), conds (s.conds), size_time_table (),
     147      2624050 :     call_size_time_table (vNULL),
     148      2624050 :     loop_iterations (s.loop_iterations), loop_strides (s.loop_strides),
     149      2624050 :     builtin_constant_p_parms (s.builtin_constant_p_parms),
     150      2624050 :     growth (s.growth), scc_no (s.scc_no)
     151      2624050 :   {}
     152              : 
     153              :   /* Default constructor.  */
     154              :   ~ipa_fn_summary ();
     155              : 
     156              :   /* Information about the function body itself.  */
     157              : 
     158              :   /* Minimal size increase after inlining.  */
     159              :   int min_size;
     160              : 
     161              :   /* False when there something makes inlining impossible (such as va_arg).  */
     162              :   unsigned inlinable : 1;
     163              :   /* True wen there is only one caller of the function before small function
     164              :      inlining.  */
     165              :   unsigned int single_caller : 1;
     166              :   /* True if function contains any floating point expressions.  */
     167              :   unsigned int fp_expressions : 1;
     168              :   /* Cache for analysis of can_early_inline_edge_p.  */
     169              :   unsigned int safe_to_inline_to_always_inline : 2;
     170              :   /* Like fp_expressions field above, but it's to hold some target specific
     171              :      information, such as some target specific isa flags.  Note that for
     172              :      offloading target compilers, this field isn't streamed.  */
     173              :   unsigned int target_info;
     174              : 
     175              :   /* Information about function that will result after applying all the
     176              :      inline decisions present in the callgraph.  Generally kept up to
     177              :      date only for functions that are not inline clones. */
     178              : 
     179              :   /* Estimated stack frame consumption by the function.  */
     180              :   HOST_WIDE_INT estimated_stack_size;
     181              :   /* Estimated runtime of function after inlining.  */
     182              :   sreal GTY((skip)) time;
     183              : 
     184              :   /* Conditional size/time information.  The summaries are being
     185              :      merged during inlining.  */
     186              :   conditions conds;
     187              :   /* Normal code is accounted in size_time_table, while calls are
     188              :      accounted in call_size_time_table.  This is because calls
     189              :      are often adjusted by IPA optimizations and thus this summary
     190              :      is generated from call summary information when needed.  */
     191              :   auto_vec<size_time_entry> GTY((skip)) size_time_table;
     192              :   /* Unlike size_time_table that is initialized for all summaries
     193              :      call_size_time_table is allocated only for functions with
     194              :      many calls.  Use effecient vl_ptr storage.  */
     195              :   vec<size_time_entry, va_heap, vl_ptr> GTY((skip)) call_size_time_table;
     196              : 
     197              :   /* Predicates on when some loops in the function can have known bounds.  */
     198              :   vec<ipa_freqcounting_predicate, va_gc> *loop_iterations;
     199              :   /* Predicates on when some loops in the function can have known strides.  */
     200              :   vec<ipa_freqcounting_predicate, va_gc> *loop_strides;
     201              :   /* Parameters tested by builtin_constant_p.  */
     202              :   vec<int, va_heap, vl_ptr> GTY((skip)) builtin_constant_p_parms;
     203              :   /* Estimated growth for inlining all copies of the function before start
     204              :      of small functions inlining.
     205              :      This value will get out of date as the callers are duplicated, but
     206              :      using up-to-date value in the badness metric mean a lot of extra
     207              :      expenses.  */
     208              :   int growth;
     209              :   /* Number of SCC on the beginning of inlining process.  */
     210              :   int scc_no;
     211              : 
     212              :   /* Record time and size under given predicates.  */
     213              :   void account_size_time (int, sreal, const ipa_predicate &,
     214              :                           const ipa_predicate &,
     215              :                           bool call = false);
     216              : 
     217              :   /* We keep values scaled up, so fractional sizes can be accounted.  */
     218              :   static const int size_scale = 2;
     219              :   /* Maximal size of size_time_table before we start to be conservative.  */
     220              :   static const int max_size_time_table_size = 256;
     221              : };
     222              : 
     223              : class GTY((user)) ipa_fn_summary_t:
     224              :   public fast_function_summary <ipa_fn_summary *, va_gc>
     225              : {
     226              : public:
     227       454060 :   ipa_fn_summary_t (symbol_table *symtab):
     228       908120 :     fast_function_summary <ipa_fn_summary *, va_gc> (symtab) {}
     229              : 
     230       454060 :   static ipa_fn_summary_t *create_ggc (symbol_table *symtab)
     231              :   {
     232       454060 :     class ipa_fn_summary_t *summary
     233       454060 :       = new (ggc_alloc_no_dtor<ipa_fn_summary_t> ()) ipa_fn_summary_t (symtab);
     234       454060 :     summary->disable_insertion_hook ();
     235       454060 :     return summary;
     236              :   }
     237              : 
     238              :   /* Remove ipa_fn_summary for all callees of NODE.  */
     239              :   void remove_callees (cgraph_node *node);
     240              : 
     241              :   void insert (cgraph_node *, ipa_fn_summary *) final override;
     242            0 :   void remove (cgraph_node *node, ipa_fn_summary *) final override
     243              :   {
     244            0 :     remove_callees (node);
     245            0 :   }
     246              : 
     247              :   void duplicate (cgraph_node *src, cgraph_node *dst,
     248              :                   ipa_fn_summary *src_data, ipa_fn_summary *dst_data)
     249              :     final override;
     250              : };
     251              : 
     252              : extern GTY(()) fast_function_summary <ipa_fn_summary *, va_gc>
     253              :   *ipa_fn_summaries;
     254              : 
     255              : class ipa_size_summary_t:
     256              :   public fast_function_summary <ipa_size_summary *, va_heap>
     257              : {
     258              : public:
     259       454060 :   ipa_size_summary_t (symbol_table *symtab):
     260       454060 :     fast_function_summary <ipa_size_summary *, va_heap> (symtab)
     261              :   {
     262       454060 :     disable_insertion_hook ();
     263       454060 :   }
     264              : 
     265      3058401 :   void duplicate (cgraph_node *, cgraph_node *,
     266              :                   ipa_size_summary *src_data,
     267              :                   ipa_size_summary *dst_data) final override
     268              :   {
     269      3058401 :     *dst_data = *src_data;
     270      3058401 :   }
     271              : };
     272              : extern fast_function_summary <ipa_size_summary *, va_heap>
     273              :   *ipa_size_summaries;
     274              : 
     275              : /* Information kept about callgraph edges.  */
     276              : class ipa_call_summary
     277              : {
     278              : public:
     279              :   /* Keep all field empty so summary dumping works during its computation.
     280              :      This is useful for debugging.  */
     281     26701302 :   ipa_call_summary ()
     282            0 :     : predicate (NULL), param (vNULL), call_stmt_size (0), call_stmt_time (0),
     283            0 :       loop_depth (0), is_return_callee_uncaptured (false)
     284              :     {
     285              :     }
     286              : 
     287              :   /* Copy constructor.  */
     288      3662137 :   ipa_call_summary (const ipa_call_summary &s):
     289      3662137 :     predicate (s.predicate), param (s.param), call_stmt_size (s.call_stmt_size),
     290      3662137 :     call_stmt_time (s.call_stmt_time), loop_depth (s.loop_depth),
     291      3662137 :     is_return_callee_uncaptured (s.is_return_callee_uncaptured)
     292              :   {
     293              :   }
     294              : 
     295              :   /* Default destructor.  */
     296              :   ~ipa_call_summary ();
     297              : 
     298              :   ipa_predicate *predicate;
     299              :   /* Vector indexed by parameters.  */
     300              :   vec<inline_param_summary> param;
     301              :   /* Estimated size and time of the call statement.  */
     302              :   int call_stmt_size;
     303              :   int call_stmt_time;
     304              :   /* Depth of loop nest, 0 means no nesting.  */
     305              :   unsigned int loop_depth;
     306              :   /* Indicates whether the caller returns the value of it's callee.  */
     307              :   bool is_return_callee_uncaptured;
     308              : };
     309              : 
     310              : class ipa_call_summary_t: public fast_call_summary <ipa_call_summary *, va_heap>
     311              : {
     312              : public:
     313       454060 :   ipa_call_summary_t (symbol_table *symtab):
     314       454060 :     fast_call_summary <ipa_call_summary *, va_heap> (symtab) {}
     315              : 
     316              :   /* Hook that is called by summary when an edge is duplicated.  */
     317              :   void duplicate (cgraph_edge *src, cgraph_edge *dst,
     318              :                   ipa_call_summary *src_data,
     319              :                   ipa_call_summary *dst_data) final override;
     320              : };
     321              : 
     322              : /* Estimated execution times, code sizes and other information about the
     323              :    code executing a call described by ipa_call_context.  */
     324              : 
     325     18866692 : struct ipa_call_estimates
     326              : {
     327              :   /* Estimated size needed to execute call in the given context. */
     328              :   int size;
     329              : 
     330              :   /* Minimal size needed for the call that is + independent on the call context
     331              :      and can be used for fast estimates.  */
     332              :   int min_size;
     333              : 
     334              :   /* Estimated time needed to execute call in the given context. */
     335              :   sreal time;
     336              : 
     337              :   /* Estimated time needed to execute the function when not ignoring
     338              :      computations known to be constant in this context.  */
     339              :   sreal nonspecialized_time;
     340              : 
     341              :   /* Further discovered reasons why to inline or specialize the give calls.  */
     342              :   ipa_hints hints;
     343              : 
     344              :   /* Frequency how often a loop with known number of iterations is encountered.
     345              :      Calculated with hints.  */
     346              :   sreal loops_with_known_iterations;
     347              : 
     348              :   /* Frequency how often a loop with known strides is encountered.  Calculated
     349              :      with hints.  */
     350              :   sreal loops_with_known_strides;
     351              : };
     352              : 
     353              : class ipa_cached_call_context;
     354              : 
     355              : /* This object describe a context of call.  That is a summary of known
     356              :    information about its parameters.  Main purpose of this context is
     357              :    to give more realistic estimations of function runtime, size and
     358              :    inline hints.  */
     359              : class ipa_call_context
     360              : {
     361              : public:
     362              :   ipa_call_context (cgraph_node *node,
     363              :                     clause_t possible_truths,
     364              :                     clause_t nonspec_possible_truths,
     365              :                     vec<inline_param_summary> inline_param_summary,
     366              :                     ipa_auto_call_arg_values *arg_values);
     367      1166590 :   ipa_call_context ()
     368      1166590 :   : m_node(NULL)
     369              :   {
     370              :   }
     371              :   void estimate_size_and_time (ipa_call_estimates *estimates,
     372              :                                bool est_times = true, bool est_hints = true);
     373              :   bool equal_to (const ipa_call_context &);
     374      1855623 :   bool exists_p ()
     375              :   {
     376      1855623 :     return m_node != NULL;
     377              :   }
     378              : private:
     379              :   /* Called function.  */
     380              :   cgraph_node *m_node;
     381              :   /* Clause describing what predicate conditionals can be satisfied
     382              :      in this context if function is inlined/specialized.  */
     383              :   clause_t m_possible_truths;
     384              :   /* Clause describing what predicate conditionals can be satisfied
     385              :      in this context if function is kept offline.  */
     386              :   clause_t m_nonspec_possible_truths;
     387              :   /* Inline summary maintains info about change probabilities.  */
     388              :   vec<inline_param_summary> m_inline_param_summary;
     389              : 
     390              :   /* Even after having calculated clauses, the information about argument
     391              :      values is used to resolve indirect calls.  */
     392              :   ipa_call_arg_values m_avals;
     393              : 
     394              :   friend ipa_cached_call_context;
     395              : };
     396              : 
     397              : /* Variant of ipa_call_context that is stored in a cache over a longer period
     398              :    of time.  */
     399              : 
     400            0 : class ipa_cached_call_context : public ipa_call_context
     401              : {
     402              : public:
     403              :   void duplicate_from (const ipa_call_context &ctx);
     404              :   void release ();
     405              : };
     406              : 
     407              : extern fast_call_summary <ipa_call_summary *, va_heap> *ipa_call_summaries;
     408              : 
     409              : /* In ipa-fnsummary.cc  */
     410              : void ipa_debug_fn_summary (struct cgraph_node *);
     411              : void ipa_dump_fn_summaries (FILE *f);
     412              : void ipa_dump_fn_summary (FILE *f, struct cgraph_node *node);
     413              : void ipa_dump_hints (FILE *f, ipa_hints);
     414              : void ipa_free_fn_summary (void);
     415              : void ipa_free_size_summary (void);
     416              : void inline_analyze_function (struct cgraph_node *node);
     417              : void estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
     418              :                                         ipa_auto_call_arg_values *avals,
     419              :                                         ipa_call_estimates *estimates);
     420              : void ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge);
     421              : void ipa_update_overall_fn_summary (struct cgraph_node *node, bool reset = true);
     422              : void compute_fn_summary (struct cgraph_node *, bool);
     423              : bool refs_local_or_readonly_memory_p (tree);
     424              : bool points_to_local_or_readonly_memory_p (tree);
     425              : 
     426              : 
     427              : void evaluate_properties_for_edge (struct cgraph_edge *e,
     428              :                                    bool inline_p,
     429              :                                    clause_t *clause_ptr,
     430              :                                    clause_t *nonspec_clause_ptr,
     431              :                                    ipa_auto_call_arg_values *avals,
     432              :                                    bool compute_contexts);
     433              : 
     434              : void ipa_fnsummary_cc_finalize (void);
     435              : HOST_WIDE_INT ipa_get_stack_frame_offset (struct cgraph_node *node);
     436              : void ipa_remove_from_growth_caches (struct cgraph_edge *edge);
     437              : 
     438              : /* Return true if EDGE is a cross module call.  */
     439              : 
     440              : inline bool
     441      6678568 : cross_module_call_p (struct cgraph_edge *edge)
     442              : {
     443              :   /* Here we do not want to walk to alias target becuase ICF may create
     444              :      cross-unit aliases.  */
     445      6678568 :   if (edge->caller->unit_id == edge->callee->unit_id)
     446              :     return false;
     447              :   /* If the call is to a (former) comdat function or s symbol with mutiple
     448              :      extern inline definitions then treat is as in-module call.  */
     449         4116 :   if (edge->callee->merged_extern_inline || edge->callee->merged_comdat
     450         8231 :       || DECL_COMDAT (edge->callee->decl))
     451            7 :     return false;
     452              :   return true;
     453              : }
     454              : 
     455              : #endif /* GCC_IPA_FNSUMMARY_H */
        

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.