Mercurial > hg > CbC > CbC_gcc
comparison gcc/ipa-inline-transform.c @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
comparison
equal
deleted
inserted
replaced
131:84e7813d76e9 | 145:1830386684a0 |
---|---|
1 /* Callgraph transformations to handle inlining | 1 /* Callgraph transformations to handle inlining |
2 Copyright (C) 2003-2018 Free Software Foundation, Inc. | 2 Copyright (C) 2003-2020 Free Software Foundation, Inc. |
3 Contributed by Jan Hubicka | 3 Contributed by Jan Hubicka |
4 | 4 |
5 This file is part of GCC. | 5 This file is part of GCC. |
6 | 6 |
7 GCC is free software; you can redistribute it and/or modify it under | 7 GCC is free software; you can redistribute it and/or modify it under |
45 #include "ipa-inline.h" | 45 #include "ipa-inline.h" |
46 #include "tree-inline.h" | 46 #include "tree-inline.h" |
47 #include "function.h" | 47 #include "function.h" |
48 #include "cfg.h" | 48 #include "cfg.h" |
49 #include "basic-block.h" | 49 #include "basic-block.h" |
50 #include "ipa-utils.h" | |
50 | 51 |
51 int ncalls_inlined; | 52 int ncalls_inlined; |
52 int nfunctions_inlined; | 53 int nfunctions_inlined; |
53 | 54 |
54 /* Scale counts of NODE edges by NUM/DEN. */ | 55 /* Scale counts of NODE edges by NUM/DEN. */ |
102 Lacking may edges in callgraph we just preserve them post | 103 Lacking may edges in callgraph we just preserve them post |
103 inlining. */ | 104 inlining. */ |
104 && (!DECL_VIRTUAL_P (node->decl) | 105 && (!DECL_VIRTUAL_P (node->decl) |
105 || !opt_for_fn (node->decl, flag_devirtualize)) | 106 || !opt_for_fn (node->decl, flag_devirtualize)) |
106 /* During early inlining some unanalyzed cgraph nodes might be in the | 107 /* During early inlining some unanalyzed cgraph nodes might be in the |
107 callgraph and they might reffer the function in question. */ | 108 callgraph and they might refer the function in question. */ |
108 && !cgraph_new_nodes.exists ()); | 109 && !cgraph_new_nodes.exists ()); |
109 } | 110 } |
110 | 111 |
111 /* We are going to eliminate last direct call to NODE (or alias of it) via edge E. | 112 /* We are going to eliminate last direct call to NODE (or alias of it) via edge E. |
112 Verify that the NODE can be removed from unit and if it is contained in comdat | 113 Verify that the NODE can be removed from unit and if it is contained in comdat |
164 bool update_original, int *overall_size) | 165 bool update_original, int *overall_size) |
165 { | 166 { |
166 struct cgraph_node *inlining_into; | 167 struct cgraph_node *inlining_into; |
167 struct cgraph_edge *next; | 168 struct cgraph_edge *next; |
168 | 169 |
169 if (e->caller->global.inlined_to) | 170 if (e->caller->inlined_to) |
170 inlining_into = e->caller->global.inlined_to; | 171 inlining_into = e->caller->inlined_to; |
171 else | 172 else |
172 inlining_into = e->caller; | 173 inlining_into = e->caller; |
173 | 174 |
174 if (duplicate) | 175 if (duplicate) |
175 { | 176 { |
176 /* We may eliminate the need for out-of-line copy to be output. | 177 /* We may eliminate the need for out-of-line copy to be output. |
177 In that case just go ahead and re-use it. This is not just an | 178 In that case just go ahead and re-use it. This is not just an |
178 memory optimization. Making offline copy of fuction disappear | 179 memory optimization. Making offline copy of function disappear |
179 from the program will improve future decisions on inlining. */ | 180 from the program will improve future decisions on inlining. */ |
180 if (!e->callee->callers->next_caller | 181 if (!e->callee->callers->next_caller |
181 /* Recursive inlining never wants the master clone to | 182 /* Recursive inlining never wants the master clone to |
182 be overwritten. */ | 183 be overwritten. */ |
183 && update_original | 184 && update_original |
189 /* TODO: When callee is in a comdat group, we could remove all of it, | 190 /* TODO: When callee is in a comdat group, we could remove all of it, |
190 including all inline clones inlined into it. That would however | 191 including all inline clones inlined into it. That would however |
191 need small function inlining to register edge removal hook to | 192 need small function inlining to register edge removal hook to |
192 maintain the priority queue. | 193 maintain the priority queue. |
193 | 194 |
194 For now we keep the ohter functions in the group in program until | 195 For now we keep the other functions in the group in program until |
195 cgraph_remove_unreachable_functions gets rid of them. */ | 196 cgraph_remove_unreachable_functions gets rid of them. */ |
196 gcc_assert (!e->callee->global.inlined_to); | 197 gcc_assert (!e->callee->inlined_to); |
197 e->callee->remove_from_same_comdat_group (); | 198 e->callee->remove_from_same_comdat_group (); |
198 if (e->callee->definition | 199 if (e->callee->definition |
199 && inline_account_function_p (e->callee)) | 200 && inline_account_function_p (e->callee)) |
200 { | 201 { |
201 gcc_assert (!e->callee->alias); | 202 gcc_assert (!e->callee->alias); |
202 if (overall_size) | 203 if (overall_size) |
203 *overall_size -= ipa_fn_summaries->get (e->callee)->size; | 204 *overall_size -= ipa_size_summaries->get (e->callee)->size; |
204 nfunctions_inlined++; | 205 nfunctions_inlined++; |
205 } | 206 } |
206 duplicate = false; | 207 duplicate = false; |
207 e->callee->externally_visible = false; | 208 e->callee->externally_visible = false; |
208 update_noncloned_counts (e->callee, e->count, e->callee->count); | 209 update_noncloned_counts (e->callee, e->count, e->callee->count); |
224 } | 225 } |
225 } | 226 } |
226 else | 227 else |
227 e->callee->remove_from_same_comdat_group (); | 228 e->callee->remove_from_same_comdat_group (); |
228 | 229 |
229 e->callee->global.inlined_to = inlining_into; | 230 e->callee->inlined_to = inlining_into; |
230 | 231 |
231 /* Recursively clone all bodies. */ | 232 /* Recursively clone all bodies. */ |
232 for (e = e->callee->callees; e; e = next) | 233 for (e = e->callee->callees; e; e = next) |
233 { | 234 { |
234 next = e->next_callee; | 235 next = e->next_callee; |
235 if (!e->inline_failed) | 236 if (!e->inline_failed) |
236 clone_inlined_nodes (e, duplicate, update_original, overall_size); | 237 clone_inlined_nodes (e, duplicate, update_original, overall_size); |
237 } | 238 } |
238 } | 239 } |
239 | 240 |
240 /* Check all speculations in N and resolve them if they seems useless. */ | 241 /* Check all speculations in N and if any seem useless, resolve them. When a |
242 first edge is resolved, pop all edges from NEW_EDGES and insert them to | |
243 EDGE_SET. Then remove each resolved edge from EDGE_SET, if it is there. */ | |
241 | 244 |
242 static bool | 245 static bool |
243 check_speculations (cgraph_node *n) | 246 check_speculations_1 (cgraph_node *n, vec<cgraph_edge *> *new_edges, |
247 hash_set <cgraph_edge *> *edge_set) | |
244 { | 248 { |
245 bool speculation_removed = false; | 249 bool speculation_removed = false; |
246 cgraph_edge *next; | 250 cgraph_edge *next; |
247 | 251 |
248 for (cgraph_edge *e = n->callees; e; e = next) | 252 for (cgraph_edge *e = n->callees; e; e = next) |
249 { | 253 { |
250 next = e->next_callee; | 254 next = e->next_callee; |
251 if (e->speculative && !speculation_useful_p (e, true)) | 255 if (e->speculative && !speculation_useful_p (e, true)) |
252 { | 256 { |
253 e->resolve_speculation (NULL); | 257 while (new_edges && !new_edges->is_empty ()) |
258 edge_set->add (new_edges->pop ()); | |
259 edge_set->remove (e); | |
260 | |
261 cgraph_edge::resolve_speculation (e, NULL); | |
254 speculation_removed = true; | 262 speculation_removed = true; |
255 } | 263 } |
256 else if (!e->inline_failed) | 264 else if (!e->inline_failed) |
257 speculation_removed |= check_speculations (e->callee); | 265 speculation_removed |= check_speculations_1 (e->callee, new_edges, |
266 edge_set); | |
258 } | 267 } |
259 return speculation_removed; | 268 return speculation_removed; |
269 } | |
270 | |
271 /* Push E to NEW_EDGES. Called from hash_set traverse method, which | |
272 unfortunately means this function has to have external linkage, otherwise | |
273 the code will not compile with gcc 4.8. */ | |
274 | |
275 bool | |
276 push_all_edges_in_set_to_vec (cgraph_edge * const &e, | |
277 vec<cgraph_edge *> *new_edges) | |
278 { | |
279 new_edges->safe_push (e); | |
280 return true; | |
281 } | |
282 | |
283 /* Check all speculations in N and if any seem useless, resolve them and remove | |
284 them from NEW_EDGES. */ | |
285 | |
286 static bool | |
287 check_speculations (cgraph_node *n, vec<cgraph_edge *> *new_edges) | |
288 { | |
289 hash_set <cgraph_edge *> edge_set; | |
290 bool res = check_speculations_1 (n, new_edges, &edge_set); | |
291 if (!edge_set.is_empty ()) | |
292 edge_set.traverse <vec<cgraph_edge *> *, | |
293 push_all_edges_in_set_to_vec> (new_edges); | |
294 return res; | |
260 } | 295 } |
261 | 296 |
262 /* Mark all call graph edges coming out of NODE and all nodes that have been | 297 /* Mark all call graph edges coming out of NODE and all nodes that have been |
263 inlined to it as in_polymorphic_cdtor. */ | 298 inlined to it as in_polymorphic_cdtor. */ |
264 | 299 |
294 bool *callee_removed) | 329 bool *callee_removed) |
295 { | 330 { |
296 int old_size = 0, new_size = 0; | 331 int old_size = 0, new_size = 0; |
297 struct cgraph_node *to = NULL; | 332 struct cgraph_node *to = NULL; |
298 struct cgraph_edge *curr = e; | 333 struct cgraph_edge *curr = e; |
334 bool comdat_local = e->callee->comdat_local_p (); | |
299 struct cgraph_node *callee = e->callee->ultimate_alias_target (); | 335 struct cgraph_node *callee = e->callee->ultimate_alias_target (); |
300 bool new_edges_found = false; | 336 bool new_edges_found = false; |
301 | 337 |
302 int estimated_growth = 0; | 338 int estimated_growth = 0; |
303 if (! update_overall_summary) | 339 if (! update_overall_summary) |
308 #endif | 344 #endif |
309 | 345 |
310 /* Don't inline inlined edges. */ | 346 /* Don't inline inlined edges. */ |
311 gcc_assert (e->inline_failed); | 347 gcc_assert (e->inline_failed); |
312 /* Don't even think of inlining inline clone. */ | 348 /* Don't even think of inlining inline clone. */ |
313 gcc_assert (!callee->global.inlined_to); | 349 gcc_assert (!callee->inlined_to); |
314 | 350 |
315 to = e->caller; | 351 to = e->caller; |
316 if (to->global.inlined_to) | 352 if (to->inlined_to) |
317 to = to->global.inlined_to; | 353 to = to->inlined_to; |
318 if (to->thunk.thunk_p) | 354 if (to->thunk.thunk_p) |
319 { | 355 { |
320 struct cgraph_node *target = to->callees->callee; | 356 struct cgraph_node *target = to->callees->callee; |
357 thunk_expansion = true; | |
358 symtab->call_cgraph_removal_hooks (to); | |
321 if (in_lto_p) | 359 if (in_lto_p) |
322 to->get_untransformed_body (); | 360 to->get_untransformed_body (); |
323 to->expand_thunk (false, true); | 361 to->expand_thunk (false, true); |
324 /* When thunk is instrumented we may have multiple callees. */ | 362 /* When thunk is instrumented we may have multiple callees. */ |
325 for (e = to->callees; e && e->callee != target; e = e->next_callee) | 363 for (e = to->callees; e && e->callee != target; e = e->next_callee) |
326 ; | 364 ; |
365 symtab->call_cgraph_insertion_hooks (to); | |
366 thunk_expansion = false; | |
327 gcc_assert (e); | 367 gcc_assert (e); |
328 } | 368 } |
329 | 369 |
330 | 370 |
331 e->inline_failed = CIF_OK; | 371 e->inline_failed = CIF_OK; |
440 } | 480 } |
441 } | 481 } |
442 | 482 |
443 clone_inlined_nodes (e, true, update_original, overall_size); | 483 clone_inlined_nodes (e, true, update_original, overall_size); |
444 | 484 |
445 gcc_assert (curr->callee->global.inlined_to == to); | 485 gcc_assert (curr->callee->inlined_to == to); |
446 | 486 |
447 old_size = ipa_fn_summaries->get (to)->size; | 487 old_size = ipa_size_summaries->get (to)->size; |
448 ipa_merge_fn_summary_after_inlining (e); | 488 ipa_merge_fn_summary_after_inlining (e); |
449 if (e->in_polymorphic_cdtor) | 489 if (e->in_polymorphic_cdtor) |
450 mark_all_inlined_calls_cdtor (e->callee); | 490 mark_all_inlined_calls_cdtor (e->callee); |
451 if (opt_for_fn (e->caller->decl, optimize)) | 491 if (opt_for_fn (e->caller->decl, optimize)) |
452 new_edges_found = ipa_propagate_indirect_call_infos (curr, new_edges); | 492 new_edges_found = ipa_propagate_indirect_call_infos (curr, new_edges); |
453 check_speculations (e->callee); | 493 bool removed_p = check_speculations (e->callee, new_edges); |
454 if (update_overall_summary) | 494 if (update_overall_summary) |
455 ipa_update_overall_fn_summary (to); | 495 ipa_update_overall_fn_summary (to, new_edges_found || removed_p); |
456 else | 496 else |
457 /* Update self size by the estimate so overall function growth limits | 497 /* Update self size by the estimate so overall function growth limits |
458 work for further inlining into this function. Before inlining | 498 work for further inlining into this function. Before inlining |
459 the function we inlined to again we expect the caller to update | 499 the function we inlined to again we expect the caller to update |
460 the overall summary. */ | 500 the overall summary. */ |
461 ipa_fn_summaries->get (to)->size += estimated_growth; | 501 ipa_size_summaries->get (to)->size += estimated_growth; |
462 new_size = ipa_fn_summaries->get (to)->size; | 502 new_size = ipa_size_summaries->get (to)->size; |
463 | 503 |
464 if (callee->calls_comdat_local) | 504 if (callee->calls_comdat_local) |
465 to->calls_comdat_local = true; | 505 to->calls_comdat_local = true; |
466 else if (to->calls_comdat_local && callee->comdat_local_p ()) | 506 else if (to->calls_comdat_local && comdat_local) |
467 { | 507 { |
468 struct cgraph_edge *se = to->callees; | 508 struct cgraph_edge *se = to->callees; |
469 for (; se; se = se->next_callee) | 509 for (; se; se = se->next_callee) |
470 if (se->inline_failed && se->callee->comdat_local_p ()) | 510 if (se->inline_failed && se->callee->comdat_local_p ()) |
471 break; | 511 break; |
511 { | 551 { |
512 struct cgraph_node *first_clone, *n; | 552 struct cgraph_node *first_clone, *n; |
513 | 553 |
514 if (dump_file) | 554 if (dump_file) |
515 fprintf (dump_file, "\nSaving body of %s for later reuse\n", | 555 fprintf (dump_file, "\nSaving body of %s for later reuse\n", |
516 node->name ()); | 556 node->dump_name ()); |
517 | 557 |
518 gcc_assert (node == cgraph_node::get (node->decl)); | 558 gcc_assert (node == cgraph_node::get (node->decl)); |
519 | 559 |
520 /* first_clone will be turned into real function. */ | 560 /* first_clone will be turned into real function. */ |
521 first_clone = node->clones; | 561 first_clone = node->clones; |
581 } | 621 } |
582 } | 622 } |
583 | 623 |
584 /* Copy the OLD_VERSION_NODE function tree to the new version. */ | 624 /* Copy the OLD_VERSION_NODE function tree to the new version. */ |
585 tree_function_versioning (node->decl, first_clone->decl, | 625 tree_function_versioning (node->decl, first_clone->decl, |
586 NULL, true, NULL, false, | 626 NULL, NULL, true, NULL, NULL); |
587 NULL, NULL); | |
588 | 627 |
589 /* The function will be short lived and removed after we inline all the clones, | 628 /* The function will be short lived and removed after we inline all the clones, |
590 but make it internal so we won't confuse ourself. */ | 629 but make it internal so we won't confuse ourself. */ |
591 DECL_EXTERNAL (first_clone->decl) = 0; | 630 DECL_EXTERNAL (first_clone->decl) = 0; |
592 TREE_PUBLIC (first_clone->decl) = 0; | 631 TREE_PUBLIC (first_clone->decl) = 0; |
594 first_clone->ipa_transforms_to_apply.release (); | 633 first_clone->ipa_transforms_to_apply.release (); |
595 | 634 |
596 /* When doing recursive inlining, the clone may become unnecessary. | 635 /* When doing recursive inlining, the clone may become unnecessary. |
597 This is possible i.e. in the case when the recursive function is proved to be | 636 This is possible i.e. in the case when the recursive function is proved to be |
598 non-throwing and the recursion happens only in the EH landing pad. | 637 non-throwing and the recursion happens only in the EH landing pad. |
599 We can not remove the clone until we are done with saving the body. | 638 We cannot remove the clone until we are done with saving the body. |
600 Remove it now. */ | 639 Remove it now. */ |
601 if (!first_clone->callers) | 640 if (!first_clone->callers) |
602 { | 641 { |
603 first_clone->remove_symbol_and_inline_clones (); | 642 first_clone->remove_symbol_and_inline_clones (); |
604 first_clone = NULL; | 643 first_clone = NULL; |
641 /* We might need the body of this function so that we can expand | 680 /* We might need the body of this function so that we can expand |
642 it inline somewhere else. */ | 681 it inline somewhere else. */ |
643 if (preserve_function_body_p (node)) | 682 if (preserve_function_body_p (node)) |
644 save_inline_function_body (node); | 683 save_inline_function_body (node); |
645 | 684 |
685 profile_count num = node->count; | |
686 profile_count den = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count; | |
687 bool scale = num.initialized_p () && !(num == den); | |
688 if (scale) | |
689 { | |
690 profile_count::adjust_for_ipa_scaling (&num, &den); | |
691 if (dump_file) | |
692 { | |
693 fprintf (dump_file, "Applying count scale "); | |
694 num.dump (dump_file); | |
695 fprintf (dump_file, "/"); | |
696 den.dump (dump_file); | |
697 fprintf (dump_file, "\n"); | |
698 } | |
699 | |
700 basic_block bb; | |
701 cfun->cfg->count_max = profile_count::uninitialized (); | |
702 FOR_ALL_BB_FN (bb, cfun) | |
703 { | |
704 bb->count = bb->count.apply_scale (num, den); | |
705 cfun->cfg->count_max = cfun->cfg->count_max.max (bb->count); | |
706 } | |
707 ENTRY_BLOCK_PTR_FOR_FN (cfun)->count = node->count; | |
708 } | |
709 | |
646 for (e = node->callees; e; e = next) | 710 for (e = node->callees; e; e = next) |
647 { | 711 { |
648 if (!e->inline_failed) | 712 if (!e->inline_failed) |
649 has_inline = true; | 713 has_inline = true; |
650 next = e->next_callee; | 714 next = e->next_callee; |
651 e->redirect_call_stmt_to_callee (); | 715 cgraph_edge::redirect_call_stmt_to_callee (e); |
652 } | 716 } |
653 node->remove_all_references (); | 717 node->remove_all_references (); |
654 | 718 |
655 timevar_push (TV_INTEGRATION); | 719 timevar_push (TV_INTEGRATION); |
656 if (node->callees && (opt_for_fn (node->decl, optimize) || has_inline)) | 720 if (node->callees && (opt_for_fn (node->decl, optimize) || has_inline)) |
657 { | 721 { |
658 profile_count num = node->count; | |
659 profile_count den = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count; | |
660 bool scale = num.initialized_p () && !(num == den); | |
661 if (scale) | |
662 { | |
663 profile_count::adjust_for_ipa_scaling (&num, &den); | |
664 if (dump_file) | |
665 { | |
666 fprintf (dump_file, "Applying count scale "); | |
667 num.dump (dump_file); | |
668 fprintf (dump_file, "/"); | |
669 den.dump (dump_file); | |
670 fprintf (dump_file, "\n"); | |
671 } | |
672 | |
673 basic_block bb; | |
674 cfun->cfg->count_max = profile_count::uninitialized (); | |
675 FOR_ALL_BB_FN (bb, cfun) | |
676 { | |
677 bb->count = bb->count.apply_scale (num, den); | |
678 cfun->cfg->count_max = cfun->cfg->count_max.max (bb->count); | |
679 } | |
680 ENTRY_BLOCK_PTR_FOR_FN (cfun)->count = node->count; | |
681 } | |
682 todo = optimize_inline_calls (current_function_decl); | 722 todo = optimize_inline_calls (current_function_decl); |
683 } | 723 } |
684 timevar_pop (TV_INTEGRATION); | 724 timevar_pop (TV_INTEGRATION); |
685 | 725 |
686 cfun->always_inline_functions_inlined = true; | 726 cfun->always_inline_functions_inlined = true; |
687 cfun->after_inlining = true; | 727 cfun->after_inlining = true; |
688 todo |= execute_fixup_cfg (); | 728 todo |= execute_fixup_cfg (); |