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