111
|
1 /* Interprocedural Identical Code Folding pass
|
145
|
2 Copyright (C) 2014-2020 Free Software Foundation, Inc.
|
111
|
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 #include "config.h"
|
|
23 #include "system.h"
|
|
24 #include "coretypes.h"
|
|
25 #include "backend.h"
|
|
26 #include "rtl.h"
|
|
27 #include "tree.h"
|
|
28 #include "gimple.h"
|
|
29 #include "tree-pass.h"
|
|
30 #include "ssa.h"
|
|
31 #include "cgraph.h"
|
|
32 #include "data-streamer.h"
|
|
33 #include "gimple-pretty-print.h"
|
|
34 #include "fold-const.h"
|
|
35 #include "gimple-iterator.h"
|
|
36 #include "ipa-utils.h"
|
|
37 #include "tree-eh.h"
|
|
38 #include "builtins.h"
|
145
|
39 #include "cfgloop.h"
|
111
|
40
|
|
41 #include "ipa-icf-gimple.h"
|
|
42
|
|
43 namespace ipa_icf_gimple {
|
|
44
|
|
45 /* Initialize internal structures for a given SOURCE_FUNC_DECL and
|
|
46 TARGET_FUNC_DECL. Strict polymorphic comparison is processed if
|
|
47 an option COMPARE_POLYMORPHIC is true. For special cases, one can
|
|
48 set IGNORE_LABELS to skip label comparison.
|
|
49 Similarly, IGNORE_SOURCE_DECLS and IGNORE_TARGET_DECLS are sets
|
|
50 of declarations that can be skipped. */
|
|
51
|
|
52 func_checker::func_checker (tree source_func_decl, tree target_func_decl,
|
|
53 bool ignore_labels,
|
|
54 hash_set<symtab_node *> *ignored_source_nodes,
|
|
55 hash_set<symtab_node *> *ignored_target_nodes)
|
|
56 : m_source_func_decl (source_func_decl), m_target_func_decl (target_func_decl),
|
|
57 m_ignored_source_nodes (ignored_source_nodes),
|
|
58 m_ignored_target_nodes (ignored_target_nodes),
|
|
59 m_ignore_labels (ignore_labels)
|
|
60 {
|
|
61 function *source_func = DECL_STRUCT_FUNCTION (source_func_decl);
|
|
62 function *target_func = DECL_STRUCT_FUNCTION (target_func_decl);
|
|
63
|
|
64 unsigned ssa_source = SSANAMES (source_func)->length ();
|
|
65 unsigned ssa_target = SSANAMES (target_func)->length ();
|
|
66
|
|
67 m_source_ssa_names.create (ssa_source);
|
|
68 m_target_ssa_names.create (ssa_target);
|
|
69
|
|
70 for (unsigned i = 0; i < ssa_source; i++)
|
|
71 m_source_ssa_names.safe_push (-1);
|
|
72
|
|
73 for (unsigned i = 0; i < ssa_target; i++)
|
|
74 m_target_ssa_names.safe_push (-1);
|
|
75 }
|
|
76
|
|
77 /* Memory release routine. */
|
|
78
|
|
79 func_checker::~func_checker ()
|
|
80 {
|
|
81 m_source_ssa_names.release();
|
|
82 m_target_ssa_names.release();
|
|
83 }
|
|
84
|
|
85 /* Verifies that trees T1 and T2 are equivalent from perspective of ICF. */
|
|
86
|
|
87 bool
|
145
|
88 func_checker::compare_ssa_name (const_tree t1, const_tree t2)
|
111
|
89 {
|
|
90 gcc_assert (TREE_CODE (t1) == SSA_NAME);
|
|
91 gcc_assert (TREE_CODE (t2) == SSA_NAME);
|
|
92
|
|
93 unsigned i1 = SSA_NAME_VERSION (t1);
|
|
94 unsigned i2 = SSA_NAME_VERSION (t2);
|
|
95
|
|
96 if (m_source_ssa_names[i1] == -1)
|
|
97 m_source_ssa_names[i1] = i2;
|
|
98 else if (m_source_ssa_names[i1] != (int) i2)
|
|
99 return false;
|
|
100
|
|
101 if(m_target_ssa_names[i2] == -1)
|
|
102 m_target_ssa_names[i2] = i1;
|
|
103 else if (m_target_ssa_names[i2] != (int) i1)
|
|
104 return false;
|
|
105
|
|
106 if (SSA_NAME_IS_DEFAULT_DEF (t1))
|
|
107 {
|
|
108 tree b1 = SSA_NAME_VAR (t1);
|
|
109 tree b2 = SSA_NAME_VAR (t2);
|
|
110
|
145
|
111 return compare_operand (b1, b2);
|
111
|
112 }
|
|
113
|
|
114 return true;
|
|
115 }
|
|
116
|
|
117 /* Verification function for edges E1 and E2. */
|
|
118
|
|
119 bool
|
|
120 func_checker::compare_edge (edge e1, edge e2)
|
|
121 {
|
|
122 if (e1->flags != e2->flags)
|
|
123 return false;
|
|
124
|
|
125 bool existed_p;
|
|
126
|
|
127 edge &slot = m_edge_map.get_or_insert (e1, &existed_p);
|
|
128 if (existed_p)
|
|
129 return return_with_debug (slot == e2);
|
|
130 else
|
|
131 slot = e2;
|
|
132
|
|
133 /* TODO: filter edge probabilities for profile feedback match. */
|
|
134
|
|
135 return true;
|
|
136 }
|
|
137
|
|
138 /* Verification function for declaration trees T1 and T2 that
|
|
139 come from functions FUNC1 and FUNC2. */
|
|
140
|
|
141 bool
|
145
|
142 func_checker::compare_decl (const_tree t1, const_tree t2)
|
111
|
143 {
|
|
144 if (!auto_var_in_fn_p (t1, m_source_func_decl)
|
|
145 || !auto_var_in_fn_p (t2, m_target_func_decl))
|
|
146 return return_with_debug (t1 == t2);
|
|
147
|
|
148 tree_code t = TREE_CODE (t1);
|
|
149 if ((t == VAR_DECL || t == PARM_DECL || t == RESULT_DECL)
|
|
150 && DECL_BY_REFERENCE (t1) != DECL_BY_REFERENCE (t2))
|
|
151 return return_false_with_msg ("DECL_BY_REFERENCE flags are different");
|
|
152
|
|
153 if (!compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2)))
|
|
154 return return_false ();
|
|
155
|
|
156 bool existed_p;
|
145
|
157 const_tree &slot = m_decl_map.get_or_insert (t1, &existed_p);
|
111
|
158 if (existed_p)
|
|
159 return return_with_debug (slot == t2);
|
|
160 else
|
|
161 slot = t2;
|
|
162
|
|
163 return true;
|
|
164 }
|
|
165
|
|
166 /* Return true if T1 and T2 are same for purposes of ipa-polymorphic-call
|
|
167 analysis. COMPARE_PTR indicates if types of pointers needs to be
|
|
168 considered. */
|
|
169
|
|
170 bool
|
|
171 func_checker::compatible_polymorphic_types_p (tree t1, tree t2,
|
|
172 bool compare_ptr)
|
|
173 {
|
|
174 gcc_assert (TREE_CODE (t1) != FUNCTION_TYPE && TREE_CODE (t1) != METHOD_TYPE);
|
|
175
|
|
176 /* Pointer types generally give no information. */
|
|
177 if (POINTER_TYPE_P (t1))
|
|
178 {
|
|
179 if (!compare_ptr)
|
|
180 return true;
|
|
181 return func_checker::compatible_polymorphic_types_p (TREE_TYPE (t1),
|
|
182 TREE_TYPE (t2),
|
|
183 false);
|
|
184 }
|
|
185
|
|
186 /* If types contain a polymorphic types, match them. */
|
|
187 bool c1 = contains_polymorphic_type_p (t1);
|
|
188 bool c2 = contains_polymorphic_type_p (t2);
|
|
189 if (!c1 && !c2)
|
|
190 return true;
|
|
191 if (!c1 || !c2)
|
|
192 return return_false_with_msg ("one type is not polymorphic");
|
|
193 if (!types_must_be_same_for_odr (t1, t2))
|
|
194 return return_false_with_msg ("types are not same for ODR");
|
|
195 return true;
|
|
196 }
|
|
197
|
|
198 /* Return true if types are compatible from perspective of ICF. */
|
|
199 bool
|
|
200 func_checker::compatible_types_p (tree t1, tree t2)
|
|
201 {
|
|
202 if (TREE_CODE (t1) != TREE_CODE (t2))
|
|
203 return return_false_with_msg ("different tree types");
|
|
204
|
|
205 if (TYPE_RESTRICT (t1) != TYPE_RESTRICT (t2))
|
|
206 return return_false_with_msg ("restrict flags are different");
|
|
207
|
|
208 if (!types_compatible_p (t1, t2))
|
|
209 return return_false_with_msg ("types are not compatible");
|
|
210
|
|
211 return true;
|
|
212 }
|
|
213
|
|
214 /* Function compare for equality given trees T1 and T2 which
|
|
215 can be either a constant or a declaration type. */
|
|
216
|
145
|
217 void
|
|
218 func_checker::hash_operand (const_tree arg, inchash::hash &hstate,
|
|
219 unsigned int flags)
|
|
220 {
|
|
221 if (arg == NULL_TREE)
|
|
222 {
|
|
223 hstate.merge_hash (0);
|
|
224 return;
|
|
225 }
|
|
226
|
|
227 switch (TREE_CODE (arg))
|
|
228 {
|
|
229 case FUNCTION_DECL:
|
|
230 case VAR_DECL:
|
|
231 case LABEL_DECL:
|
|
232 case PARM_DECL:
|
|
233 case RESULT_DECL:
|
|
234 case CONST_DECL:
|
|
235 case SSA_NAME:
|
|
236 return;
|
|
237 case FIELD_DECL:
|
|
238 inchash::add_expr (DECL_FIELD_OFFSET (arg), hstate, flags);
|
|
239 inchash::add_expr (DECL_FIELD_BIT_OFFSET (arg), hstate, flags);
|
|
240 return;
|
|
241 default:
|
|
242 break;
|
|
243 }
|
|
244
|
|
245 return operand_compare::hash_operand (arg, hstate, flags);
|
|
246 }
|
|
247
|
111
|
248 bool
|
145
|
249 func_checker::operand_equal_p (const_tree t1, const_tree t2,
|
|
250 unsigned int flags)
|
111
|
251 {
|
145
|
252 bool r;
|
|
253 if (verify_hash_value (t1, t2, flags, &r))
|
|
254 return r;
|
|
255
|
|
256 if (t1 == t2)
|
|
257 return true;
|
|
258 else if (!t1 || !t2)
|
|
259 return false;
|
|
260
|
|
261 if (TREE_CODE (t1) != TREE_CODE (t2))
|
|
262 return return_false ();
|
111
|
263
|
|
264 switch (TREE_CODE (t1))
|
|
265 {
|
|
266 case FUNCTION_DECL:
|
|
267 /* All function decls are in the symbol table and known to match
|
|
268 before we start comparing bodies. */
|
|
269 return true;
|
|
270 case VAR_DECL:
|
|
271 return return_with_debug (compare_variable_decl (t1, t2));
|
|
272 case LABEL_DECL:
|
|
273 {
|
|
274 int *bb1 = m_label_bb_map.get (t1);
|
|
275 int *bb2 = m_label_bb_map.get (t2);
|
|
276 /* Labels can point to another function (non-local GOTOs). */
|
|
277 return return_with_debug (bb1 != NULL && bb2 != NULL && *bb1 == *bb2);
|
|
278 }
|
145
|
279
|
111
|
280 case PARM_DECL:
|
|
281 case RESULT_DECL:
|
|
282 case CONST_DECL:
|
145
|
283 return compare_decl (t1, t2);
|
|
284 case SSA_NAME:
|
|
285 return compare_ssa_name (t1, t2);
|
111
|
286 default:
|
145
|
287 break;
|
111
|
288 }
|
145
|
289
|
|
290 return operand_compare::operand_equal_p (t1, t2, flags);
|
111
|
291 }
|
|
292
|
|
293 /* Function responsible for comparison of various operands T1 and T2.
|
|
294 If these components, from functions FUNC1 and FUNC2, are equal, true
|
|
295 is returned. */
|
|
296
|
|
297 bool
|
|
298 func_checker::compare_operand (tree t1, tree t2)
|
|
299 {
|
|
300 if (!t1 && !t2)
|
|
301 return true;
|
|
302 else if (!t1 || !t2)
|
|
303 return false;
|
145
|
304 if (operand_equal_p (t1, t2, OEP_MATCH_SIDE_EFFECTS))
|
|
305 return true;
|
|
306 return return_false_with_msg ("operand_equal_p failed");
|
111
|
307 }
|
|
308
|
|
309 bool
|
|
310 func_checker::compare_asm_inputs_outputs (tree t1, tree t2)
|
|
311 {
|
|
312 gcc_assert (TREE_CODE (t1) == TREE_LIST);
|
|
313 gcc_assert (TREE_CODE (t2) == TREE_LIST);
|
|
314
|
|
315 for (; t1; t1 = TREE_CHAIN (t1))
|
|
316 {
|
|
317 if (!t2)
|
|
318 return false;
|
|
319
|
|
320 if (!compare_operand (TREE_VALUE (t1), TREE_VALUE (t2)))
|
|
321 return return_false ();
|
|
322
|
|
323 tree p1 = TREE_PURPOSE (t1);
|
|
324 tree p2 = TREE_PURPOSE (t2);
|
|
325
|
|
326 gcc_assert (TREE_CODE (p1) == TREE_LIST);
|
|
327 gcc_assert (TREE_CODE (p2) == TREE_LIST);
|
|
328
|
|
329 if (strcmp (TREE_STRING_POINTER (TREE_VALUE (p1)),
|
|
330 TREE_STRING_POINTER (TREE_VALUE (p2))) != 0)
|
|
331 return return_false ();
|
|
332
|
|
333 t2 = TREE_CHAIN (t2);
|
|
334 }
|
|
335
|
|
336 if (t2)
|
|
337 return return_false ();
|
|
338
|
|
339 return true;
|
|
340 }
|
|
341
|
|
342 /* Verifies that trees T1 and T2 do correspond. */
|
|
343
|
|
344 bool
|
145
|
345 func_checker::compare_variable_decl (const_tree t1, const_tree t2)
|
111
|
346 {
|
|
347 bool ret = false;
|
|
348
|
|
349 if (t1 == t2)
|
|
350 return true;
|
|
351
|
|
352 if (DECL_ALIGN (t1) != DECL_ALIGN (t2))
|
|
353 return return_false_with_msg ("alignments are different");
|
|
354
|
|
355 if (DECL_HARD_REGISTER (t1) != DECL_HARD_REGISTER (t2))
|
|
356 return return_false_with_msg ("DECL_HARD_REGISTER are different");
|
|
357
|
|
358 if (DECL_HARD_REGISTER (t1)
|
145
|
359 && DECL_ASSEMBLER_NAME_RAW (t1) != DECL_ASSEMBLER_NAME_RAW (t2))
|
111
|
360 return return_false_with_msg ("HARD REGISTERS are different");
|
|
361
|
|
362 /* Symbol table variables are known to match before we start comparing
|
|
363 bodies. */
|
|
364 if (decl_in_symtab_p (t1))
|
|
365 return decl_in_symtab_p (t2);
|
|
366 ret = compare_decl (t1, t2);
|
|
367
|
|
368 return return_with_debug (ret);
|
|
369 }
|
|
370
|
145
|
371 /* Compare loop information for basic blocks BB1 and BB2. */
|
|
372
|
|
373 bool
|
|
374 func_checker::compare_loops (basic_block bb1, basic_block bb2)
|
|
375 {
|
|
376 if ((bb1->loop_father == NULL) != (bb2->loop_father == NULL))
|
|
377 return return_false ();
|
|
378
|
|
379 class loop *l1 = bb1->loop_father;
|
|
380 class loop *l2 = bb2->loop_father;
|
|
381 if (l1 == NULL)
|
|
382 return true;
|
|
383
|
|
384 if ((bb1 == l1->header) != (bb2 == l2->header))
|
|
385 return return_false_with_msg ("header");
|
|
386 if ((bb1 == l1->latch) != (bb2 == l2->latch))
|
|
387 return return_false_with_msg ("latch");
|
|
388 if (l1->simdlen != l2->simdlen)
|
|
389 return return_false_with_msg ("simdlen");
|
|
390 if (l1->safelen != l2->safelen)
|
|
391 return return_false_with_msg ("safelen");
|
|
392 if (l1->can_be_parallel != l2->can_be_parallel)
|
|
393 return return_false_with_msg ("can_be_parallel");
|
|
394 if (l1->dont_vectorize != l2->dont_vectorize)
|
|
395 return return_false_with_msg ("dont_vectorize");
|
|
396 if (l1->force_vectorize != l2->force_vectorize)
|
|
397 return return_false_with_msg ("force_vectorize");
|
|
398 if (l1->unroll != l2->unroll)
|
|
399 return return_false_with_msg ("unroll");
|
|
400 if (!compare_variable_decl (l1->simduid, l2->simduid))
|
|
401 return return_false_with_msg ("simduid");
|
|
402
|
|
403 return true;
|
|
404 }
|
111
|
405
|
|
406 /* Function visits all gimple labels and creates corresponding
|
|
407 mapping between basic blocks and labels. */
|
|
408
|
|
409 void
|
|
410 func_checker::parse_labels (sem_bb *bb)
|
|
411 {
|
|
412 for (gimple_stmt_iterator gsi = gsi_start_bb (bb->bb); !gsi_end_p (gsi);
|
|
413 gsi_next (&gsi))
|
|
414 {
|
|
415 gimple *stmt = gsi_stmt (gsi);
|
|
416
|
|
417 if (glabel *label_stmt = dyn_cast <glabel *> (stmt))
|
|
418 {
|
145
|
419 const_tree t = gimple_label_label (label_stmt);
|
111
|
420 gcc_assert (TREE_CODE (t) == LABEL_DECL);
|
|
421
|
|
422 m_label_bb_map.put (t, bb->bb->index);
|
|
423 }
|
|
424 }
|
|
425 }
|
|
426
|
|
427 /* Basic block equivalence comparison function that returns true if
|
|
428 basic blocks BB1 and BB2 (from functions FUNC1 and FUNC2) correspond.
|
|
429
|
|
430 In general, a collection of equivalence dictionaries is built for types
|
|
431 like SSA names, declarations (VAR_DECL, PARM_DECL, ..). This infrastructure
|
|
432 is utilized by every statement-by-statement comparison function. */
|
|
433
|
|
434 bool
|
|
435 func_checker::compare_bb (sem_bb *bb1, sem_bb *bb2)
|
|
436 {
|
|
437 gimple_stmt_iterator gsi1, gsi2;
|
|
438 gimple *s1, *s2;
|
|
439
|
131
|
440 gsi1 = gsi_start_nondebug_bb (bb1->bb);
|
|
441 gsi2 = gsi_start_nondebug_bb (bb2->bb);
|
111
|
442
|
|
443 while (!gsi_end_p (gsi1))
|
|
444 {
|
|
445 if (gsi_end_p (gsi2))
|
|
446 return return_false ();
|
|
447
|
|
448 s1 = gsi_stmt (gsi1);
|
|
449 s2 = gsi_stmt (gsi2);
|
|
450
|
|
451 int eh1 = lookup_stmt_eh_lp_fn
|
|
452 (DECL_STRUCT_FUNCTION (m_source_func_decl), s1);
|
|
453 int eh2 = lookup_stmt_eh_lp_fn
|
|
454 (DECL_STRUCT_FUNCTION (m_target_func_decl), s2);
|
|
455
|
|
456 if (eh1 != eh2)
|
|
457 return return_false_with_msg ("EH regions are different");
|
|
458
|
|
459 if (gimple_code (s1) != gimple_code (s2))
|
|
460 return return_false_with_msg ("gimple codes are different");
|
|
461
|
|
462 switch (gimple_code (s1))
|
|
463 {
|
|
464 case GIMPLE_CALL:
|
|
465 if (!compare_gimple_call (as_a <gcall *> (s1),
|
|
466 as_a <gcall *> (s2)))
|
|
467 return return_different_stmts (s1, s2, "GIMPLE_CALL");
|
|
468 break;
|
|
469 case GIMPLE_ASSIGN:
|
|
470 if (!compare_gimple_assign (s1, s2))
|
|
471 return return_different_stmts (s1, s2, "GIMPLE_ASSIGN");
|
|
472 break;
|
|
473 case GIMPLE_COND:
|
|
474 if (!compare_gimple_cond (s1, s2))
|
|
475 return return_different_stmts (s1, s2, "GIMPLE_COND");
|
|
476 break;
|
|
477 case GIMPLE_SWITCH:
|
|
478 if (!compare_gimple_switch (as_a <gswitch *> (s1),
|
|
479 as_a <gswitch *> (s2)))
|
|
480 return return_different_stmts (s1, s2, "GIMPLE_SWITCH");
|
|
481 break;
|
|
482 case GIMPLE_DEBUG:
|
|
483 break;
|
|
484 case GIMPLE_EH_DISPATCH:
|
|
485 if (gimple_eh_dispatch_region (as_a <geh_dispatch *> (s1))
|
|
486 != gimple_eh_dispatch_region (as_a <geh_dispatch *> (s2)))
|
|
487 return return_different_stmts (s1, s2, "GIMPLE_EH_DISPATCH");
|
|
488 break;
|
|
489 case GIMPLE_RESX:
|
|
490 if (!compare_gimple_resx (as_a <gresx *> (s1),
|
|
491 as_a <gresx *> (s2)))
|
|
492 return return_different_stmts (s1, s2, "GIMPLE_RESX");
|
|
493 break;
|
|
494 case GIMPLE_LABEL:
|
|
495 if (!compare_gimple_label (as_a <glabel *> (s1),
|
|
496 as_a <glabel *> (s2)))
|
|
497 return return_different_stmts (s1, s2, "GIMPLE_LABEL");
|
|
498 break;
|
|
499 case GIMPLE_RETURN:
|
|
500 if (!compare_gimple_return (as_a <greturn *> (s1),
|
|
501 as_a <greturn *> (s2)))
|
|
502 return return_different_stmts (s1, s2, "GIMPLE_RETURN");
|
|
503 break;
|
|
504 case GIMPLE_GOTO:
|
|
505 if (!compare_gimple_goto (s1, s2))
|
|
506 return return_different_stmts (s1, s2, "GIMPLE_GOTO");
|
|
507 break;
|
|
508 case GIMPLE_ASM:
|
|
509 if (!compare_gimple_asm (as_a <gasm *> (s1),
|
|
510 as_a <gasm *> (s2)))
|
|
511 return return_different_stmts (s1, s2, "GIMPLE_ASM");
|
|
512 break;
|
|
513 case GIMPLE_PREDICT:
|
|
514 case GIMPLE_NOP:
|
|
515 break;
|
|
516 default:
|
|
517 return return_false_with_msg ("Unknown GIMPLE code reached");
|
|
518 }
|
|
519
|
|
520 gsi_next_nondebug (&gsi1);
|
|
521 gsi_next_nondebug (&gsi2);
|
|
522 }
|
|
523
|
|
524 if (!gsi_end_p (gsi2))
|
|
525 return return_false ();
|
|
526
|
145
|
527 if (!compare_loops (bb1->bb, bb2->bb))
|
|
528 return return_false ();
|
|
529
|
111
|
530 return true;
|
|
531 }
|
|
532
|
|
533 /* Verifies for given GIMPLEs S1 and S2 that
|
|
534 call statements are semantically equivalent. */
|
|
535
|
|
536 bool
|
|
537 func_checker::compare_gimple_call (gcall *s1, gcall *s2)
|
|
538 {
|
|
539 unsigned i;
|
|
540 tree t1, t2;
|
|
541
|
|
542 if (gimple_call_num_args (s1) != gimple_call_num_args (s2))
|
|
543 return false;
|
|
544
|
|
545 t1 = gimple_call_fn (s1);
|
|
546 t2 = gimple_call_fn (s2);
|
|
547 if (!compare_operand (t1, t2))
|
|
548 return return_false ();
|
|
549
|
|
550 /* Compare flags. */
|
|
551 if (gimple_call_internal_p (s1) != gimple_call_internal_p (s2)
|
|
552 || gimple_call_ctrl_altering_p (s1) != gimple_call_ctrl_altering_p (s2)
|
|
553 || gimple_call_tail_p (s1) != gimple_call_tail_p (s2)
|
|
554 || gimple_call_return_slot_opt_p (s1) != gimple_call_return_slot_opt_p (s2)
|
|
555 || gimple_call_from_thunk_p (s1) != gimple_call_from_thunk_p (s2)
|
|
556 || gimple_call_va_arg_pack_p (s1) != gimple_call_va_arg_pack_p (s2)
|
131
|
557 || gimple_call_alloca_for_var_p (s1) != gimple_call_alloca_for_var_p (s2))
|
111
|
558 return false;
|
|
559
|
|
560 if (gimple_call_internal_p (s1)
|
|
561 && gimple_call_internal_fn (s1) != gimple_call_internal_fn (s2))
|
|
562 return false;
|
|
563
|
|
564 tree fntype1 = gimple_call_fntype (s1);
|
|
565 tree fntype2 = gimple_call_fntype (s2);
|
|
566 if ((fntype1 && !fntype2)
|
|
567 || (!fntype1 && fntype2)
|
|
568 || (fntype1 && !types_compatible_p (fntype1, fntype2)))
|
|
569 return return_false_with_msg ("call function types are not compatible");
|
|
570
|
|
571 tree chain1 = gimple_call_chain (s1);
|
|
572 tree chain2 = gimple_call_chain (s2);
|
|
573 if ((chain1 && !chain2)
|
|
574 || (!chain1 && chain2)
|
|
575 || !compare_operand (chain1, chain2))
|
|
576 return return_false_with_msg ("static call chains are different");
|
|
577
|
|
578 /* Checking of argument. */
|
|
579 for (i = 0; i < gimple_call_num_args (s1); ++i)
|
|
580 {
|
|
581 t1 = gimple_call_arg (s1, i);
|
|
582 t2 = gimple_call_arg (s2, i);
|
|
583
|
145
|
584 if (!compare_operand (t1, t2))
|
|
585 return return_false_with_msg ("GIMPLE call operands are different");
|
111
|
586 }
|
|
587
|
|
588 /* Return value checking. */
|
|
589 t1 = gimple_get_lhs (s1);
|
|
590 t2 = gimple_get_lhs (s2);
|
|
591
|
145
|
592 return compare_operand (t1, t2);
|
111
|
593 }
|
|
594
|
|
595
|
|
596 /* Verifies for given GIMPLEs S1 and S2 that
|
|
597 assignment statements are semantically equivalent. */
|
|
598
|
|
599 bool
|
|
600 func_checker::compare_gimple_assign (gimple *s1, gimple *s2)
|
|
601 {
|
|
602 tree arg1, arg2;
|
|
603 tree_code code1, code2;
|
|
604 unsigned i;
|
|
605
|
|
606 code1 = gimple_expr_code (s1);
|
|
607 code2 = gimple_expr_code (s2);
|
|
608
|
|
609 if (code1 != code2)
|
|
610 return false;
|
|
611
|
|
612 code1 = gimple_assign_rhs_code (s1);
|
|
613 code2 = gimple_assign_rhs_code (s2);
|
|
614
|
|
615 if (code1 != code2)
|
|
616 return false;
|
|
617
|
|
618 for (i = 0; i < gimple_num_ops (s1); i++)
|
|
619 {
|
|
620 arg1 = gimple_op (s1, i);
|
|
621 arg2 = gimple_op (s2, i);
|
|
622
|
145
|
623 /* LHS types of NOP_EXPR must be compatible. */
|
|
624 if (CONVERT_EXPR_CODE_P (code1) && i == 0)
|
|
625 {
|
|
626 if (!compatible_types_p (TREE_TYPE (arg1), TREE_TYPE (arg2)))
|
|
627 return return_false_with_msg ("GIMPLE NOP LHS type mismatch");
|
|
628 }
|
|
629
|
|
630 if (!compare_operand (arg1, arg2))
|
|
631 return return_false_with_msg ("GIMPLE assignment operands "
|
|
632 "are different");
|
111
|
633 }
|
|
634
|
|
635
|
|
636 return true;
|
|
637 }
|
|
638
|
|
639 /* Verifies for given GIMPLEs S1 and S2 that
|
|
640 condition statements are semantically equivalent. */
|
|
641
|
|
642 bool
|
|
643 func_checker::compare_gimple_cond (gimple *s1, gimple *s2)
|
|
644 {
|
|
645 tree t1, t2;
|
|
646 tree_code code1, code2;
|
|
647
|
|
648 code1 = gimple_expr_code (s1);
|
|
649 code2 = gimple_expr_code (s2);
|
|
650
|
|
651 if (code1 != code2)
|
|
652 return false;
|
|
653
|
|
654 t1 = gimple_cond_lhs (s1);
|
|
655 t2 = gimple_cond_lhs (s2);
|
|
656
|
|
657 if (!compare_operand (t1, t2))
|
|
658 return false;
|
|
659
|
|
660 t1 = gimple_cond_rhs (s1);
|
|
661 t2 = gimple_cond_rhs (s2);
|
|
662
|
|
663 return compare_operand (t1, t2);
|
|
664 }
|
|
665
|
|
666 /* Verifies for given GIMPLE_LABEL stmts S1 and S2 that
|
|
667 label statements are semantically equivalent. */
|
|
668
|
|
669 bool
|
|
670 func_checker::compare_gimple_label (const glabel *g1, const glabel *g2)
|
|
671 {
|
|
672 if (m_ignore_labels)
|
|
673 return true;
|
|
674
|
|
675 tree t1 = gimple_label_label (g1);
|
|
676 tree t2 = gimple_label_label (g2);
|
|
677
|
|
678 if (FORCED_LABEL (t1) || FORCED_LABEL (t2))
|
|
679 return return_false_with_msg ("FORCED_LABEL");
|
|
680
|
|
681 /* As the pass build BB to label mapping, no further check is needed. */
|
|
682 return true;
|
|
683 }
|
|
684
|
|
685 /* Verifies for given GIMPLE_SWITCH stmts S1 and S2 that
|
|
686 switch statements are semantically equivalent. */
|
|
687
|
|
688 bool
|
|
689 func_checker::compare_gimple_switch (const gswitch *g1, const gswitch *g2)
|
|
690 {
|
|
691 unsigned lsize1, lsize2, i;
|
|
692
|
|
693 lsize1 = gimple_switch_num_labels (g1);
|
|
694 lsize2 = gimple_switch_num_labels (g2);
|
|
695
|
|
696 if (lsize1 != lsize2)
|
|
697 return false;
|
|
698
|
|
699 tree t1 = gimple_switch_index (g1);
|
|
700 tree t2 = gimple_switch_index (g2);
|
|
701
|
|
702 if (!compare_operand (t1, t2))
|
|
703 return false;
|
|
704
|
|
705 for (i = 0; i < lsize1; i++)
|
|
706 {
|
|
707 tree label1 = gimple_switch_label (g1, i);
|
|
708 tree label2 = gimple_switch_label (g2, i);
|
|
709
|
|
710 /* Label LOW and HIGH comparison. */
|
|
711 tree low1 = CASE_LOW (label1);
|
|
712 tree low2 = CASE_LOW (label2);
|
|
713
|
|
714 if (!tree_int_cst_equal (low1, low2))
|
|
715 return return_false_with_msg ("case low values are different");
|
|
716
|
|
717 tree high1 = CASE_HIGH (label1);
|
|
718 tree high2 = CASE_HIGH (label2);
|
|
719
|
|
720 if (!tree_int_cst_equal (high1, high2))
|
|
721 return return_false_with_msg ("case high values are different");
|
|
722
|
|
723 if (TREE_CODE (label1) == CASE_LABEL_EXPR
|
|
724 && TREE_CODE (label2) == CASE_LABEL_EXPR)
|
|
725 {
|
|
726 label1 = CASE_LABEL (label1);
|
|
727 label2 = CASE_LABEL (label2);
|
|
728
|
|
729 if (!compare_operand (label1, label2))
|
|
730 return return_false_with_msg ("switch label_exprs are different");
|
|
731 }
|
|
732 else if (!tree_int_cst_equal (label1, label2))
|
|
733 return return_false_with_msg ("switch labels are different");
|
|
734 }
|
|
735
|
|
736 return true;
|
|
737 }
|
|
738
|
|
739 /* Verifies for given GIMPLE_RETURN stmts S1 and S2 that
|
|
740 return statements are semantically equivalent. */
|
|
741
|
|
742 bool
|
|
743 func_checker::compare_gimple_return (const greturn *g1, const greturn *g2)
|
|
744 {
|
|
745 tree t1, t2;
|
|
746
|
|
747 t1 = gimple_return_retval (g1);
|
|
748 t2 = gimple_return_retval (g2);
|
|
749
|
|
750 /* Void return type. */
|
|
751 if (t1 == NULL && t2 == NULL)
|
|
752 return true;
|
|
753 else
|
|
754 return compare_operand (t1, t2);
|
|
755 }
|
|
756
|
|
757 /* Verifies for given GIMPLEs S1 and S2 that
|
|
758 goto statements are semantically equivalent. */
|
|
759
|
|
760 bool
|
|
761 func_checker::compare_gimple_goto (gimple *g1, gimple *g2)
|
|
762 {
|
|
763 tree dest1, dest2;
|
|
764
|
|
765 dest1 = gimple_goto_dest (g1);
|
|
766 dest2 = gimple_goto_dest (g2);
|
|
767
|
|
768 if (TREE_CODE (dest1) != TREE_CODE (dest2) || TREE_CODE (dest1) != SSA_NAME)
|
|
769 return false;
|
|
770
|
|
771 return compare_operand (dest1, dest2);
|
|
772 }
|
|
773
|
|
774 /* Verifies for given GIMPLE_RESX stmts S1 and S2 that
|
|
775 resx statements are semantically equivalent. */
|
|
776
|
|
777 bool
|
|
778 func_checker::compare_gimple_resx (const gresx *g1, const gresx *g2)
|
|
779 {
|
|
780 return gimple_resx_region (g1) == gimple_resx_region (g2);
|
|
781 }
|
|
782
|
|
783 /* Verifies for given GIMPLEs S1 and S2 that ASM statements are equivalent.
|
|
784 For the beginning, the pass only supports equality for
|
|
785 '__asm__ __volatile__ ("", "", "", "memory")'. */
|
|
786
|
|
787 bool
|
|
788 func_checker::compare_gimple_asm (const gasm *g1, const gasm *g2)
|
|
789 {
|
|
790 if (gimple_asm_volatile_p (g1) != gimple_asm_volatile_p (g2))
|
|
791 return false;
|
|
792
|
|
793 if (gimple_asm_input_p (g1) != gimple_asm_input_p (g2))
|
|
794 return false;
|
|
795
|
145
|
796 if (gimple_asm_inline_p (g1) != gimple_asm_inline_p (g2))
|
|
797 return false;
|
|
798
|
111
|
799 if (gimple_asm_ninputs (g1) != gimple_asm_ninputs (g2))
|
|
800 return false;
|
|
801
|
|
802 if (gimple_asm_noutputs (g1) != gimple_asm_noutputs (g2))
|
|
803 return false;
|
|
804
|
|
805 /* We do not suppport goto ASM statement comparison. */
|
|
806 if (gimple_asm_nlabels (g1) || gimple_asm_nlabels (g2))
|
|
807 return false;
|
|
808
|
|
809 if (gimple_asm_nclobbers (g1) != gimple_asm_nclobbers (g2))
|
|
810 return false;
|
|
811
|
|
812 if (strcmp (gimple_asm_string (g1), gimple_asm_string (g2)) != 0)
|
|
813 return return_false_with_msg ("ASM strings are different");
|
|
814
|
|
815 for (unsigned i = 0; i < gimple_asm_ninputs (g1); i++)
|
|
816 {
|
|
817 tree input1 = gimple_asm_input_op (g1, i);
|
|
818 tree input2 = gimple_asm_input_op (g2, i);
|
|
819
|
|
820 if (!compare_asm_inputs_outputs (input1, input2))
|
|
821 return return_false_with_msg ("ASM input is different");
|
|
822 }
|
|
823
|
|
824 for (unsigned i = 0; i < gimple_asm_noutputs (g1); i++)
|
|
825 {
|
|
826 tree output1 = gimple_asm_output_op (g1, i);
|
|
827 tree output2 = gimple_asm_output_op (g2, i);
|
|
828
|
|
829 if (!compare_asm_inputs_outputs (output1, output2))
|
|
830 return return_false_with_msg ("ASM output is different");
|
|
831 }
|
|
832
|
|
833 for (unsigned i = 0; i < gimple_asm_nclobbers (g1); i++)
|
|
834 {
|
|
835 tree clobber1 = gimple_asm_clobber_op (g1, i);
|
|
836 tree clobber2 = gimple_asm_clobber_op (g2, i);
|
|
837
|
|
838 if (!operand_equal_p (TREE_VALUE (clobber1), TREE_VALUE (clobber2),
|
|
839 OEP_ONLY_CONST))
|
|
840 return return_false_with_msg ("ASM clobber is different");
|
|
841 }
|
|
842
|
|
843 return true;
|
|
844 }
|
|
845
|
|
846 } // ipa_icf_gimple namespace
|