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 ();