Made the following changes: * -ffunction-sections turned on with -freorder-functions= * Change name from cgedge to callgraph. * The plugin should not dump final layout to file by default.
* cgraphbuild.c (remove_cgraph_callee_edges): Replace flag_callgraph_profiles_sections with flag_reorder_functions. * final.c (rest_of_handle_final): Ditto. * configure: Regenerate. * config.in: undef FRPLUGINSONAME. * congifure.ac: Define FRPLUGINSONAME. * config.host: Set host_function_reordering_plugin_soname. * gcc.c: Invoke function_reordering linker plugin with -freorder-functions=* option. (set_func_reorder_linker_plugin_spec): New function. (main): Call set_func_reorder_linker_plugin_spec when -freorder-functions=* option is seen. * common.opt (fcallgraph-profiles-sections): Remove. (freorder-functions=): New option. * testsuite/g++.dg/tree-prof/callgraph-profiles.C: Replace -fcallgraph-profiles-sections with -freorder-functions=callgraph. * opts.c (finish_options): Turn on -ffunction-sections when -freorder-functions= is used. * function_reordering_plugin.c (register_claim_file_hook): New function pointer. (register_all_symbols_read_hook): Ditto. (no_op): New global. (out_file): Make static. (is_api_exist): Make static. (process_option): New function. (onload): Return if no_op is set. Do not register handlers until necessary. (get_load): Check if out_file is NULL before opening & closing the file. * callgraph.c (find_pettis_hansen_function_layout): (get_layout): Dump only when fp is not NULL. Index: gcc/cgraphbuild.c =================================================================== --- gcc/cgraphbuild.c (revision 185372) +++ gcc/cgraphbuild.c (working copy) @@ -703,10 +703,10 @@ extern bool cgraph_callee_edges_final_cleanup; static unsigned int remove_cgraph_callee_edges (void) { - /* The -fcallgraph-profiles-sections flag needs the call-graph preserved + /* The -freorder-functions=* flag needs the call-graph preserved till pass_final. */ if (cgraph_callee_edges_final_cleanup - && flag_callgraph_profiles_sections) + && flag_reorder_functions > 1) return 0; cgraph_node_remove_callees (cgraph_node (current_function_decl)); Index: gcc/configure =================================================================== --- gcc/configure (revision 185372) +++ gcc/configure (working copy) @@ -4861,7 +4861,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_cc_gcc_supports_ada" >&5 $as_echo "$acx_cv_cc_gcc_supports_ada" >&6; } -if test x$GNATBIND != xno && test x$GNATMAKE != xno && test x$acx_cv_cc_gcc_supports_ada != xno; then +if test "x$GNATBIND" != xno && test "x$GNATMAKE" != xno && test x$acx_cv_cc_gcc_supports_ada != xno; then have_gnat=yes else have_gnat=no @@ -11480,6 +11480,12 @@ esac cat >>confdefs.h <<_ACEOF +#define FRPLUGINSONAME "${host_function_reordering_plugin_soname}" +_ACEOF + + + +cat >>confdefs.h <<_ACEOF #define LTOPLUGINSONAME "${host_lto_plugin_soname}" _ACEOF @@ -17572,7 +17578,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 17575 "configure" +#line 17581 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -17678,7 +17684,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 17681 "configure" +#line 17687 "configure" #include "confdefs.h" #if HAVE_DLFCN_H Index: gcc/final.c =================================================================== --- gcc/final.c (revision 185372) +++ gcc/final.c (working copy) @@ -4421,9 +4421,9 @@ rest_of_handle_final (void) decl_fini_priority_lookup (current_function_decl)); - /* With -fcallgraph-profiles-sections, add ".gnu.callgraph.text" section + /* With -freorder-functions=, add ".gnu.callgraph.text" section for storing profiling information. */ - if (flag_callgraph_profiles_sections + if (flag_reorder_functions > 1 && flag_profile_use && cgraph_node (current_function_decl) != NULL && (cgraph_node (current_function_decl))->callees != NULL) Index: gcc/gcc.c =================================================================== --- gcc/gcc.c (revision 185372) +++ gcc/gcc.c (working copy) @@ -663,6 +663,9 @@ proper position among the other output files. */ -plugin-opt=-fresolution=%u.res \ %{!nostdlib:%{!nodefaultlibs:%:pass-through-libs(%(link_gcc_c_sequence))}} \ }"PLUGIN_COND_CLOSE" \ + %{freorder-functions=*: \ + -plugin %(func_reorder_linker_plugin_file) \ + -plugin-opt=%(func_reorder_linker_plugin_opt)} \ %{flto|flto=*:%<fcompare-debug*} \ %{flto} %{flto=*} %l " LINK_PIE_SPEC \ "%{fuse-ld=gold:%{fuse-ld=bfd:%e-fuse-ld=gold and -fuse-ld=bfd may not be used together}} \ @@ -717,6 +720,8 @@ static const char *endfile_spec = ENDFILE_SPEC; static const char *startfile_spec = STARTFILE_SPEC; static const char *linker_name_spec = LINKER_NAME; static const char *linker_plugin_file_spec = ""; +static const char *func_reorder_linker_plugin_file_spec = ""; +static const char *func_reorder_linker_plugin_opt = ""; static const char *lto_wrapper_spec = ""; static const char *lto_gcc_spec = ""; static const char *link_command_spec = LINK_COMMAND_SPEC; @@ -1206,6 +1211,10 @@ static struct spec_list static_specs[] = INIT_STATIC_SPEC ("multilib_options", &multilib_options), INIT_STATIC_SPEC ("linker", &linker_name_spec), INIT_STATIC_SPEC ("linker_plugin_file", &linker_plugin_file_spec), + INIT_STATIC_SPEC ("func_reorder_linker_plugin_file", + &func_reorder_linker_plugin_file_spec), + INIT_STATIC_SPEC ("func_reorder_linker_plugin_opt", + &func_reorder_linker_plugin_opt), INIT_STATIC_SPEC ("lto_wrapper", <o_wrapper_spec), INIT_STATIC_SPEC ("lto_gcc", <o_gcc_spec), INIT_STATIC_SPEC ("link_libgcc", &link_libgcc_spec), @@ -6108,6 +6117,51 @@ compare_files (char *cmpfile[]) return ret; } +/* Set func_reorder_linker_plugin_file_spec and func_reorder_linker_plugin_opt + here. This is the linker plugin to do global function reordering and is + enabled with -freorder-functions=*. */ + +static void +set_func_reorder_linker_plugin_spec (void) +{ + int i; + const char *plugin_opt_none = "group=none"; + const char *plugin_opt_callgraph = "group=callgraph"; + + /* Find the linker plugin that does function ordering. */ + func_reorder_linker_plugin_file_spec = find_a_file (&exec_prefixes, + FRPLUGINSONAME, R_OK, false); + + if (!func_reorder_linker_plugin_file_spec) + fatal_error ("-freorder-functions=*, but " + FRPLUGINSONAME " file not found"); + + func_reorder_linker_plugin_opt = plugin_opt_none; + + /* Set linker plugin options here. Option ordering is also checked here. + -fno-reorder-functions or -freorder-functions should disable any + previous -freorder-functions=*. */ + for (i = 0; (int) i < n_switches; i++) + { + /* Check for match with "-freorder-functions=callgraph". */ + if (func_reorder_linker_plugin_opt != plugin_opt_callgraph + && !strcmp (switches[i].part1, "freorder-functions=callgraph")) + { + func_reorder_linker_plugin_opt = plugin_opt_callgraph; + continue; + } + /* Set option to none if it matches -fno-reorder-functions + or -freorder-functions */ + if (func_reorder_linker_plugin_opt != plugin_opt_none + && (!strcmp (switches[i].part1, "fno-reorder-functions") + || !strcmp (switches[i].part1, "freorder-functions"))) + { + func_reorder_linker_plugin_opt = plugin_opt_none; + continue; + } + } +} + extern int main (int, char **); int @@ -6843,6 +6897,8 @@ warranty; not even for MERCHANTABILITY or FITNESS const char *fuse_linker_plugin = "fuse-linker-plugin"; #endif + const char *freorder_functions_ = "freorder-functions="; + /* We'll use ld if we can't find collect2. */ if (! strcmp (linker_name_spec, "collect2")) { @@ -6866,6 +6922,12 @@ warranty; not even for MERCHANTABILITY or FITNESS fatal_error ("-fuse-linker-plugin, but " LTOPLUGINSONAME " not found"); } lto_gcc_spec = argv[0]; + + /* The function reordering linker plugin will be loaded if the option + -freorder-functions= is present in the command-line. */ + if (switch_matches (freorder_functions_, + freorder_functions_ + strlen (freorder_functions_), 1)) + set_func_reorder_linker_plugin_spec (); /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables for collect. */ Index: gcc/testsuite/g++.dg/tree-prof/callgraph-profiles.C =================================================================== --- gcc/testsuite/g++.dg/tree-prof/callgraph-profiles.C (revision 185372) +++ gcc/testsuite/g++.dg/tree-prof/callgraph-profiles.C (working copy) @@ -1,6 +1,6 @@ /* Verify if call-graph profile sections are created - with -fcallgraph-profiles-sections. */ -/* { dg-options "-O2 -fcallgraph-profiles-sections -ffunction-sections --save-temps" } */ + with -freorder-functions=. */ +/* { dg-options "-O2 -freorder-functions=callgraph -ffunction-sections --save-temps" } */ /* { dg-require-section-exclude "" } */ int __attribute__ ((noinline)) Index: gcc/config.in =================================================================== --- gcc/config.in (revision 185372) +++ gcc/config.in (working copy) @@ -1583,13 +1583,18 @@ #endif +/* Define to the name of the function reordering plugin DSO that must be + passed to the linker's -plugin=LIB option. */ +#ifndef USED_FOR_TARGET +#undef FRPLUGINSONAME +#endif + /* Define to the name of the LTO plugin DSO that must be passed to the linker's -plugin=LIB option. */ #ifndef USED_FOR_TARGET #undef LTOPLUGINSONAME #endif - /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #ifndef USED_FOR_TARGET Index: gcc/opts.c =================================================================== --- gcc/opts.c (revision 185372) +++ gcc/opts.c (working copy) @@ -846,6 +846,10 @@ finish_options (struct gcc_options *opts, struct g (PARAM_MAX_INLINE_INSNS_AUTO, 1000, opts->x_param_values, opts_set->x_param_values); } + + /* Turn on -ffunction-sections when -freorder-functions=* is used. */ + if (opts->x_flag_reorder_functions > 1) + opts->x_flag_function_sections = 1; } #define LEFT_COLUMN 27 Index: gcc/configure.ac =================================================================== --- gcc/configure.ac (revision 185372) +++ gcc/configure.ac (working copy) @@ -1858,6 +1858,10 @@ case $use_collect2 in ;; esac +AC_DEFINE_UNQUOTED(FRPLUGINSONAME,"${host_function_reordering_plugin_soname}", +[Define to the name of the function reordering plugin DSO that must be + passed to the linker's -plugin=LIB option.]) + AC_DEFINE_UNQUOTED(LTOPLUGINSONAME,"${host_lto_plugin_soname}", [Define to the name of the LTO plugin DSO that must be passed to the linker's -plugin=LIB option.]) Index: gcc/common.opt =================================================================== --- gcc/common.opt (revision 185372) +++ gcc/common.opt (working copy) @@ -920,10 +920,6 @@ fcaller-saves Common Report Var(flag_caller_saves) Optimization Save registers around function calls -fcallgraph-profiles-sections -Common Report Var(flag_callgraph_profiles_sections) Init(0) -Generate .note.callgraph.text sections listing callees and edge counts. - fcheck-data-deps Common Report Var(flag_check_data_deps) Compare the results of several data dependence analyzers. @@ -1758,9 +1754,19 @@ Common Report Var(flag_reorder_blocks_and_partitio Reorder basic blocks and partition into hot and cold sections freorder-functions -Common Report Var(flag_reorder_functions) Optimization +Common Report Var(flag_reorder_functions,1) Init(0) Optimization Reorder functions to improve code placement +freorder-functions= +Common Joined RejectNegative Enum(function_reorder) Var(flag_reorder_functions) Init(0) Optimization +-freorder-functions=[callgraph] Select the scheme for function reordering. This invokes a linker plugin. Generate .note.callgraph.text sections listing callees and edge counts. + +Enum +Name(function_reorder) Type(int) UnknownError(unrecognized function reorder value %qs) + +EnumValue +Enum(function_reorder) String(callgraph) Value(2) + frerun-cse-after-loop Common Report Var(flag_rerun_cse_after_loop) Optimization Add a common subexpression elimination pass after loop optimizations Index: gcc/config.host =================================================================== --- gcc/config.host (revision 185372) +++ gcc/config.host (working copy) @@ -76,6 +76,7 @@ out_host_hook_obj=host-default.o host_can_use_collect2=yes use_long_long_for_widest_fast_int=no host_lto_plugin_soname=liblto_plugin.so +host_function_reordering_plugin_soname=libfunction_reordering_plugin.so # Unsupported hosts list. Generally, only include hosts known to fail here, # since we allow hosts not listed to be supported generically. Index: function_reordering_plugin/function_reordering_plugin.c =================================================================== --- function_reordering_plugin/function_reordering_plugin.c (revision 185372) +++ function_reordering_plugin/function_reordering_plugin.c (working copy) @@ -64,6 +64,9 @@ enum ld_plugin_status claim_file_hook (const struc int *claimed); enum ld_plugin_status all_symbols_read_hook (); +static ld_plugin_register_claim_file register_claim_file_hook = NULL; +static ld_plugin_register_all_symbols_read + register_all_symbols_read_hook = NULL; static ld_plugin_get_input_section_count get_input_section_count = NULL; static ld_plugin_get_input_section_type get_input_section_type = NULL; static ld_plugin_get_input_section_name get_input_section_name = NULL; @@ -72,23 +75,54 @@ static ld_plugin_update_section_order update_secti static ld_plugin_allow_section_ordering allow_section_ordering = NULL; /* The file where the final function order will be stored. - It is "./final_layout.txt". It can be changed by passing - new name to --plugin-opt */ + It can be set by using the plugin option as --plugin-opt + "file=<name>". To dump to stderr, say --plugin-opt "file=stderr". */ -char *out_file = "./final_layout.txt"; +static char *out_file = NULL; -int is_api_exist = 0; +static int is_api_exist = 0; +/* The plugin does nothing when no-op is 1. */ +static int no_op = 0; + /* Copies new output file name out_file */ void get_filename (const char *name) { - if (strcmp (name, "stderr") == 0) + out_file = (char *) malloc (strlen (name) + 1); + strcpy (out_file, name); +} + +/* Process options to plugin. Options with prefix "group=" are special. + They specify the type of grouping. The option "group=none" makes the + plugin do nothing. Options with prefix "file=" set the output file + where the final function order must be stored. */ +void +process_option (const char *name) +{ + const char *option_group = "group="; + const char *option_file = "file="; + + /* Check if option is "group=" */ + if (strncmp (name, option_group, strlen (option_group)) == 0) { - out_file = NULL; + if (strcmp (name + strlen (option_group), "none") == 0) + no_op = 1; + else + no_op = 0; return; } - out_file = (char *) malloc (strlen (name) + 1); - strcpy (out_file, name); + + /* Check if option is "file=" */ + if (strncmp (name, option_file, strlen (option_file)) == 0) + { + get_filename (name + strlen (option_file)); + return; + } + + /* Unknown option, set no_op to 1. */ + no_op = 1; + fprintf (stderr, "Unknown option to function reordering plugin :%s\n", + name); } /* Plugin entry point. */ @@ -105,14 +139,16 @@ onload (struct ld_plugin_tv *tv) case LDPT_GOLD_VERSION: break; case LDPT_OPTION: - get_filename (entry->tv_u.tv_string); + process_option (entry->tv_u.tv_string); + /* If no_op is set, do not do anything else. */ + if (no_op) return LDPS_OK; break; case LDPT_REGISTER_CLAIM_FILE_HOOK: - assert ((*entry->tv_u.tv_register_claim_file) (claim_file_hook) == LDPS_OK); + register_claim_file_hook = *entry->tv_u.tv_register_claim_file; break; case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK: - assert ((*entry->tv_u.tv_register_all_symbols_read) (all_symbols_read_hook) - == LDPS_OK); + register_all_symbols_read_hook + = *entry->tv_u.tv_register_all_symbols_read; break; case LDPT_GET_INPUT_SECTION_COUNT: get_input_section_count = *entry->tv_u.tv_get_input_section_count; @@ -137,14 +173,25 @@ onload (struct ld_plugin_tv *tv) } } - if (get_input_section_count != NULL + assert (!no_op); + + if (register_all_symbols_read_hook != NULL + && register_claim_file_hook != NULL + && get_input_section_count != NULL && get_input_section_type != NULL && get_input_section_name != NULL && get_input_section_contents != NULL && update_section_order != NULL && allow_section_ordering != NULL) is_api_exist = 1; + else + return LDPS_OK; + /* Register handlers. */ + assert ((*register_all_symbols_read_hook) (all_symbols_read_hook) + == LDPS_OK); + assert ((*register_claim_file_hook) (claim_file_hook) + == LDPS_OK); return LDPS_OK; } @@ -161,9 +208,8 @@ claim_file_hook (const struct ld_plugin_input_file (void) claimed; - /* Silently return if the plugin APIs are not supported. */ - if (!is_api_exist) - return LDPS_OK; + /* Plugin APIs are supported if this is called. */ + assert (is_api_exist); if (is_ordering_specified == 0) { @@ -219,24 +265,26 @@ all_symbols_read_hook (void) struct ld_plugin_section *section_list; void **handles; unsigned int *shndx; - FILE *fp; + FILE *fp = NULL; - /* Silently return if the plugin APIs are not supported. */ - if (!is_api_exist) - return LDPS_OK; + /* Plugin APIs are supported if this is called. */ + assert (is_api_exist); if (is_callgraph_empty ()) return LDPS_OK; /* Open the file to write the final layout */ - if (out_file == NULL) - fp = stderr; - else - fp = fopen (out_file, "w"); + if (out_file != NULL) + { + if (strcmp (out_file, "stderr") == 0) + fp = stderr; + else + fp = fopen (out_file, "w"); - fprintf (fp, "# Remove lines starting with \'#\' to" - " pass to --section-ordering-file\n"); - fprintf (fp, "# Lines starting with \'#\' are the edge profiles\n"); + fprintf (fp, "# Remove lines starting with \'#\' to" + " pass to --section-ordering-file\n"); + fprintf (fp, "# Lines starting with \'#\' are the edge profiles\n"); + } find_pettis_hansen_function_layout (fp); num_entries = get_layout (fp, &handles, &shndx); @@ -248,7 +296,8 @@ all_symbols_read_hook (void) section_list[i].shndx = shndx[i]; } - if (out_file != NULL) + if (out_file != NULL + && strcmp (out_file, "stderr") != 0) fclose (fp); /* Pass the new order of functions to the linker. */ update_section_order (section_list, num_entries); Index: function_reordering_plugin/callgraph.c =================================================================== --- function_reordering_plugin/callgraph.c (revision 185372) +++ function_reordering_plugin/callgraph.c (working copy) @@ -435,10 +435,9 @@ find_pettis_hansen_function_layout (FILE *fp) assert (node_chain != NULL); assert (active_edges != NULL); - assert (fp != NULL); + if (fp != NULL) + dump_edges (fp); - dump_edges (fp); - /* Go over all the nodes and set it as real node only if a corresponding function section exists. */ for (n_it = node_chain; n_it != NULL; n_it = n_it->next) @@ -509,7 +508,8 @@ write_out_node (FILE *fp, char *name, Section_id *s = (Section_id *)slot; handles[position] = s->handle; shndx[position] = s->shndx; - fprintf (fp, "%s\n", s->full_name); + if (fp != NULL) + fprintf (fp, "%s\n", s->full_name); /* No more use of full_name */ free (s->full_name); } @@ -524,8 +524,6 @@ get_layout (FILE *fp, void*** handles, Node *it; int position = 0; - assert (fp != NULL); - *handles = XNEWVEC (void *, num_real_nodes); *shndx = XNEWVEC (unsigned int, num_real_nodes); -- This patch is available for review at http://codereview.appspot.com/5825054