diff options
author | Raksit Ashok <raksit@google.com> | 2009-08-18 05:43:57 +0000 |
---|---|---|
committer | Raksit Ashok <raksit@google.com> | 2009-08-18 05:43:57 +0000 |
commit | c00d5de9e4743e95c75cf7c76af3367e66162afd (patch) | |
tree | 2f33fed5dcb877bfbaba709f07b2fecba9aac551 | |
parent | 905da5babc29f4498951834b97f5180ae2a6e414 (diff) |
(1) Record relevant GCC command line options in the gcda file (-O*, -f*,
-W*, --param).
(2) At profile-use time, if foo.cc imports bar.cc, compare the command line
options that were used at profile-generate time for these two modules
(these options are recorded in the gcda file), and decide if bar.cc
would be compatible with foo.cc.
(3) New warning option -Wripa-opt-mismatch emits a warning whenever we
encounter auxiliary modules with mismatching options from the primary
module (this warning is turned on by -Wall).
(4) New option -fripa-disallow-opt-mismatch skips auxiliary modules with
mismatching options from the primary module.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/lw-ipo@150867 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/c-opts.c | 1 | ||||
-rw-r--r-- | gcc/common.opt | 8 | ||||
-rw-r--r-- | gcc/coverage.c | 183 | ||||
-rw-r--r-- | gcc/doc/invoke.texi | 24 | ||||
-rw-r--r-- | gcc/dyn-ipa.c | 5 | ||||
-rw-r--r-- | gcc/gcov-io.c | 5 | ||||
-rw-r--r-- | gcc/gcov-io.h | 1 | ||||
-rw-r--r-- | gcc/opts.c | 33 | ||||
-rw-r--r-- | gcc/opts.h | 9 |
9 files changed, 225 insertions, 44 deletions
diff --git a/gcc/c-opts.c b/gcc/c-opts.c index b1343fef53e..1859534c9b3 100644 --- a/gcc/c-opts.c +++ b/gcc/c-opts.c @@ -388,6 +388,7 @@ c_common_handle_option (size_t scode, const char *arg, int value) warn_missing_braces = value; warn_parentheses = value; warn_return_type = value; + warn_ripa_opt_mismatch = value; warn_sequence_point = value; /* Was C only. */ warn_switch = value; if (warn_strict_aliasing == -1) diff --git a/gcc/common.opt b/gcc/common.opt index d0ecea8a1aa..947eeb7b8ef 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -152,6 +152,10 @@ Wpadded Common Var(warn_padded) Warning Warn when padding is required to align structure members +Wripa-opt-mismatch +Common Var(warn_ripa_opt_mismatch) Warning +Warn if primary and auxiliary modules have mismatched command line options + Wshadow Common Var(warn_shadow) Warning Warn when one local variable shadows another @@ -482,6 +486,10 @@ fdump-unnumbered-links Common Report Var(flag_dump_unnumbered_links) VarExists Suppress output of previous and next insn numbers in debugging dumps +fripa-disallow-opt-mismatch +Common Report Var(flag_ripa_disallow_opt_mismatch) +Don't import an auxiliary module if the command line options mismatch with the primary module + fearly-inlining Common Report Var(flag_early_inlining) Init(1) Optimization Perform early inlining diff --git a/gcc/coverage.c b/gcc/coverage.c index 914e48691f4..4d22ca8d3a3 100644 --- a/gcc/coverage.c +++ b/gcc/coverage.c @@ -149,7 +149,7 @@ static tree build_ctr_info_type (void); static tree build_ctr_info_value (unsigned, tree); static tree build_gcov_info (void); static void create_coverage (void); -static void get_da_file_name (const char *); +static char * get_da_file_name (const char *); /* Return the type node for gcov_type. */ @@ -205,6 +205,70 @@ is_last_module (unsigned mod_id) return (mod_id == module_infos[num_in_fnames - 1]->ident); } +/* Returns true if the command-line arguments stored in the given module-infos + are incompatible. */ +static bool +incompatible_cl_args (struct gcov_module_info* mod_info1, + struct gcov_module_info* mod_info2) +{ + char **warning_opts1 = XNEWVEC (char *, mod_info1->num_cl_args); + char **warning_opts2 = XNEWVEC (char *, mod_info2->num_cl_args); + char **non_warning_opts1 = XNEWVEC (char *, mod_info1->num_cl_args); + char **non_warning_opts2 = XNEWVEC (char *, mod_info2->num_cl_args); + unsigned int i, num_warning_opts1 = 0, num_warning_opts2 = 0; + unsigned int num_non_warning_opts1 = 0, num_non_warning_opts2 = 0; + bool warning_mismatch = false; + bool non_warning_mismatch = false; + unsigned int start_index1 = mod_info1->num_quote_paths + + mod_info1->num_bracket_paths + mod_info1->num_cpp_defines; + unsigned int start_index2 = mod_info2->num_quote_paths + + mod_info2->num_bracket_paths + mod_info2->num_cpp_defines; + + /* First, separate the warning and non-warning options. */ + for (i = 0; i < mod_info1->num_cl_args; i++) + if (mod_info1->string_array[start_index1 + i][1] == 'W') + warning_opts1[num_warning_opts1++] = + mod_info1->string_array[start_index1 + i]; + else + non_warning_opts1[num_non_warning_opts1++] = + mod_info1->string_array[start_index1 + i]; + + for (i = 0; i < mod_info2->num_cl_args; i++) + if (mod_info2->string_array[start_index2 + i][1] == 'W') + warning_opts2[num_warning_opts2++] = + mod_info2->string_array[start_index2 + i]; + else + non_warning_opts2[num_non_warning_opts2++] = + mod_info2->string_array[start_index2 + i]; + + /* Compare warning options. If these mismatch, we emit a warning. */ + if (num_warning_opts1 != num_warning_opts2) + warning_mismatch = true; + else + for (i = 0; i < num_warning_opts1 && !warning_mismatch; i++) + warning_mismatch = strcmp (warning_opts1[i], warning_opts2[i]) != 0; + + /* Compare non-warning options. If these mismatch, we emit a warning, and if + -fripa-disallow-opt-mismatch is supplied, the two modules are also + incompatible. */ + if (num_non_warning_opts1 != num_non_warning_opts2) + non_warning_mismatch = true; + else + for (i = 0; i < num_non_warning_opts1 && !non_warning_mismatch; i++) + non_warning_mismatch = + strcmp (non_warning_opts1[i], non_warning_opts2[i]) != 0; + + if (warn_ripa_opt_mismatch && (warning_mismatch || non_warning_mismatch)) + warning (OPT_Wripa_opt_mismatch, "command line arguments mismatch for %s " + "and %s", mod_info1->source_filename, mod_info2->source_filename); + + XDELETEVEC (warning_opts1); + XDELETEVEC (warning_opts2); + XDELETEVEC (non_warning_opts1); + XDELETEVEC (non_warning_opts2); + return flag_ripa_disallow_opt_mismatch && non_warning_mismatch; +} + /* Read in the counts file, if available. DA_FILE_NAME is the name of the gcda file, and MODULE_ID is the module id of the associated source module. */ @@ -377,16 +441,16 @@ read_counts_file (const char *da_file_name, unsigned module_id) = (struct gcov_module_info *) alloca ((length + 2) * sizeof (gcov_unsigned_t)); gcov_read_module_info (mod_info, length); - module_infos_read++; - info_sz = (sizeof (struct gcov_module_info) + sizeof (void *) * (mod_info->num_quote_paths + mod_info->num_bracket_paths + - mod_info->num_cpp_defines)); + mod_info->num_cpp_defines + + mod_info->num_cl_args)); /* The first MODULE_INFO record must be for the primary module. */ - if (module_infos_read == 1) + if (module_infos_read == 0) { gcc_assert (mod_info->is_primary && !modset); + module_infos_read++; modset = pointer_set_create (); pointer_set_insert (modset, (void *)(size_t)mod_info->ident); primary_module_id = mod_info->ident; @@ -396,33 +460,49 @@ read_counts_file (const char *da_file_name, unsigned module_id) } else { + int fd; + char *aux_da_filename = get_da_file_name (mod_info->da_filename); gcc_assert (!mod_info->is_primary); - if (!pointer_set_insert (modset, (void *)(size_t)mod_info->ident) - /* Forbid mixed language LIPO for now. */ - && module_infos[0]->lang == mod_info->lang - /* Debugging support. */ - && module_infos_read <= max_group) + if (pointer_set_insert (modset, (void *)(size_t)mod_info->ident)) + inform (input_location, "Not importing %s: already imported", + mod_info->source_filename); + else if (module_infos[0]->lang != mod_info->lang) + inform (input_location, "Not importing %s: source language" + " different from primary module's source language", + mod_info->source_filename); + else if (module_infos_read == max_group) + inform (input_location, "Not importing %s: maximum group size" + " reached", mod_info->source_filename); + else if (incompatible_cl_args (module_infos[0], mod_info)) + inform (input_location, "Not importing %s: command-line" + " arguments not compatible with primary module", + mod_info->source_filename); + else if ((fd = open (aux_da_filename, O_RDONLY)) < 0) + inform (input_location, "Not importing %s: couldn't open %s", + mod_info->source_filename, aux_da_filename); + else { + close (fd); + module_infos_read++; add_input_filename (mod_info->source_filename); - module_infos = XRESIZEVEC (struct gcov_module_info *, module_infos, - num_in_fnames); - gcc_assert (num_in_fnames == module_infos_read); - module_infos[module_infos_read - 1] - = XCNEWVAR (struct gcov_module_info, info_sz); - memcpy (module_infos[module_infos_read - 1], mod_info, info_sz); + module_infos = XRESIZEVEC (struct gcov_module_info *, + module_infos, num_in_fnames); + gcc_assert (num_in_fnames == module_infos_read); + module_infos[module_infos_read - 1] + = XCNEWVAR (struct gcov_module_info, info_sz); + memcpy (module_infos[module_infos_read - 1], mod_info, + info_sz); } - else - module_infos_read--; } /* Debugging */ { - fprintf (stderr, - "MODULE Id=%d, Is_Primary=%s," - " Is_Exported=%s, Name=%s (%s)\n", - mod_info->ident, mod_info->is_primary?"yes":"no", - mod_info->is_exported?"yes":"no", mod_info->source_filename, - mod_info->da_filename); + inform (input_location, + "MODULE Id=%d, Is_Primary=%s," + " Is_Exported=%s, Name=%s (%s)", + mod_info->ident, mod_info->is_primary?"yes":"no", + mod_info->is_exported?"yes":"no", mod_info->source_filename, + mod_info->da_filename); } } gcov_sync (offset, length); @@ -1129,6 +1209,29 @@ build_cpp_def_array_value (tree string_type, tree cpp_def_value, return cpp_def_value; } +/* Returns an array (tree) of command-line argument strings. STRING_TYPE is + the string type, CL_ARGS_VALUE is the initial value of the command-line + args array. */ + +static tree +build_cl_args_array_value (tree string_type, tree cl_args_value) +{ + unsigned int i; + for (i = 0; i < num_lipo_cl_args; i++) + { + int arg_length = strlen (lipo_cl_args[i]); + tree arg_string = build_string (arg_length + 1, lipo_cl_args[i]); + TREE_TYPE (arg_string) = + build_array_type (char_type_node, + build_index_type (build_int_cst (NULL_TREE, + arg_length))); + cl_args_value = tree_cons (NULL_TREE, + build1 (ADDR_EXPR, string_type, arg_string), + cl_args_value); + } + return cl_args_value; +} + /* Returns the value of the module info associated with the current source module being compiled. */ @@ -1254,11 +1357,20 @@ build_gcov_module_info_value (void) value = tree_cons (field, build_int_cstu (get_gcov_unsigned_t (), num_cpp_defines), value); + /* Num command-line args. */ + field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, + NULL_TREE, get_gcov_unsigned_t ()); + TREE_CHAIN (field) = fields; + fields = field; + value = tree_cons (field, build_int_cstu (get_gcov_unsigned_t (), + num_lipo_cl_args), value); + /* string array */ index_type = build_index_type (build_int_cst (NULL_TREE, num_quote_paths + num_bracket_paths + - num_cpp_defines)); + num_cpp_defines + + num_lipo_cl_args)); string_array_type = build_array_type (string_type, index_type); string_array = build_inc_path_array_value (string_type, string_array, quote_paths, num_quote_paths); @@ -1266,6 +1378,7 @@ build_gcov_module_info_value (void) bracket_paths, num_bracket_paths); string_array = build_cpp_def_array_value (string_type, string_array, cpp_defines_head); + string_array = build_cl_args_array_value (string_type, string_array); string_array = build_constructor_from_list (string_array_type, nreverse (string_array)); field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, @@ -1500,9 +1613,10 @@ create_coverage (void) /* Get the da file name, given base file name. */ -void +static char * get_da_file_name (const char *base_file_name) { + char *da_file_name; int len = strlen (base_file_name); const char *prefix = profile_data_prefix; /* + 1 for extra '/', in case prefix doesn't end with /. */ @@ -1516,7 +1630,6 @@ get_da_file_name (const char *base_file_name) /* Name of da file. */ da_file_name = XNEWVEC (char, len + strlen (GCOV_DATA_SUFFIX) + prefix_len + 1); - da_base_file_name = XNEWVEC (char, len + 1); if (prefix) { @@ -1528,7 +1641,7 @@ get_da_file_name (const char *base_file_name) da_file_name[0] = 0; strcat (da_file_name, base_file_name); strcat (da_file_name, GCOV_DATA_SUFFIX); - strcpy (da_base_file_name, base_file_name); + return da_file_name; } /* Rebuild counts_hash already built the primary module. This hashtable @@ -1640,7 +1753,9 @@ coverage_init (const char *filename, const char* source_name) int src_name_prefix_len = 0; int len = strlen (filename); - get_da_file_name (filename); + da_file_name = get_da_file_name (filename); + da_base_file_name = XNEWVEC (char, strlen (filename) + 1); + strcpy (da_base_file_name, filename); /* Name of bbg file. */ bbg_file_name = XNEWVEC (char, len + strlen (GCOV_NOTE_SUFFIX) + 1); @@ -1670,17 +1785,11 @@ coverage_init (const char *filename, const char* source_name) if (flag_profile_use && L_IPO_COMP_MODE) { unsigned i; - char *da_file_name_p = da_file_name; - char *da_base_file_name_p = da_base_file_name; gcc_assert (flag_dyn_ipa); rebuild_counts_hash (); for (i = 1; i < num_in_fnames; i++) - { - get_da_file_name (module_infos[i]->da_filename); - read_counts_file (da_file_name, module_infos[i]->ident); - } - da_file_name = da_file_name_p; - da_base_file_name = da_base_file_name_p; + read_counts_file (get_da_file_name (module_infos[i]->da_filename), + module_infos[i]->ident); } } diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 77568998a44..84018510b46 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -253,7 +253,7 @@ Objective-C and Objective-C++ Dialects}. -Wparentheses -Wpedantic-ms-format -Wno-pedantic-ms-format @gol -Wpointer-arith -Wno-pointer-to-int-cast @gol -Wredundant-decls @gol --Wreturn-type -Wsequence-point -Wshadow @gol +-Wreturn-type -Wripa-opt-mismatch -Wsequence-point -Wshadow @gol -Wsign-compare -Wsign-conversion -Wstack-protector @gol -Wstrict-aliasing -Wstrict-aliasing=n @gol -Wstrict-overflow -Wstrict-overflow=@var{n} @gol @@ -333,7 +333,7 @@ Objective-C and Objective-C++ Dialects}. -fcheck-data-deps -fconserve-stack -fcprop-registers -fcrossjumping @gol -fcse-follow-jumps -fcse-skip-blocks -fcx-fortran-rules -fcx-limited-range @gol -fdata-sections -fdce -fdce @gol --fdelayed-branch -fdelete-null-pointer-checks -fdse -fdse -fripa @gol +-fdelayed-branch -fdelete-null-pointer-checks -fdse -fdse @gol -fearly-inlining -fexpensive-optimizations -ffast-math @gol -ffinite-math-only -ffloat-store -fexcess-precision=@var{style} @gol -fforward-propagate -ffunction-sections @gol @@ -363,7 +363,7 @@ Objective-C and Objective-C++ Dialects}. -freciprocal-math -fregmove -frename-registers -freorder-blocks @gol -freorder-blocks-and-partition -freorder-functions @gol -frerun-cse-after-loop -freschedule-modulo-scheduled-loops @gol --frounding-math -fsched2-use-superblocks @gol +-fripa -fripa-disallow-opt-mismatch -frounding-math -fsched2-use-superblocks @gol -fsched2-use-traces -fsched-spec-load -fsched-spec-load-dangerous @gol -fsched-stalled-insns-dep[=@var{n}] -fsched-stalled-insns[=@var{n}] @gol -fsched-group-heuristic -fsched-critical-path-heuristic @gol @@ -2803,6 +2803,7 @@ Options} and @ref{Objective-C and Objective-C++ Dialect Options}. -Wpointer-sign @gol -Wreorder @gol -Wreturn-type @gol +-Wripa-opt-mismatch @gol -Wsequence-point @gol -Wsign-compare @r{(only in C++)} @gol -Wstrict-aliasing @gol @@ -3207,6 +3208,16 @@ exceptions are @samp{main} and functions defined in system headers. This warning is enabled by @option{-Wall}. +@item -Wripa-opt-mismatch +@opindex Wripa-opt-mismatch +@opindex Wno-ripa-opt-mismatch +When doing an FDO build with @option{-fprofile-use} and @option{-fripa}, +warn if importing an axuiliary module that was built with a different +GCC command line during the profile-generate phase than the primary +module. + +This warning is enabled by @option{-Wall}. + @item -Wswitch @opindex Wswitch @opindex Wno-switch @@ -7103,6 +7114,13 @@ During the @option{-fprofile-generate} phase, this flag turns on some additional instrumentation code that enables dynamic call-graph analysis. During the @option{-fprofile-use} phase, this flag enables cross-module optimizations such as inlining. + +@item -fripa-disallow-opt-mismatch +@opindex fripa-disallow-opt-mismatch +Don't import an auxiliary module, if the GCC command line options used for this +auxiliary module during the profile-generate stage were different from those used +for the primary module. Note that any mismatches in warning-related options are +ignored for this comparison. @end table The following options control compiler behavior regarding floating diff --git a/gcc/dyn-ipa.c b/gcc/dyn-ipa.c index 99b7fd25adb..9353535f780 100644 --- a/gcc/dyn-ipa.c +++ b/gcc/dyn-ipa.c @@ -1011,7 +1011,7 @@ gcov_write_module_info (const struct gcov_info *mod_info, len += 2; /* each name string is led by a length. */ num_strings = module_info->num_quote_paths + module_info->num_bracket_paths + - module_info->num_cpp_defines; + module_info->num_cpp_defines + module_info->num_cl_args; for (i = 0; i < num_strings; i++) { gcov_unsigned_t string_len @@ -1021,7 +1021,7 @@ gcov_write_module_info (const struct gcov_info *mod_info, len += 1; /* Each string is lead by a length. */ } - len += 7; /* 7 more fields */ + len += 8; /* 8 more fields */ gcov_write_tag_length (GCOV_TAG_MODULE_INFO, len); gcov_write_unsigned (module_info->ident); @@ -1031,6 +1031,7 @@ gcov_write_module_info (const struct gcov_info *mod_info, gcov_write_unsigned (module_info->num_quote_paths); gcov_write_unsigned (module_info->num_bracket_paths); gcov_write_unsigned (module_info->num_cpp_defines); + gcov_write_unsigned (module_info->num_cl_args); /* Now write the filenames */ aligned_fname = (gcov_unsigned_t *) alloca ((filename_len + src_filename_len + 2) * diff --git a/gcc/gcov-io.c b/gcc/gcov-io.c index 1e351f1cb3b..833f7ae1215 100644 --- a/gcc/gcov-io.c +++ b/gcc/gcov-io.c @@ -511,7 +511,8 @@ gcov_read_module_info (struct gcov_module_info *mod_info, mod_info->num_quote_paths = gcov_read_unsigned (); mod_info->num_bracket_paths = gcov_read_unsigned (); mod_info->num_cpp_defines = gcov_read_unsigned (); - len -= 7; + mod_info->num_cl_args = gcov_read_unsigned (); + len -= 8; filename_len = gcov_read_unsigned (); mod_info->da_filename = (char *) xmalloc (filename_len * @@ -528,7 +529,7 @@ gcov_read_module_info (struct gcov_module_info *mod_info, len -= (src_filename_len + 1); num_strings = mod_info->num_quote_paths + mod_info->num_bracket_paths + - mod_info->num_cpp_defines; + mod_info->num_cpp_defines + mod_info->num_cl_args; for (j = 0; j < num_strings; j++) { gcov_unsigned_t string_len = gcov_read_unsigned (); diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h index e88db363069..4fccc63e0a3 100644 --- a/gcc/gcov-io.h +++ b/gcc/gcov-io.h @@ -470,6 +470,7 @@ struct gcov_module_info gcov_unsigned_t num_quote_paths; gcov_unsigned_t num_bracket_paths; gcov_unsigned_t num_cpp_defines; + gcov_unsigned_t num_cl_args; char *string_array[1]; }; diff --git a/gcc/opts.c b/gcc/opts.c index cb43729edac..cc0bff14ac9 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -731,6 +731,37 @@ flag_instrument_functions_exclude_p (tree fndecl) return false; } +/* GCC command-line options saved to the LIPO profile data file. + See detailed comment in opts.h. */ +const char **lipo_cl_args; +unsigned num_lipo_cl_args; + +/* Inspect the given GCC command-line arguments, which are part of one GCC + switch, and decide whether or not to store these to the LIPO profile data + file. */ +static void +lipo_save_cl_args (unsigned int argc, const char **argv) +{ + unsigned int i; + const char *opt = argv[0]; + /* Store the following command-line flags to the lipo profile data file: + (1) -f... (except -frandom-seed...) + (2) -m... + (3) -W... + (4) -O... + (5) --param... + */ + if (opt[0] == '-' + && (opt[1] == 'f' || opt[1] == 'm' || opt[1] == 'W' || opt[1] == 'O' + || (strstr (opt, "--param") == opt)) + && !strstr(opt, "-frandom-seed")) + { + num_lipo_cl_args += argc; + lipo_cl_args = XRESIZEVEC (const char *, lipo_cl_args, num_lipo_cl_args); + for (i = 0; i < argc; i++) + lipo_cl_args[num_lipo_cl_args - argc + i] = argv[i]; + } +} /* Decode and handle the vector of command line options. LANG_MASK contains has a single bit set representing the current @@ -766,6 +797,8 @@ handle_options (unsigned int argc, const char **argv, unsigned int lang_mask) n = handle_option (argv + i, lang_mask); + lipo_save_cl_args (n, argv + i); + if (!n) { n = 1; diff --git a/gcc/opts.h b/gcc/opts.h index 7a13fb705cf..590f6c14a71 100644 --- a/gcc/opts.h +++ b/gcc/opts.h @@ -98,6 +98,15 @@ extern const char **in_fnames; extern unsigned num_in_fnames; +/* GCC command-line arguments used during profile-gen, that are saved to the + profile data file. During profile-use, these can be compared to make sure + only those auxiliary modules are actually imported that use a compatible + set of GCC flags as the primary module. */ +extern const char **lipo_cl_args; + +/* The size of the above mentioned mentioned array. */ +extern unsigned num_lipo_cl_args; + size_t find_opt (const char *input, int lang_mask); extern void prune_options (int *argcp, char ***argvp); extern void decode_options (unsigned int argc, const char **argv); |