diff options
author | Giuliano Belinassi <giuliano.belinassi@usp.br> | 2020-07-14 17:51:47 -0300 |
---|---|---|
committer | Giuliano Belinassi <giuliano.belinassi@usp.br> | 2020-07-14 17:51:47 -0300 |
commit | 33c9262ecfa1bc812f957b8f7e859e1679e90c79 (patch) | |
tree | 3b37db6bf24a6e653979caf903b9f695a8899a39 | |
parent | 75c8f3173d0ebb63b7130fa692358f2c2a2a06f4 (diff) | |
download | gcc-33c9262ecfa1bc812f957b8f7e859e1679e90c79.zip gcc-33c9262ecfa1bc812f957b8f7e859e1679e90c79.tar.gz gcc-33c9262ecfa1bc812f957b8f7e859e1679e90c79.tar.bz2 |
Make bootstrap work when partitioning after LTRANS
Previously, we were incorrectly partitioning before the LTRANS stage,
which made us fall into several problems with regard to symbol promotion
and inlining. This commit fixes this behaviour by moving the
partitioning stage right after the LTRANS stage.
gcc/ChangeLog
2020-07-14 Giuliano Belinassi <giuliano.belinassi@usp.br>
* cgraphunit.c (ipa_passes): Move split_outputs to.
(symbol_table::compile): Here. Also make sure it runs after the IPA
transformation stage.
* ipa-fnsummary.c (gate): Make sure it runs once in split_outputs.
* lto-cgraph.c (handle_node_in_boundary): Implemement case where
body should not be removed.
(compute_boundary): New function.
* symtab.c: Show aux2 variable on dump.
-rw-r--r-- | gcc/ChangeLog | 18 | ||||
-rw-r--r-- | gcc/cgraphunit.c | 196 | ||||
-rw-r--r-- | gcc/ipa-fnsummary.c | 2 | ||||
-rw-r--r-- | gcc/lto-cgraph.c | 163 | ||||
-rw-r--r-- | gcc/lto-partition.c | 5 | ||||
-rw-r--r-- | gcc/symtab.c | 2 |
6 files changed, 236 insertions, 150 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1909efb..55474f0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2020-07-14 Giuliano Belinassi <giuliano.belinassi@usp.br> + + * cgraphunit.c (ipa_passes): Move split_outputs to. + (symbol_table::compile): Here. Also make sure it runs after the IPA + transformation stage. + * ipa-fnsummary.c (gate): Make sure it runs once in split_outputs. + * lto-cgraph.c (handle_node_in_boundary): Implemement case where + body should not be removed. + (compute_boundary): New function. + * symtab.c: Show aux2 variable on dump. + +2020-07-08 Giuliano Belinassi <giuliano.belinassi@usp.br> + + * cgraphunit.c (ipa_passes): Use params instead of literals. + * lto-partition.c (merge_static_calls): Be careful with + SYMBOL_DUPLICATE. + * params.def: New params promote-statics and balance-partitions. + 2020-07-07 Giuliano Belinassi <giuliano.belinassi@usp.br> * ipa-cp.c (initialize_node_lattices): Uncoment `gcc_unreachable'. diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index d61bded..6ea665a 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -2639,10 +2639,6 @@ ipa_passes (void) if (!in_lto_p) { - struct symtab_node *node; - int partitions, i; - int *pids; - /* Generate coverage variables and constructors. */ coverage_finish (); @@ -2654,97 +2650,8 @@ ipa_passes (void) execute_ipa_summary_passes ((ipa_opt_pass_d *) passes->all_regular_ipa_passes); - if (split_outputs) - { - bool promote_statics = param_promote_statics; - bool balance = param_balance_partitions; - - /* Trick the compiler to think that we are in WPA. */ - flag_wpa = ""; - symtab_node::checking_verify_symtab_nodes (); - - /* Partition the program so that COMDATs get mapped to the same - partition. If promote_statics is true, it also maps statics - to the same partition. If balance is true, try to balance the - partitions for compilation performance. */ - lto_merge_comdat_map (balance, promote_statics); - - /* AUX pointers are used by partitioning code to bookkeep number of - partitions symbol is in. This is no longer needed. */ - FOR_EACH_SYMBOL (node) - node->aux = NULL; - - /* We decided that partitioning is a bad idea. In this case, just - proceed with the default compilation method. */ - if (ltrans_partitions.length () <= 1) - { - flag_wpa = NULL; - goto continue_compilation; - } - - /* Find out statics that need to be promoted - to globals with hidden visibility because they are accessed from - multiple partitions. */ - lto_promote_cross_file_statics (promote_statics); - - /* Check if we have variables being referenced across partitions. */ - lto_check_usage_from_other_partitions (); - - /* Trick the compiler to think we are not in WPA anymore. */ - flag_wpa = NULL; - - partitions = ltrans_partitions.length (); - pids = (int *) alloca (partitions * sizeof (*pids)); - - /* Trick the compiler to think we are in LTRANS mode. */ - flag_ltrans = true; - - init_additional_asm_names_file (); - - /* Flush asm file, so we don't get repeated output as we fork. */ - fflush (asm_out_file); - - /* Run serially for now. */ - for (i = 0; i < partitions; ++i) - { - gcc_assert (ltrans_partitions[i]->symbols > 0); - - pids[i] = fork (); - if (pids[i] == 0) - { - lto_apply_partition_mask (ltrans_partitions[i]); - - goto continue_compilation; - } - else - { - int wstatus; - waitpid (pids[i], &wstatus, 0); - - if (WIFEXITED (wstatus)) - { - if (WEXITSTATUS (wstatus) == 0) - continue; - else - { - fprintf (stderr, "Child %d exited with error\n", i); - internal_error ("Child exited with error"); - } - - } - else if (WIFSIGNALED (wstatus)) - { - fprintf (stderr, "Child %d aborted due to signal\n", i); - internal_error ("Child aborted with error"); - } - } - } - exit (0); - } } - continue_compilation: - /* Some targets need to handle LTO assembler output specially. */ if (flag_generate_lto || flag_generate_offload) targetm.asm_out.lto_start (); @@ -2772,10 +2679,17 @@ ipa_passes (void) if (flag_generate_lto || flag_generate_offload) targetm.asm_out.lto_end (); + if (split_outputs) + flag_ltrans = true; + if ((!flag_ltrans || split_outputs) && ((in_lto_p && flag_incremental_link != INCREMENTAL_LINK_LTO) || !flag_lto || flag_fat_lto_objects)) execute_ipa_pass_list (passes->all_regular_ipa_passes); + + if (split_outputs) + flag_ltrans = false; + invoke_plugin_callbacks (PLUGIN_ALL_IPA_PASSES_END, NULL); bitmap_obstack_release (NULL); @@ -2853,6 +2767,102 @@ symbol_table::compile (const char *name) { timevar_start (TV_CGRAPH_IPA_PASSES); ipa_passes (); + + if (split_outputs) + { + struct symtab_node *node; + int partitions, i; + int *pids; + + bool promote_statics = param_promote_statics; + bool balance = param_balance_partitions; + + /* Trick the compiler to think that we are in WPA. */ + flag_wpa = ""; + symtab_node::checking_verify_symtab_nodes (); + + /* Partition the program so that COMDATs get mapped to the same + partition. If promote_statics is true, it also maps statics + to the same partition. If balance is true, try to balance the + partitions for compilation performance. */ + lto_merge_comdat_map (balance, promote_statics); + + /* AUX pointers are used by partitioning code to bookkeep number of + partitions symbol is in. This is no longer needed. */ + FOR_EACH_SYMBOL (node) + node->aux = NULL; + + /* We decided that partitioning is a bad idea. In this case, just + proceed with the default compilation method. */ + if (ltrans_partitions.length () <= 1) + { + flag_wpa = NULL; + goto continue_compilation; + } + + /* Find out statics that need to be promoted + to globals with hidden visibility because they are accessed from + multiple partitions. */ + lto_promote_cross_file_statics (promote_statics); + + /* Check if we have variables being referenced across partitions. */ + lto_check_usage_from_other_partitions (); + + /* Trick the compiler to think we are not in WPA anymore. */ + flag_wpa = NULL; + + partitions = ltrans_partitions.length (); + pids = (int *) alloca (partitions * sizeof (*pids)); + + /* Trick the compiler to think we are in LTRANS mode. */ + flag_ltrans = true; + + init_additional_asm_names_file (); + + /* Flush asm file, so we don't get repeated output as we fork. */ + fflush (asm_out_file); + + symtab_node::checking_verify_symtab_nodes (); + + /* Run serially for now. */ + for (i = 0; i < partitions; ++i) + { + gcc_assert (ltrans_partitions[i]->symbols > 0); + + pids[i] = fork (); + if (pids[i] == 0) + { + lto_apply_partition_mask (ltrans_partitions[i]); + + goto continue_compilation; + } + else + { + int wstatus; + waitpid (pids[i], &wstatus, 0); + + if (WIFEXITED (wstatus)) + { + if (WEXITSTATUS (wstatus) == 0) + continue; + else + { + fprintf (stderr, "Child %d exited with error\n", i); + internal_error ("Child exited with error"); + } + + } + else if (WIFSIGNALED (wstatus)) + { + fprintf (stderr, "Child %d aborted due to signal\n", i); + internal_error ("Child aborted with error"); + } + } + } + exit (0); + } + +continue_compilation: timevar_stop (TV_CGRAPH_IPA_PASSES); } /* Do nothing else if any IPA pass found errors or if we are just streaming LTO. */ diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c index 045a0ec..9f491a7 100644 --- a/gcc/ipa-fnsummary.c +++ b/gcc/ipa-fnsummary.c @@ -4599,7 +4599,7 @@ public: gcc_assert (n == 0); small_p = param; } - virtual bool gate (function *) { return true; } + virtual bool gate (function *) { return !(flag_ltrans && split_outputs); } virtual unsigned int execute (function *) { ipa_free_fn_summary (); diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index 0029588..1971fdb 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -2061,29 +2061,55 @@ input_cgraph_opt_summary (vec<symtab_node *> nodes) } } +/* When analysing function for removal, we have mainly three states, as + defined below. */ + +enum node_partition_state +{ + CAN_REMOVE, /* This node can be removed, or is still to be analysed. */ + IN_CURRENT_PARTITION, /* This node is in current partition and should not be + touched. */ + IN_BOUNDARY, /* This node is in boundary, therefore being in other + partition or is a external symbol, and its body can be + released. */ + IN_BOUNDARY_KEEP_BODY /* This symbol is in other partition but we may need its + body for inlining, for instance. */ +}; + /* Handle node that are in the LTRANS boundary, releasing its body and - other informations. */ + other informations if necessary. */ static void -handle_node_in_boundary (symtab_node *node) +handle_node_in_boundary (symtab_node *node, bool keep_body) { - cgraph_node *cnode = dyn_cast <cgraph_node *> (node); - varpool_node *vnode = dyn_cast <varpool_node *> (node); - if (cnode) + if (cgraph_node *cnode = dyn_cast <cgraph_node *> (node)) { - cnode->maybe_release_dominators (); + if (cnode->inlined_to && cnode->inlined_to->aux2 != IN_CURRENT_PARTITION) + { + /* Marked to be inlined into a node not in current partition? + Then undo the inline. */ - if (cnode->clone_of) - cnode->remove_from_clone_tree (); + if (cnode->callers) /* This edge could be removed. */ + cnode->callers->inline_failed = CIF_UNSPECIFIED; + cnode->inlined_to = NULL; + } if (cnode->has_gimple_body_p ()) { - cnode->remove_callees (); - cnode->remove_all_references (); - cnode->release_body (); - cnode->body_removed = true; - cnode->analyzed = false; - cnode->definition = false; + if (!keep_body) + { + cnode->maybe_release_dominators (); + cnode->remove_callees (); + cnode->remove_all_references (); + + /* FIXME: Releasing body of clones can release bodies of functions + in current partition. */ + + /* cnode->release_body (); */ + cnode->body_removed = true; + cnode->definition = false; + cnode->analyzed = false; + } cnode->cpp_implicit_alias = false; cnode->alias = false; cnode->transparent_alias = false; @@ -2099,68 +2125,99 @@ handle_node_in_boundary (symtab_node *node) cnode->in_other_partition = true; } } - else if (vnode && !DECL_EXTERNAL (vnode->decl)) - vnode->in_other_partition = true; + else if (is_a <varpool_node *> (node) && !DECL_EXTERNAL (node->decl)) + node->in_other_partition = true; } -/* Replace the partition in the symbol table, removing every node which is not - in partition. */ +/* Check the boundary and expands it if necessary, including more nodes or + promoting then to a state where their body is required. */ -void -lto_apply_partition_mask (ltrans_partition partition) +static void +compute_boundary (ltrans_partition partition) { vec<lto_encoder_entry> &nodes = partition->encoder->nodes; symtab_node *node; + cgraph_node *cnode; auto_vec<symtab_node *, 16> mark_to_remove; unsigned int i; FOR_EACH_SYMBOL (node) - node->aux2 = 0; + node->aux2 = CAN_REMOVE; + /* Lets assign the information that the encoder gave to us. */ for (i = 0; i < nodes.length (); i++) { - symtab_node *node = nodes[i].node; - node->aux2 = 1; - - if (!nodes[i].in_partition) - handle_node_in_boundary (node); + node = nodes[i].node; + if (nodes[i].in_partition) + { + node->aux2 = IN_CURRENT_PARTITION; + node->in_other_partition = false; + } + else if (nodes[i].body) + node->aux2 = IN_BOUNDARY_KEEP_BODY; + else + node->aux2 = IN_BOUNDARY; } + /* Then look for nodes that was marked to be inlined to. If it is marked to be + inlined into a node that is in current partition, then mark its body to + not be removed. Also expand the boundary for nodes that requires that + its body not to be removed. */ for (i = 0; i < nodes.length (); i++) { - symtab_node *node = nodes[i].node; - bool in_partition = nodes[i].in_partition; + cnode = dyn_cast <cgraph_node *> (nodes[i].node); + if (!cnode) + continue; - /* Expand boundary a little more to avoid issues with ipa-cp. */ - if (in_partition) - { - if (cgraph_node *cnode = dyn_cast <cgraph_node *> (node)) - if (cnode->local) - for (cgraph_edge *e = cnode->callers; e; e = e->next_caller) - { - if (e->caller->get_partitioning_class () == SYMBOL_PARTITION) - { - if (e->caller->aux2 == 0 && e->caller->has_gimple_body_p ()) - { - bool in_other_partition = node->in_other_partition; - handle_node_in_boundary (node); - node->in_other_partition = in_other_partition; - } - } - e->caller->aux2 = 1; - } + /* Promote nodes that will be inlined into a node in current partiton. */ + if (cnode->inlined_to && cnode->inlined_to->aux2 == IN_CURRENT_PARTITION + && cnode->aux2 == IN_BOUNDARY) + cnode->aux2 = IN_BOUNDARY_KEEP_BODY; - /* Handle Schrondiger nodes that are and are not in the partition. */ - node->in_other_partition = false; - } + /* Expand the boundary based on nodes in boundary that requires their + body to be present. */ + if (cnode->aux2 == IN_BOUNDARY_KEEP_BODY) + for (cgraph_edge *e = cnode->callees; e; e = e->next_callee) + if (e->callee->aux2 == CAN_REMOVE) + e->callee->aux2 = IN_BOUNDARY; } +} + +/* Replace the partition in the symbol table, removing every node which is not + in partition. */ + +void +lto_apply_partition_mask (ltrans_partition partition) +{ + symtab_node *node; + auto_vec<symtab_node *, 16> mark_to_remove; + unsigned int i; + + compute_boundary (partition); FOR_EACH_SYMBOL (node) - if (node->aux2 == 0) - mark_to_remove.safe_push (node); - else - node->aux2 = 0; + switch (node->aux2) + { + case IN_CURRENT_PARTITION: + continue; + + case CAN_REMOVE: + mark_to_remove.safe_push (node); + break; + + case IN_BOUNDARY: + handle_node_in_boundary (node, false); + break; + + case IN_BOUNDARY_KEEP_BODY: + handle_node_in_boundary (node, true); + break; + + default: + gcc_unreachable (); + } + /* Finally remove queued nodes. */ for (i = 0; i < mark_to_remove.length (); i++) { symtab_node *node = mark_to_remove[i]; diff --git a/gcc/lto-partition.c b/gcc/lto-partition.c index 1431abb..c3b4ef6 100644 --- a/gcc/lto-partition.c +++ b/gcc/lto-partition.c @@ -1072,9 +1072,8 @@ lto_merge_comdat_map (bool balance, bool promote_statics) FOR_EACH_SYMBOL (node) node->aux = NULL; - if (balance) - if (!balance_partitions (&disjoint_sets, n)) - return; + if (balance && !balance_partitions (&disjoint_sets, n)) + return; build_ltrans_partitions (&disjoint_sets, n); } diff --git a/gcc/symtab.c b/gcc/symtab.c index 0e852d4..a5fba15 100644 --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -965,6 +965,8 @@ symtab_node::dump_base (FILE *f) if (lto_file_data) fprintf (f, " Read from file: %s\n", lto_file_data->file_name); + + fprintf(f, " AUX2: %d\n", aux2); } /* Dump symtab node to F. */ |