LCOV - code coverage report
Current view: top level - gcc - ipa-icf-gimple.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 100.0 % 24 24
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 4 4
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Interprocedural semantic function equality pass
       2              :    Copyright (C) 2014-2026 Free Software Foundation, Inc.
       3              : 
       4              :    Contributed by Jan Hubicka <hubicka@ucw.cz> and Martin Liska <mliska@suse.cz>
       5              : 
       6              : This file is part of GCC.
       7              : 
       8              : GCC is free software; you can redistribute it and/or modify it under
       9              : the terms of the GNU General Public License as published by the Free
      10              : Software Foundation; either version 3, or (at your option) any later
      11              : version.
      12              : 
      13              : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      14              : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      15              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      16              : for more details.
      17              : 
      18              : You should have received a copy of the GNU General Public License
      19              : along with GCC; see the file COPYING3.  If not see
      20              : <http://www.gnu.org/licenses/>.  */
      21              : 
      22              : /* Gimple identical code folding (class func_checker) is an infrastructure
      23              :    capable of comparing two given functions. The class compares every
      24              :    gimple statement and uses many dictionaries to map source and target
      25              :    SSA_NAMEs, declarations and other components.
      26              : 
      27              :    To use the infrastructure, create an instance of func_checker and call
      28              :    a comparison function based on type of gimple statement.  */
      29              : 
      30              : /* Prints string STRING to a FILE with a given number of SPACE_COUNT.  */
      31              : #define FPUTS_SPACES(file, space_count, string) \
      32              :   fprintf (file, "%*s" string, space_count, " ");
      33              : 
      34              : /* fprintf function wrapper that transforms given FORMAT to follow given
      35              :    number for SPACE_COUNT and call fprintf for a FILE.  */
      36              : #define FPRINTF_SPACES(file, space_count, format, ...) \
      37              :   fprintf (file, "%*s" format, space_count, " ", ##__VA_ARGS__);
      38              : 
      39              : /* Logs a MESSAGE to dump_file if exists and returns false. FUNC is name
      40              :    of function and LINE is location in the source file.  */
      41              : 
      42              : inline bool
      43      2766696 : return_false_with_message_1 (const char *message, const char *filename,
      44              :                              const char *func, unsigned int line)
      45              : {
      46      2766696 :   if (dump_file && (dump_flags & TDF_DETAILS))
      47           30 :     fprintf (dump_file, "  false returned: '%s' in %s at %s:%u\n", message, func,
      48              :              filename, line);
      49      2766696 :   return false;
      50              : }
      51              : 
      52              : /* Logs a MESSAGE to dump_file if exists and returns false.  */
      53              : #define return_false_with_msg(message) \
      54              :   return_false_with_message_1 (message, __FILE__, __func__, __LINE__)
      55              : 
      56              : /* Return false and log that false value is returned.  */
      57              : #define return_false() return_false_with_msg ("")
      58              : 
      59              : /* Logs return value if RESULT is false. FUNC is name of function and LINE
      60              :    is location in the source file.  */
      61              : 
      62              : inline bool
      63       758073 : return_with_result (bool result, const char *filename,
      64              :                     const char *func, unsigned int line)
      65              : {
      66       758073 :   if (!result && dump_file && (dump_flags & TDF_DETAILS))
      67            5 :     fprintf (dump_file, "  false returned: '' in %s at %s:%u\n", func,
      68              :              filename, line);
      69              : 
      70       758073 :   return result;
      71              : }
      72              : 
      73              : /* Logs return value if RESULT is false.  */
      74              : #define return_with_debug(result) return_with_result \
      75              :   (result, __FILE__, __func__, __LINE__)
      76              : 
      77              : /* Verbose logging function logging statements S1 and S2 of a CODE.
      78              :    FUNC is name of function and LINE is location in the source file.  */
      79              : 
      80              : inline bool
      81        38673 : return_different_stmts_1 (gimple *s1, gimple *s2, const char *code,
      82              :                           const char *func, unsigned int line)
      83              : {
      84        38673 :   if (dump_file && (dump_flags & TDF_DETAILS))
      85              :     {
      86            6 :       fprintf (dump_file, "  different statement for code: %s (%s:%u):\n",
      87              :                code, func, line);
      88              : 
      89            6 :       print_gimple_stmt (dump_file, s1, 3, TDF_DETAILS);
      90            6 :       print_gimple_stmt (dump_file, s2, 3, TDF_DETAILS);
      91              :     }
      92              : 
      93        38673 :   return false;
      94              : }
      95              : 
      96              : /* Verbose logging function logging statements S1 and S2 of a CODE.  */
      97              : #define return_different_stmts(s1, s2, code) \
      98              :   return_different_stmts_1 (s1, s2, code, __func__, __LINE__)
      99              : 
     100              : namespace ipa_icf_gimple {
     101              : 
     102              : /* Basic block struct for semantic equality pass.  */
     103              : class sem_bb
     104              : {
     105              : public:
     106      6601023 :   sem_bb (basic_block bb_, unsigned nondbg_stmt_count_, unsigned edge_count_):
     107      6601023 :     bb (bb_), nondbg_stmt_count (nondbg_stmt_count_), edge_count (edge_count_) {}
     108              : 
     109              :   /* Basic block the structure belongs to.  */
     110              :   basic_block bb;
     111              : 
     112              :   /* Number of non-debug statements in the basic block.  */
     113              :   unsigned nondbg_stmt_count;
     114              : 
     115              :   /* Number of edges connected to the block.  */
     116              :   unsigned edge_count;
     117              : };
     118              : 
     119              : /* A class aggregating all connections and semantic equivalents
     120              :    for a given pair of semantic function candidates.  */
     121              : class func_checker : ao_compare
     122              : {
     123              : public:
     124              :   /* Default constructor.  */
     125       252341 :   func_checker ():
     126       252341 :     m_source_func_decl (NULL_TREE), m_target_func_decl (NULL_TREE),
     127       252341 :     m_ignored_source_nodes (NULL), m_ignored_target_nodes (NULL),
     128       252341 :     m_ignore_labels (false), m_tbaa (true),
     129       252341 :     m_total_scalarization_limit_known_p (false)
     130              :   {
     131       252341 :     m_source_ssa_names.create (0);
     132       252341 :     m_target_ssa_names.create (0);
     133       252341 :   }
     134              : 
     135              :   /* Initialize internal structures for a given SOURCE_FUNC_DECL and
     136              :      TARGET_FUNC_DECL. Strict polymorphic comparison is processed if
     137              :      an option COMPARE_POLYMORPHIC is true. For special cases, one can
     138              :      set IGNORE_LABELS to skip label comparison.
     139              :      Similarly, IGNORE_SOURCE_DECLS and IGNORE_TARGET_DECLS are sets
     140              :      of declarations that can be skipped.  */
     141              :   func_checker (tree source_func_decl, tree target_func_decl,
     142              :                 bool ignore_labels = false,
     143              :                 bool tbaa = true,
     144              :                 hash_set<symtab_node *> *ignored_source_nodes = NULL,
     145              :                 hash_set<symtab_node *> *ignored_target_nodes = NULL);
     146              : 
     147              :   /* Memory release routine.  */
     148              :   virtual ~func_checker ();
     149              : 
     150              :   /* Function visits all gimple labels and creates corresponding
     151              :      mapping between basic blocks and labels.  */
     152              :   void parse_labels (sem_bb *bb);
     153              : 
     154              :   /* Basic block equivalence comparison function that returns true if
     155              :      basic blocks BB1 and BB2 correspond.  */
     156              :   bool compare_bb (sem_bb *bb1, sem_bb *bb2);
     157              : 
     158              :   /* Verifies that trees T1 and T2 are equivalent from perspective of ICF.  */
     159              :   bool compare_ssa_name (const_tree t1, const_tree t2);
     160              : 
     161              :   /* Verification function for edges E1 and E2.  */
     162              :   bool compare_edge (edge e1, edge e2);
     163              : 
     164              :   /* Verifies for given GIMPLEs S1 and S2 that
     165              :      call statements are semantically equivalent.  */
     166              :   bool compare_gimple_call (gcall *s1, gcall *s2);
     167              : 
     168              :   /* Verifies for given GIMPLEs S1 and S2 that
     169              :      assignment statements are semantically equivalent.  */
     170              :   bool compare_gimple_assign (gimple *s1, gimple *s2);
     171              : 
     172              :   /* Verifies for given GIMPLEs S1 and S2 that
     173              :      condition statements are semantically equivalent.  */
     174              :   bool compare_gimple_cond (gimple *s1, gimple *s2);
     175              : 
     176              :   /* Verifies for given GIMPLE_LABEL stmts S1 and S2 that
     177              :      label statements are semantically equivalent.  */
     178              :   bool compare_gimple_label (const glabel *s1, const glabel *s2);
     179              : 
     180              :   /* Verifies for given GIMPLE_SWITCH stmts S1 and S2 that
     181              :      switch statements are semantically equivalent.  */
     182              :   bool compare_gimple_switch (const gswitch *s1, const gswitch *s2);
     183              : 
     184              :   /* Verifies for given GIMPLE_RETURN stmts S1 and S2 that
     185              :      return statements are semantically equivalent.  */
     186              :   bool compare_gimple_return (const greturn *s1, const greturn *s2);
     187              : 
     188              :   /* Verifies for given GIMPLEs S1 and S2 that
     189              :      goto statements are semantically equivalent.  */
     190              :   bool compare_gimple_goto (gimple *s1, gimple *s2);
     191              : 
     192              :   /* Verifies for given GIMPLE_RESX stmts S1 and S2 that
     193              :      resx statements are semantically equivalent.  */
     194              :   bool compare_gimple_resx (const gresx *s1, const gresx *s2);
     195              : 
     196              :   /* Verifies for given GIMPLE_ASM stmts S1 and S2 that ASM statements
     197              :      are equivalent.
     198              :      For the beginning, the pass only supports equality for
     199              :      '__asm__ __volatile__ ("", "", "", "memory")'.  */
     200              :   bool compare_gimple_asm (const gasm *s1, const gasm *s2);
     201              : 
     202              :   /* Verification function for declaration trees T1 and T2.  */
     203              :   bool compare_decl (const_tree t1, const_tree t2);
     204              : 
     205              :   /* Compute hash map MAP that determines loads and stores of STMT.  */
     206              :   enum operand_access_type {OP_MEMORY, OP_NORMAL};
     207              :   typedef hash_set<tree> operand_access_type_map;
     208              : 
     209              :   /* Return true if either T1 and T2 cannot be totally scalarized or if doing
     210              :      so would result in copying the same memory.  Otherwise return false.  */
     211              :   bool safe_for_total_scalarization_p (tree t1, tree t2);
     212              : 
     213              :   /* Function responsible for comparison of various operands T1 and T2.
     214              :      If these components, from functions FUNC1 and FUNC2, are equal, true
     215              :      is returned.  */
     216              :   bool compare_operand (tree t1, tree t2, operand_access_type type);
     217              : 
     218              :   /* Compares GIMPLE ASM inputs (or outputs) where we iterate tree chain
     219              :      and compare both TREE_PURPOSEs and TREE_VALUEs.  */
     220              :   bool compare_asm_inputs_outputs (tree t1, tree t2,
     221              :                                    operand_access_type_map *map);
     222              : 
     223              :   /* Verifies that trees T1 and T2, representing function declarations
     224              :      are equivalent from perspective of ICF.  */
     225              :   bool compare_function_decl (tree t1, tree t2);
     226              : 
     227              :   /* Verifies that trees T1 and T2 do correspond.  */
     228              :   bool compare_variable_decl (const_tree t1, const_tree t2);
     229              : 
     230              :   /* Compare loop information for basic blocks BB1 and BB2.  */
     231              :   bool compare_loops (basic_block bb1, basic_block bb2);
     232              : 
     233              :   /* Return true if types are compatible for polymorphic call analysis.
     234              :      COMPARE_PTR indicates if polymorphic type comparison should be
     235              :      done for pointers, too.  */
     236              :   static bool compatible_polymorphic_types_p (tree t1, tree t2,
     237              :                                               bool compare_ptr);
     238              : 
     239              :   /* Return true if types are compatible from perspective of ICF.
     240              :      FIRST_ARGUMENT indicates if the comparison is called for
     241              :      first parameter of a function.  */
     242              :   static bool compatible_types_p (tree t1, tree t2);
     243              : 
     244              :   /* Compute hash map determining access types of operands.  */
     245              :   static void classify_operands (const gimple *stmt,
     246              :                                  operand_access_type_map *map);
     247              : 
     248              :   /* Return access type of a given operand.  */
     249              :   static operand_access_type get_operand_access_type
     250              :                  (operand_access_type_map *map, tree);
     251              : private:
     252              :   /* Vector mapping source SSA names to target ones.  */
     253              :   vec <int> m_source_ssa_names;
     254              : 
     255              :   /* Vector mapping target SSA names to source ones.  */
     256              :   vec <int> m_target_ssa_names;
     257              : 
     258              :   /* Source TREE function declaration.  */
     259              :   tree m_source_func_decl;
     260              : 
     261              :   /* Target TREE function declaration.  */
     262              :   tree m_target_func_decl;
     263              : 
     264              :   /* Source symbol nodes that should be skipped by
     265              :      declaration comparison.  */
     266              :   hash_set<symtab_node *> *m_ignored_source_nodes;
     267              : 
     268              :   /* Target symbol nodes that should be skipped by
     269              :      declaration comparison.  */
     270              :   hash_set<symtab_node *> *m_ignored_target_nodes;
     271              : 
     272              :   /* Source to target edge map.  */
     273              :   hash_map <edge, edge> m_edge_map;
     274              : 
     275              :   /* Source to target declaration map.  */
     276              :   hash_map <const_tree, const_tree> m_decl_map;
     277              : 
     278              :   /* Label to basic block index mapping.  */
     279              :   hash_map <const_tree, int> m_label_bb_map;
     280              : 
     281              :   /* Flag if ignore labels in comparison.  */
     282              :   bool m_ignore_labels;
     283              : 
     284              :   /* Flag if we should compare type based alias analysis info.  */
     285              :   bool m_tbaa;
     286              : 
     287              :   /* Set to true when total scalarization size has already been determined for
     288              :      the functions.  */
     289              :   bool m_total_scalarization_limit_known_p;
     290              : 
     291              :   /* When the above it set to true the determiend total scalarization
     292              :      limit.  */
     293              :   unsigned HOST_WIDE_INT m_total_scalarization_limit;
     294              : 
     295              : public:
     296              :   /* Return true if two operands are equal.  The flags fields can be used
     297              :      to specify OEP flags described above.  */
     298              :   bool operand_equal_p (const_tree, const_tree, unsigned int flags)
     299              :     final override;
     300              : 
     301              :   /* Generate a hash value for an expression.  This can be used iteratively
     302              :      by passing a previous result as the HSTATE argument.  */
     303              :   void hash_operand (const_tree, inchash::hash &, unsigned flags)
     304              :     final override;
     305              :   void hash_operand (const_tree, inchash::hash &, unsigned flags,
     306              :                      operand_access_type access);
     307              : };
     308              : 
     309              : } // ipa_icf_gimple namespace
        

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.