xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/ipa-icf-gimple.h (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
1 /* Interprocedural semantic function equality pass
2    Copyright (C) 2014-2020 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 static inline bool
return_false_with_message_1(const char * message,const char * filename,const char * func,unsigned int line)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 static inline bool
return_with_result(bool result,const char * filename,const char * func,unsigned int line)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 static inline bool
return_different_stmts_1(gimple * s1,gimple * s2,const char * code,const char * func,unsigned int line)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:
sem_bb(basic_block bb_,unsigned nondbg_stmt_count_,unsigned edge_count_)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 : operand_compare
122 {
123 public:
124   /* Default constructor.  */
func_checker()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)
129   {
130     m_source_ssa_names.create (0);
131     m_target_ssa_names.create (0);
132   }
133 
134   /* Initialize internal structures for a given SOURCE_FUNC_DECL and
135      TARGET_FUNC_DECL. Strict polymorphic comparison is processed if
136      an option COMPARE_POLYMORPHIC is true. For special cases, one can
137      set IGNORE_LABELS to skip label comparison.
138      Similarly, IGNORE_SOURCE_DECLS and IGNORE_TARGET_DECLS are sets
139      of declarations that can be skipped.  */
140   func_checker (tree source_func_decl, tree target_func_decl,
141 		bool ignore_labels = false,
142 		hash_set<symtab_node *> *ignored_source_nodes = NULL,
143 		hash_set<symtab_node *> *ignored_target_nodes = NULL);
144 
145   /* Memory release routine.  */
146   virtual ~func_checker ();
147 
148   /* Function visits all gimple labels and creates corresponding
149      mapping between basic blocks and labels.  */
150   void parse_labels (sem_bb *bb);
151 
152   /* Basic block equivalence comparison function that returns true if
153      basic blocks BB1 and BB2 correspond.  */
154   bool compare_bb (sem_bb *bb1, sem_bb *bb2);
155 
156   /* Verifies that trees T1 and T2 are equivalent from perspective of ICF.  */
157   bool compare_ssa_name (const_tree t1, const_tree t2);
158 
159   /* Verification function for edges E1 and E2.  */
160   bool compare_edge (edge e1, edge e2);
161 
162   /* Verifies for given GIMPLEs S1 and S2 that
163      call statements are semantically equivalent.  */
164   bool compare_gimple_call (gcall *s1, gcall *s2);
165 
166   /* Verifies for given GIMPLEs S1 and S2 that
167      assignment statements are semantically equivalent.  */
168   bool compare_gimple_assign (gimple *s1, gimple *s2);
169 
170   /* Verifies for given GIMPLEs S1 and S2 that
171      condition statements are semantically equivalent.  */
172   bool compare_gimple_cond (gimple *s1, gimple *s2);
173 
174   /* Verifies for given GIMPLE_LABEL stmts S1 and S2 that
175      label statements are semantically equivalent.  */
176   bool compare_gimple_label (const glabel *s1, const glabel *s2);
177 
178   /* Verifies for given GIMPLE_SWITCH stmts S1 and S2 that
179      switch statements are semantically equivalent.  */
180   bool compare_gimple_switch (const gswitch *s1, const gswitch *s2);
181 
182   /* Verifies for given GIMPLE_RETURN stmts S1 and S2 that
183      return statements are semantically equivalent.  */
184   bool compare_gimple_return (const greturn *s1, const greturn *s2);
185 
186   /* Verifies for given GIMPLEs S1 and S2 that
187      goto statements are semantically equivalent.  */
188   bool compare_gimple_goto (gimple *s1, gimple *s2);
189 
190   /* Verifies for given GIMPLE_RESX stmts S1 and S2 that
191      resx statements are semantically equivalent.  */
192   bool compare_gimple_resx (const gresx *s1, const gresx *s2);
193 
194   /* Verifies for given GIMPLE_ASM stmts S1 and S2 that ASM statements
195      are equivalent.
196      For the beginning, the pass only supports equality for
197      '__asm__ __volatile__ ("", "", "", "memory")'.  */
198   bool compare_gimple_asm (const gasm *s1, const gasm *s2);
199 
200   /* Verification function for declaration trees T1 and T2.  */
201   bool compare_decl (const_tree t1, const_tree t2);
202 
203   /* Function responsible for comparison of various operands T1 and T2.
204      If these components, from functions FUNC1 and FUNC2, are equal, true
205      is returned.  */
206   bool compare_operand (tree t1, tree t2);
207 
208   /* Compares GIMPLE ASM inputs (or outputs) where we iterate tree chain
209      and compare both TREE_PURPOSEs and TREE_VALUEs.  */
210   bool compare_asm_inputs_outputs (tree t1, tree t2);
211 
212   /* Verifies that trees T1 and T2, representing function declarations
213      are equivalent from perspective of ICF.  */
214   bool compare_function_decl (tree t1, tree t2);
215 
216   /* Verifies that trees T1 and T2 do correspond.  */
217   bool compare_variable_decl (const_tree t1, const_tree t2);
218 
219   /* Compare loop information for basic blocks BB1 and BB2.  */
220   bool compare_loops (basic_block bb1, basic_block bb2);
221 
222   /* Return true if types are compatible for polymorphic call analysis.
223      COMPARE_PTR indicates if polymorphic type comparison should be
224      done for pointers, too.  */
225   static bool compatible_polymorphic_types_p (tree t1, tree t2,
226 					      bool compare_ptr);
227 
228   /* Return true if types are compatible from perspective of ICF.
229      FIRST_ARGUMENT indicates if the comparison is called for
230      first parameter of a function.  */
231   static bool compatible_types_p (tree t1, tree t2);
232 
233 
234 private:
235   /* Vector mapping source SSA names to target ones.  */
236   vec <int> m_source_ssa_names;
237 
238   /* Vector mapping target SSA names to source ones.  */
239   vec <int> m_target_ssa_names;
240 
241   /* Source TREE function declaration.  */
242   tree m_source_func_decl;
243 
244   /* Target TREE function declaration.  */
245   tree m_target_func_decl;
246 
247   /* Source symbol nodes that should be skipped by
248      declaration comparison.  */
249   hash_set<symtab_node *> *m_ignored_source_nodes;
250 
251   /* Target symbol nodes that should be skipped by
252      declaration comparison.  */
253   hash_set<symtab_node *> *m_ignored_target_nodes;
254 
255   /* Source to target edge map.  */
256   hash_map <edge, edge> m_edge_map;
257 
258   /* Source to target declaration map.  */
259   hash_map <const_tree, const_tree> m_decl_map;
260 
261   /* Label to basic block index mapping.  */
262   hash_map <const_tree, int> m_label_bb_map;
263 
264   /* Flag if ignore labels in comparison.  */
265   bool m_ignore_labels;
266 
267 public:
268   /* Return true if two operands are equal.  The flags fields can be used
269      to specify OEP flags described above.  */
270   virtual bool operand_equal_p (const_tree, const_tree, unsigned int flags);
271 
272   /* Generate a hash value for an expression.  This can be used iteratively
273      by passing a previous result as the HSTATE argument.  */
274   virtual void hash_operand (const_tree, inchash::hash &, unsigned flags);
275 };
276 
277 } // ipa_icf_gimple namespace
278