Home | History | Annotate | Line # | Download | only in gcc
      1 /* Interprocedural semantic function equality pass
      2    Copyright (C) 2014-2024 Free Software Foundation, Inc.
      3 
      4    Contributed by Jan Hubicka <hubicka (at) ucw.cz> and Martin Liska <mliska (at) 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 return_false_with_message_1 (const char *message, const char *filename,
     44 			     const char *func, unsigned int line)
     45 {
     46   if (dump_file && (dump_flags & TDF_DETAILS))
     47     fprintf (dump_file, "  false returned: '%s' in %s at %s:%u\n", message, func,
     48 	     filename, line);
     49   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 return_with_result (bool result, const char *filename,
     64 		    const char *func, unsigned int line)
     65 {
     66   if (!result && dump_file && (dump_flags & TDF_DETAILS))
     67     fprintf (dump_file, "  false returned: '' in %s at %s:%u\n", func,
     68 	     filename, line);
     69 
     70   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 return_different_stmts_1 (gimple *s1, gimple *s2, const char *code,
     82 			  const char *func, unsigned int line)
     83 {
     84   if (dump_file && (dump_flags & TDF_DETAILS))
     85     {
     86       fprintf (dump_file, "  different statement for code: %s (%s:%u):\n",
     87 	       code, func, line);
     88 
     89       print_gimple_stmt (dump_file, s1, 3, TDF_DETAILS);
     90       print_gimple_stmt (dump_file, s2, 3, TDF_DETAILS);
     91     }
     92 
     93   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   sem_bb (basic_block bb_, unsigned nondbg_stmt_count_, unsigned edge_count_):
    107     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   func_checker ():
    126     m_source_func_decl (NULL_TREE), m_target_func_decl (NULL_TREE),
    127     m_ignored_source_nodes (NULL), m_ignored_target_nodes (NULL),
    128     m_ignore_labels (false), m_tbaa (true),
    129     m_total_scalarization_limit_known_p (false)
    130   {
    131     m_source_ssa_names.create (0);
    132     m_target_ssa_names.create (0);
    133   }
    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
    310