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