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