Hi, This patch is for google branch only.
It encodes and compresses various cc1 option strings in gcov_module_info to reduce the lipo instrumented object size. The savings are from string compression and the reduced number of relocations. More specifically, we replace the following fields in gcov_module_info gcov_unsigned_t num_quote_paths; gcov_unsigned_t num_bracket_paths; gcov_unsigned_t num_system_paths; gcov_unsigned_t num_cpp_defines; gcov_unsigned_t num_cpp_includes; gcov_unsigned_t num_cl_args; char *string_array[1]; with gcov_unsigned_t cc1_strlen; gcov_unsigned_t cc1_uncompressed_strlen; char *saved_cc1_strings; The new saved_cc1_strings are zlib compressed string. Tested with google internal benchmarks. Thanks, -Rong
2015-10-05 Rong Xu <x...@google.com> * gcc/Makefile.in (gcov-dump): link with zlib (gcov-tool): Ditto. * gcc/auto-profile.c (autofdo_module_profile::read): convert old gcov_module_info to the new format. (read_aux_modules): using new incompatible_cl_args interface. * gcc/coverage.c (zlib.h): new include. (enum lipo_cc1_string_kind): new define. (struct lipo_parsed_cc1_string): new define. (incompatible_cl_args): change the paramter. (read_counts_file): using new gcov_module_info. (build_fn_info_type): remove used parameter. (build_gcov_module_info_type): using new gcov_module_info. (free_parsed_string): new function. (find_substr): ditto. (lipo_parse_saved_cc1_string): ditto. (lipo_append_tag): ditto. (build_gcov_module_info_value): using new gcov_module_info. (coverage_obj_init): remove used parameter. (add_module_info): using new gcov_module_info. (process_include): ditto. (process_include_paths_1): ditto. (process_include_paths): ditto. (set_lipo_c_parsing_context): ditto. * gcc/coverage.h: add new decls. * gcc/gcov-io.c (zlib.h) new include. (gcov_read_module_info): using new gcov_module_info. * gcc/gcov-io.h (struct gcov_module_info): new gcov_module_info. * libgcc/dyn-ipa.c: delete unused code. * libgcc/libgcov-driver.c (gcov_write_module_info): using new gcov_module_info. Index: gcc/Makefile.in =================================================================== --- gcc/Makefile.in (revision 228354) +++ gcc/Makefile.in (working copy) @@ -2583,7 +2583,7 @@ gcov$(exeext): $(GCOV_OBJS) $(LIBDEPS) GCOV_DUMP_OBJS = gcov-dump.o vec.o ggc-none.o gcov-dump$(exeext): $(GCOV_DUMP_OBJS) $(LIBDEPS) +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) $(GCOV_DUMP_OBJS) \ - $(LIBS) -o $@ + $(LIBS) $(ZLIB) -o $@ GCOV_TOOL_DEP_FILES = $(srcdir)/../libgcc/libgcov-util.c gcov-io.c $(GCOV_IO_H) \ $(srcdir)/../libgcc/libgcov-driver.c $(srcdir)/../libgcc/libgcov-driver-system.c \ @@ -2607,7 +2607,7 @@ gcov-tool-params.o: params.c $(CONFIG_H) $(SYSTEM_ GCOV_TOOL_OBJS = gcov-tool.o libgcov-util.o libgcov-driver-tool.o \ libgcov-merge-tool.o gcov-tool-dyn-ipa.o gcov-tool-params.o gcov-tool$(exeext): $(GCOV_TOOL_OBJS) $(LIBDEPS) - +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) $(GCOV_TOOL_OBJS) $(LIBS) -o $@ + +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) $(GCOV_TOOL_OBJS) $(LIBS) $(ZLIB) -o $@ # # Build the include directories. The stamp files are stmp-* rather than # s-* so that mostlyclean does not force the include directory to Index: gcc/auto-profile.c =================================================================== --- gcc/auto-profile.c (revision 228354) +++ gcc/auto-profile.c (working copy) @@ -947,7 +947,6 @@ autofdo_source_profile::get_function_instance_by_i return s; } - /* Member functions for autofdo_module_profile. */ bool @@ -972,6 +971,9 @@ autofdo_module_profile::read () unsigned exported = gcov_read_unsigned (); unsigned lang = gcov_read_unsigned (); unsigned ggc_memory = gcov_read_unsigned (); + unsigned marker = 0, len = 0, k; + char **string_array, *saved_cc1_strings; + for (unsigned j = 0; j < 7; j++) { num_array[j] = gcov_read_unsigned (); @@ -988,19 +990,48 @@ autofdo_module_profile::read () module->ident = i + 1; module->lang = lang; module->ggc_memory = ggc_memory; - module->num_quote_paths = num_array[1]; - module->num_bracket_paths = num_array[2]; - module->num_system_paths = num_array[3]; - module->num_cpp_defines = num_array[4]; - module->num_cpp_includes = num_array[5]; - module->num_cl_args = num_array[6]; module->source_filename = name; module->is_primary = strcmp (name, in_fnames[0]) == 0; module->flags = module->is_primary ? exported : 1; for (unsigned j = 0; j < num_array[0]; j++) ret.first->second.first.safe_push (xstrdup (gcov_read_string ())); + + string_array = (char **) alloca ((total_num - num_array[0]) + * sizeof (char*)); for (unsigned j = 0; j < total_num - num_array[0]; j++) - module->string_array[j] = xstrdup (gcov_read_string ()); + string_array[j] = xstrdup (gcov_read_string ()); + + k = 0; + for (unsigned j = 1; j < 7; j++) + { + if (num_array[j] == 0) + continue; + marker += num_array[j]; + len += 3; /* [[<FLAG> */ + for (; k < marker; k++) + len += strlen (string_array[k]) + 1; /* 1 for delimter of ']' */ + } + saved_cc1_strings = (char *) xmalloc (len + 1); + saved_cc1_strings[0] = 0; + + marker = 0; + k = 0; + for (unsigned j = 1; j < 7; j++) + { + static const char lipo_string_flags[6] = {'Q', 'B', 'S', 'D','I', 'C'}; + if (num_array[j] == 0) + continue; + marker += num_array[j]; + sprintf (saved_cc1_strings, "%s[[%c", saved_cc1_strings, + lipo_string_flags[j - 1]); + for (; k < marker; k++) + { + sprintf (saved_cc1_strings, "%s%s]", saved_cc1_strings, + string_array[k]); + free (string_array[k]); + } + } + module->saved_cc1_strings = saved_cc1_strings; } return true; } @@ -1071,6 +1102,10 @@ read_aux_modules (void) record_module_name (module->ident, lbasename (in_fnames[0])); if (aux_modules == NULL) return; + + struct lipo_parsed_cc1_string * module_cl_args = + lipo_parse_saved_cc1_string (module->source_filename, + module->saved_cc1_strings, true); unsigned curr_module = 1, max_group = PARAM_VALUE (PARAM_MAX_LIPO_GROUP); int i; char *str; @@ -1107,17 +1142,23 @@ read_aux_modules (void) inform (0, "Not importing %s: maximum group size reached", str); continue; } - if (incompatible_cl_args (module, aux_module)) + struct lipo_parsed_cc1_string * aux_module_cl_args = + lipo_parse_saved_cc1_string (aux_module->source_filename, + aux_module->saved_cc1_strings, true); + if (incompatible_cl_args (module_cl_args, aux_module_cl_args)) { if (flag_opt_info) inform (0, "Not importing %s: command-line" " arguments not compatible with primary module", str); + free_parsed_string (aux_module_cl_args); continue; } module_infos[curr_module++] = aux_module; add_input_filename (str); record_module_name (aux_module->ident, lbasename (str)); + free_parsed_string (aux_module_cl_args); } + free_parsed_string (module_cl_args); } /* From AutoFDO profiles, find values inside STMT for that we want to measure Index: gcc/coverage.c =================================================================== --- gcc/coverage.c (revision 228354) +++ gcc/coverage.c (working copy) @@ -76,6 +76,7 @@ along with GCC; see the file COPYING3. If not see #include "input.h" #include "pointer-set.h" #include "auto-profile.h" +#include "zlib.h" struct GTY((chain_next ("%h.next"))) coverage_data { @@ -187,7 +188,7 @@ static bool has_asm_statement; /* Forward declarations. */ static void read_counts_file (const char *, unsigned); static tree build_var (tree, tree, int); -static void build_fn_info_type (tree, unsigned, tree); +static void build_fn_info_type (tree, unsigned); static void build_info_type (tree, tree); static tree build_fn_info (const struct coverage_data *, tree); static tree build_info (tree, tree); @@ -342,16 +343,51 @@ has_incompatible_cg_opts (bool *cg_opts1, bool *cg return false; } +#define DELIMTER "[[" +#define DELIMTER2 "]" +#define QUOTE_PATH_FLAG 'Q' +#define BRACKET_PATH_FLAG 'B' +#define SYSTEM_PATH_FLAG 'S' +#define D_U_OPTION_FLAG 'D' +#define INCLUDE_OPTION_FLAG 'I' +#define COMMAND_ARG_FLAG 'C' + +enum lipo_cc1_string_kind { + k_quote_paths = 0, + k_bracket_paths, + k_system_paths, + k_cpp_defines, + k_cpp_includes, + k_lipo_cl_args, + num_lipo_cc1_string_kind +}; + +struct lipo_parsed_cc1_string { + const char* source_filename; + unsigned num[num_lipo_cc1_string_kind]; + char **strings[num_lipo_cc1_string_kind]; +}; + +struct lipo_parsed_cc1_string * +lipo_parse_saved_cc1_string (const char *src, char *str, + bool parse_cl_args_only); +void free_parsed_string (struct lipo_parsed_cc1_string *string); + /* Returns true if the command-line arguments stored in the given module-infos are incompatible. */ bool -incompatible_cl_args (struct gcov_module_info* mod_info1, - struct gcov_module_info* mod_info2) +incompatible_cl_args (struct lipo_parsed_cc1_string* mod_info1, + struct lipo_parsed_cc1_string* 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 num_cl_args_1 = mod_info1->num[k_lipo_cl_args]; + unsigned num_cl_args_2 = mod_info2->num[k_lipo_cl_args]; + char **string_array_1 = mod_info1->strings[k_lipo_cl_args]; + char **string_array_2 = mod_info2->strings[k_lipo_cl_args]; + + char **warning_opts1 = XNEWVEC (char *, num_cl_args_1); + char **warning_opts2 = XNEWVEC (char *, num_cl_args_2); + char **non_warning_opts1 = XNEWVEC (char *, num_cl_args_1); + char **non_warning_opts2 = XNEWVEC (char *, num_cl_args_2); char *std_opts1 = NULL, *std_opts2 = NULL; unsigned arch_isa1 = 0, arch_isa2 = 0; unsigned int i, num_warning_opts1 = 0, num_warning_opts2 = 0; @@ -359,12 +395,6 @@ bool bool warning_mismatch = false; bool non_warning_mismatch = false; hash_table <string_hasher> option_tab1, option_tab2; - unsigned int start_index1 = mod_info1->num_quote_paths - + mod_info1->num_bracket_paths + mod_info1->num_system_paths - + mod_info1->num_cpp_defines + mod_info1->num_cpp_includes; - unsigned int start_index2 = mod_info2->num_quote_paths - + mod_info2->num_bracket_paths + mod_info2->num_system_paths - + mod_info2->num_cpp_defines + mod_info2->num_cpp_includes; bool *cg_opts1, *cg_opts2, has_any_incompatible_cg_opts, has_incompatible_std; bool has_incompatible_arch_isa; @@ -387,14 +417,13 @@ bool option_tab2.create (10); /* 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]; + for (i = 0; i < num_cl_args_1; i++) + if (string_array_1[i][1] == 'W') + warning_opts1[num_warning_opts1++] = string_array_1[i]; else { char **slot; - char *option_string = mod_info1->string_array[start_index1 + i]; + char *option_string = string_array_1[i]; check_cg_opts (cg_opts1, option_string); if (strstr (option_string, "-std=")) @@ -411,14 +440,13 @@ bool } } - 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]; + for (i = 0; i < num_cl_args_2; i++) + if (string_array_2[i][1] == 'W') + warning_opts2[num_warning_opts2++] = string_array_2[i]; else { char **slot; - char *option_string = mod_info2->string_array[start_index2 + i]; + char *option_string = string_array_2[i]; check_cg_opts (cg_opts2, option_string); if (strstr (option_string, "-std=")) @@ -710,6 +738,7 @@ read_counts_file (const char *da_file_name, unsign unsigned lineno_checksum = 0; unsigned cfg_checksum = 0; const char *imports_filename; + struct lipo_parsed_cc1_string *primary_mod_info_cl_args = NULL; if (max_group == 0) max_group = (unsigned) -1; @@ -891,6 +920,7 @@ read_counts_file (const char *da_file_name, unsign else if (tag == GCOV_TAG_MODULE_INFO && flag_dyn_ipa && !module_id) { struct gcov_module_info* mod_info; + struct lipo_parsed_cc1_string *mod_info_cl_args = NULL; size_t info_sz; /* each string has at least 8 bytes, so MOD_INFO's persistent length >= in core size. */ @@ -898,13 +928,7 @@ read_counts_file (const char *da_file_name, unsign = (struct gcov_module_info *) alloca ((length + 2) * sizeof (gcov_unsigned_t)); gcov_read_module_info (mod_info, length); - info_sz = (sizeof (struct gcov_module_info) + - sizeof (void *) * (mod_info->num_quote_paths + - mod_info->num_bracket_paths + - mod_info->num_system_paths + - mod_info->num_cpp_defines + - mod_info->num_cpp_includes + - mod_info->num_cl_args)); + info_sz = sizeof (struct gcov_module_info); /* The first MODULE_INFO record must be for the primary module. */ if (module_infos_read == 0) { @@ -917,6 +941,8 @@ read_counts_file (const char *da_file_name, unsign module_infos = XCNEWVEC (struct gcov_module_info *, 1); module_infos[0] = XCNEWVAR (struct gcov_module_info, info_sz); memcpy (module_infos[0], mod_info, info_sz); + primary_mod_info_cl_args = lipo_parse_saved_cc1_string ( + mod_info->source_filename, mod_info->saved_cc1_strings, true); } else { @@ -923,6 +949,8 @@ read_counts_file (const char *da_file_name, unsign int fd; char *aux_da_filename = get_da_file_name (mod_info->da_filename); gcc_assert (!mod_info->is_primary); + mod_info_cl_args = lipo_parse_saved_cc1_string ( + mod_info->source_filename, mod_info->saved_cc1_strings, true); if (pointer_set_insert (modset, (void *)(size_t)mod_info->ident)) { if (dump_enabled_p ()) @@ -950,7 +978,8 @@ read_counts_file (const char *da_file_name, unsign "Not importing %s: maximum group size" " reached", mod_info->source_filename); } - else if (incompatible_cl_args (module_infos[0], mod_info)) + else if (incompatible_cl_args (primary_mod_info_cl_args, + mod_info_cl_args)) { if (dump_enabled_p ()) dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, input_location, @@ -1012,6 +1041,7 @@ read_counts_file (const char *da_file_name, unsign mod_info->source_filename, mod_info->da_filename); } + free_parsed_string (mod_info_cl_args); } gcov_sync (offset, length); if ((is_error = gcov_is_error ())) @@ -1023,6 +1053,8 @@ read_counts_file (const char *da_file_name, unsign } } + free_parsed_string (primary_mod_info_cl_args); + if ((imports_filename = getenv ("LIPO_REORDER_GROUP")) && flag_dyn_ipa && !module_id) { @@ -1647,7 +1679,7 @@ build_var (tree fn_decl, tree type, int counter) /* Creates the gcov_fn_info RECORD_TYPE. */ static void -build_fn_info_type (tree type, unsigned counters, tree gcov_info_type) +build_fn_info_type (tree type, unsigned counters) { tree ctr_info = lang_hooks.types.make_type (RECORD_TYPE); tree field, fields; @@ -1954,11 +1986,8 @@ static tree build_gcov_module_info_type (void) { tree type, field, fields = NULL_TREE; - tree string_type, index_type, string_array_type; + tree string_type; - cpp_dir *quote_paths, *bracket_paths, *system_paths, *pdir; - int num_quote_paths = 0, num_bracket_paths = 0, num_system_paths = 0; - type = lang_hooks.types.make_type (RECORD_TYPE); string_type = build_pointer_type ( build_qualified_type (char_type_node, @@ -2011,76 +2040,152 @@ build_gcov_module_info_type (void) DECL_CHAIN (field) = fields; fields = field; - /* Num quote paths */ + /* cc1_strlen field */ field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); DECL_CHAIN (field) = fields; fields = field; - /* Num bracket paths */ + /* cc1_uncompressed_strlen field */ field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); DECL_CHAIN (field) = fields; fields = field; - /* Num system paths */ + /* Saved cc1 strings */ field = build_decl (BUILTINS_LOCATION, FIELD_DECL, - NULL_TREE, get_gcov_unsigned_t ()); + NULL_TREE, string_type); DECL_CHAIN (field) = fields; fields = field; - /* Num -D/-U options. */ - field = build_decl (BUILTINS_LOCATION, FIELD_DECL, - NULL_TREE, get_gcov_unsigned_t ()); - DECL_CHAIN (field) = fields; - fields = field; + finish_builtin_struct (type, "__gcov_module_info", fields, NULL_TREE); - /* Num -imacro/-include options. */ - field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE, - get_gcov_unsigned_t ()); - DECL_CHAIN (field) = fields; - fields = field; + return type; +} - /* Num command-line args. */ - field = build_decl (BUILTINS_LOCATION, FIELD_DECL, - NULL_TREE, get_gcov_unsigned_t ()); - DECL_CHAIN (field) = fields; - fields = field; +/* Free the malloc memory for struct lipo_parsed_cc1_string. */ - get_include_chains ("e_paths, &bracket_paths, &system_paths); - for (pdir = quote_paths; pdir; pdir = pdir->next) - { - if (pdir == bracket_paths) +void +free_parsed_string (struct lipo_parsed_cc1_string *string) +{ + unsigned k; + + if (string == NULL) + return; + for (k = 0; k < (int) num_lipo_cc1_string_kind; k++) + free (string->strings[k]); + free (string); +} + +/* Find the next encoded string. */ + +static inline char * +find_substr (char *str) +{ + char *substr = strstr(str, DELIMTER); + char ch; + if (substr == NULL || strlen(substr) < 2) + return str + strlen(str);; + ch = substr[2]; + if (ch == QUOTE_PATH_FLAG || + ch == BRACKET_PATH_FLAG || + ch == SYSTEM_PATH_FLAG || + ch == D_U_OPTION_FLAG || + ch == INCLUDE_OPTION_FLAG || + ch == COMMAND_ARG_FLAG) + return substr; + return str + strlen(str);; +} + +/* Parsing lipo cc1 strings in module info. Note that the STR is modified + after this function. The modification is to replace delimiter with \0. */ + +struct lipo_parsed_cc1_string * +lipo_parse_saved_cc1_string (const char *src, char *str, bool parse_cl_args_only) +{ + char *substr_begin; + unsigned size = sizeof (struct lipo_parsed_cc1_string); + + struct lipo_parsed_cc1_string *ret = (struct lipo_parsed_cc1_string *) + xmalloc (size); + memset (ret, 0, size); + ret->source_filename = src; + + substr_begin = find_substr (str); + if (substr_begin == str + strlen(str)) + return ret; + do { + char *p, *p1, *substr_end; + char **pp; + unsigned i; + enum lipo_cc1_string_kind k; + + switch (substr_begin[2]) { + case QUOTE_PATH_FLAG: + k = k_quote_paths; break; - num_quote_paths++; - } - for (pdir = bracket_paths; pdir; pdir = pdir->next) - { - if (pdir == system_paths) + case BRACKET_PATH_FLAG: + k = k_bracket_paths; break; - num_bracket_paths++; + case SYSTEM_PATH_FLAG: + k = k_system_paths; + break; + case D_U_OPTION_FLAG: + k = k_cpp_defines; + break; + case INCLUDE_OPTION_FLAG: + k = k_cpp_includes; + break; + case COMMAND_ARG_FLAG: + k = k_lipo_cl_args; + break; + default: + gcc_unreachable (); } - for (pdir = system_paths; pdir; pdir = pdir->next) - num_system_paths++; + substr_end = find_substr (substr_begin + 2); - /* string array */ - index_type = build_index_type (build_int_cst (NULL_TREE, - num_quote_paths + - num_bracket_paths + - num_system_paths + - num_cpp_defines + - num_cpp_includes + - num_lipo_cl_args)); + if (!parse_cl_args_only || k == k_lipo_cl_args) + { + /* Count number of space char b/w start and end. */ + i = 0; + p = substr_begin + 3; + p1 = p; + while (p != substr_end) { + if (*p == ']') + i++; + p++; + } + ret->num[k] = i; + pp = (char **) xmalloc ((i + 1) * sizeof (char *)); + ret->strings[k] = pp; + /* Replace the delimiter with \0. */ + *pp = p = p1; + while (p != substr_end) { + if (*p == ']') + { + *p = 0; + *(++pp) = p + 1; + } + p++; + } + } - string_array_type = build_array_type (string_type, index_type); - field = build_decl (BUILTINS_LOCATION, FIELD_DECL, - NULL_TREE, string_array_type); - DECL_CHAIN (field) = fields; - fields = field; + substr_begin = substr_end; + } while (*substr_begin); - finish_builtin_struct (type, "__gcov_module_info", fields, NULL_TREE); + return ret; +} - return type; +/* Append TAG to string STRINGS. */ +static inline void +lipo_append_tag (char *strings, char tag) +{ + int i; + + strcat (strings, DELIMTER); + i = strlen (strings); + strings[i] = tag; + strings[i + 1] = 0; } /* Returns the value of the module info associated with the @@ -2092,12 +2197,17 @@ build_gcov_module_info_value (tree mod_type) tree info_fields, mod_info; tree value = NULL_TREE; int file_name_len; - tree filename_string, string_array_type, string_type; + tree filename_string, string_type, saved_string; cpp_dir *quote_paths, *bracket_paths, *system_paths, *pdir; - int num_quote_paths = 0, num_bracket_paths = 0, num_system_paths = 0; + int num_quote_paths = 0, num_bracket_paths = 0, num_system_paths = 0, i; unsigned lang; char name_buf[50]; - vec<constructor_elt,va_gc> *v = NULL, *path_v = NULL; + vec<constructor_elt,va_gc> *v = NULL; + unsigned string_len; + char *compressed_strings; + unsigned long dest_len, src_len, total_length, ui; + struct str_list *head; + char *strings; info_fields = TYPE_FIELDS (mod_type); @@ -2181,57 +2291,128 @@ build_gcov_module_info_value (tree mod_type) for (pdir = system_paths; pdir; pdir = pdir->next) num_system_paths++; - /* Num quote paths */ - CONSTRUCTOR_APPEND_ELT (v, info_fields, - build_int_cstu (get_gcov_unsigned_t (), - num_quote_paths)); - info_fields = DECL_CHAIN (info_fields); + total_length = 1; /* space for \0. */ + /* quote paths */ + total_length += 3; + for (i = 0, pdir = quote_paths; i < num_quote_paths; i++) + { + total_length += strlen (pdir->name) + 1; + pdir = pdir->next; + } - /* Num bracket paths */ - CONSTRUCTOR_APPEND_ELT (v, info_fields, - build_int_cstu (get_gcov_unsigned_t (), - num_bracket_paths)); - info_fields = DECL_CHAIN (info_fields); + /* bracket paths */ + total_length += 3; + for (i = 0, pdir = bracket_paths; i < num_bracket_paths; i++) + { + total_length += strlen (pdir->name) + 1; + pdir = pdir->next; + } - /* Num system paths */ - CONSTRUCTOR_APPEND_ELT (v, info_fields, - build_int_cstu (get_gcov_unsigned_t (), - num_system_paths)); - info_fields = DECL_CHAIN (info_fields); + /* system paths */ + total_length += 3; + for (i = 0, pdir = system_paths; i < num_system_paths; i++) + { + total_length += strlen (pdir->name) + 1; + pdir = pdir->next; + } - /* Num -D/-U options. */ - CONSTRUCTOR_APPEND_ELT (v, info_fields, - build_int_cstu (get_gcov_unsigned_t (), - num_cpp_defines)); - info_fields = DECL_CHAIN (info_fields); + /* -D/-U options */ + total_length += 3; + head = cpp_defines_head; + while (head) + { + total_length += strlen (head->str) + 1; + head = head->next; + } - /* Num -imacro/-include options. */ + /* -imacro/-include options */ + total_length += 3; + head = cpp_includes_head; + while (head) + { + total_length += strlen (head->str) + 1; + head = head->next; + } + + /* Num command-line args */ + total_length += 3; + for (ui = 0; ui < num_lipo_cl_args; ui++) + total_length += strlen (lipo_cl_args[ui]) + 1; + + strings = (char*) xmalloc (total_length); + *strings = 0; + + lipo_append_tag (strings, QUOTE_PATH_FLAG); + for (i = 0, pdir = quote_paths; i < num_quote_paths; i++) + { + strcat(strings, pdir->name); + strcat(strings, DELIMTER2); + pdir = pdir->next; + } + + lipo_append_tag (strings, BRACKET_PATH_FLAG); + for (i = 0, pdir = bracket_paths; i < num_bracket_paths; i++) + { + strcat(strings, pdir->name); + strcat(strings, DELIMTER2); + pdir = pdir->next; + } + + lipo_append_tag (strings, SYSTEM_PATH_FLAG); + for (i = 0, pdir = system_paths; i < num_system_paths; i++) + { + strcat(strings, pdir->name); + strcat(strings, DELIMTER2); + pdir = pdir->next; + } + + lipo_append_tag (strings, D_U_OPTION_FLAG); + head = cpp_defines_head; + while (head) + { + strcat(strings, head->str); + strcat(strings, DELIMTER2); + head = head->next; + } + + lipo_append_tag (strings, INCLUDE_OPTION_FLAG); + head = cpp_includes_head; + while (head) + { + strcat(strings, head->str); + strcat(strings, DELIMTER2); + head = head->next; + } + + lipo_append_tag (strings, COMMAND_ARG_FLAG); + for (ui = 0; ui < num_lipo_cl_args; ui++) + { + strcat(strings, lipo_cl_args[ui]); + strcat(strings, DELIMTER2); + } + string_len = strlen (strings) + 1; + compressed_strings = (char*) xmalloc (string_len); + dest_len = string_len; + src_len = string_len; + compress ((Bytef *)compressed_strings, &dest_len, (const Bytef *)strings, src_len); + + /* cc1_strlen field */ CONSTRUCTOR_APPEND_ELT (v, info_fields, - build_int_cstu (get_gcov_unsigned_t (), - num_cpp_includes)); + build_int_cstu (get_gcov_unsigned_t (), dest_len)); info_fields = DECL_CHAIN (info_fields); - - /* Num command-line args. */ + /* cc1_uncompressed_strlen field */ CONSTRUCTOR_APPEND_ELT (v, info_fields, - build_int_cstu (get_gcov_unsigned_t (), - num_lipo_cl_args)); + build_int_cstu (get_gcov_unsigned_t (), src_len)); info_fields = DECL_CHAIN (info_fields); - /* string array */ - string_array_type = TREE_TYPE (info_fields); - build_inc_path_array_value (string_type, &path_v, - quote_paths, num_quote_paths); - build_inc_path_array_value (string_type, &path_v, - bracket_paths, num_bracket_paths); - build_inc_path_array_value (string_type, &path_v, - system_paths, num_system_paths); - build_str_array_value (string_type, &path_v, - cpp_defines_head); - build_str_array_value (string_type, &path_v, - cpp_includes_head); - build_cl_args_array_value (string_type, &path_v); + strings = compressed_strings; + string_len = dest_len; + saved_string = build_string (string_len, strings); + TREE_TYPE (saved_string) = build_array_type + (char_type_node, build_index_type + (build_int_cst (NULL_TREE, string_len))); CONSTRUCTOR_APPEND_ELT (v, info_fields, - build_constructor (string_array_type, path_v)); + build1 (ADDR_EXPR, string_type, saved_string)); info_fields = DECL_CHAIN (info_fields); gcc_assert (!info_fields); @@ -2523,7 +2704,7 @@ coverage_obj_init (void) gcov_fn_info_type = lang_hooks.types.make_type (RECORD_TYPE); gcov_fn_info_ptr_type = build_pointer_type (build_qualified_type (gcov_fn_info_type, TYPE_QUAL_CONST)); - build_fn_info_type (gcov_fn_info_type, n_counters, gcov_info_type); + build_fn_info_type (gcov_fn_info_type, n_counters); build_info_type (gcov_info_type, gcov_fn_info_ptr_type); /* Build the gcov info var, this is referred to in its own @@ -2703,8 +2884,6 @@ add_module_info (unsigned module_id, bool is_prima cur_info = module_infos[index]; cur_info->ident = module_id; SET_MODULE_EXPORTED (cur_info); - cur_info->num_quote_paths = 0; - cur_info->num_bracket_paths = 0; cur_info->da_filename = NULL; cur_info->source_filename = NULL; if (is_primary) @@ -2748,21 +2927,20 @@ process_include (char **orig_inc_path, char* old_s -fripa-inc-path-sub=OLD_SUB:NEW_SUB */ static void -process_include_paths_1 (struct gcov_module_info *mod_info, +process_include_paths_1 (struct lipo_parsed_cc1_string *mod_info_str, char* old_sub, char *new_sub) { - unsigned i, j; + unsigned i; + enum lipo_cc1_string_kind k; - for (i = 0; i < mod_info->num_quote_paths; i++) - process_include (&mod_info->string_array[i], old_sub, new_sub); + for (i = 0, k = k_quote_paths; i < mod_info_str->num[k]; i++) + process_include (&mod_info_str->strings[k][i], old_sub, new_sub); - for (i = 0, j = mod_info->num_quote_paths; - i < mod_info->num_bracket_paths; i++, j++) - process_include (&mod_info->string_array[j], old_sub, new_sub); + for (i = 0, k = k_bracket_paths; i < mod_info_str->num[k]; i++) + process_include (&mod_info_str->strings[k][i], old_sub, new_sub); - for (i = 0, j = mod_info->num_quote_paths + mod_info->num_bracket_paths + - mod_info->num_cpp_defines; i < mod_info->num_cpp_includes; i++, j++) - process_include (&mod_info->string_array[j], old_sub, new_sub); + for (i = 0, k = k_cpp_includes; i < mod_info_str->num[k]; i++) + process_include (&mod_info_str->strings[k][i], old_sub, new_sub); } @@ -2770,7 +2948,7 @@ static void -fripa-inc-path-sub=old_sub1:new_sub1[,old_sub2:new_sub2] */ static void -process_include_paths (struct gcov_module_info *mod_info) +process_include_paths (struct lipo_parsed_cc1_string *mod_info_str) { char *sub_pattern, *cur, *next, *new_sub; @@ -2793,7 +2971,7 @@ static void return; } *new_sub++ = '\0'; - process_include_paths_1 (mod_info, cur, new_sub); + process_include_paths_1 (mod_info_str, cur, new_sub); cur = next; } while (cur); free (sub_pattern); @@ -2818,34 +2996,36 @@ set_lipo_c_parsing_context (struct cpp_reader *par if (current_module_id != primary_module_id) { - unsigned i, j; + unsigned i; + enum lipo_cc1_string_kind k; + struct lipo_parsed_cc1_string *mod_info_str = + lipo_parse_saved_cc1_string (mod_info->source_filename, + mod_info->saved_cc1_strings, false); - process_include_paths (mod_info); + process_include_paths (mod_info_str); /* Setup include paths. */ clear_include_chains (); - for (i = 0; i < mod_info->num_quote_paths; i++) - add_path (xstrdup (mod_info->string_array[i]), - QUOTE, 0, 1); - for (i = 0, j = mod_info->num_quote_paths; - i < mod_info->num_bracket_paths; i++, j++) - add_path (xstrdup (mod_info->string_array[j]), - BRACKET, 0, 1); - for (i = 0; i < mod_info->num_system_paths; i++, j++) - add_path (xstrdup (mod_info->string_array[j]), - SYSTEM, 0, 1); - register_include_chains (parse_in, NULL, NULL, NULL, - 0, 0, verbose); + for (i = 0, k = k_quote_paths; i < mod_info_str->num[k]; i++) + add_path (xstrdup (mod_info_str->strings[k][i]), QUOTE, 0, 1); + for (i = 0, k = k_bracket_paths; i < mod_info_str->num[k]; i++) + add_path (xstrdup (mod_info_str->strings[k][i]), BRACKET, 0, 1); + for (i = 0, k = k_system_paths; i < mod_info_str->num[k]; i++) + add_path (xstrdup (mod_info_str->strings[k][i]), SYSTEM, 0, 1); + register_include_chains (parse_in, NULL, NULL, NULL, 0, 0, verbose); /* Setup defines/undefs. */ - for (i = 0; i < mod_info->num_cpp_defines; i++, j++) - if (mod_info->string_array[j][0] == 'D') - cpp_define (parse_in, mod_info->string_array[j] + 1); - else - cpp_undef (parse_in, mod_info->string_array[j] + 1); + for (i = 0, k = k_cpp_defines; i < mod_info_str->num[k]; i++) + if (mod_info_str->strings[k][i][0] == 'D') + cpp_define (parse_in, mod_info_str->strings[k][i] + 1); + else + cpp_undef (parse_in, mod_info_str->strings[k][i] + 1); /* Setup -imacro/-include. */ - for (i = 0; i < mod_info->num_cpp_includes; i++, j++) - cpp_push_include (parse_in, mod_info->string_array[j]); + for (i = 0, k = k_cpp_includes; i < mod_info_str->num[k]; i++) + cpp_push_include (parse_in, mod_info_str->strings[k][i]); + + /* free mode_info_str */ + free_parsed_string (mod_info_str); } } Index: gcc/coverage.h =================================================================== --- gcc/coverage.h (revision 228354) +++ gcc/coverage.h (working copy) @@ -86,8 +86,12 @@ extern tree get_const_string_type (void); /* Mark this module as containing asm statements. */ extern void coverage_has_asm_stmt (void); -extern bool incompatible_cl_args (struct gcov_module_info *, - struct gcov_module_info *); +struct lipo_parsed_cc1_string; +struct lipo_parsed_cc1_string * lipo_parse_saved_cc1_string (const char *src, + char *str, bool parse_cl_args_only); +void free_parsed_string (struct lipo_parsed_cc1_string *string); +extern bool incompatible_cl_args (struct lipo_parsed_cc1_string *, + struct lipo_parsed_cc1_string *); /* Defined in tree-profile.c. */ extern void tree_init_instrumentation_sampling (void); Index: gcc/gcov-io.c =================================================================== --- gcc/gcov-io.c (revision 228354) +++ gcc/gcov-io.c (working copy) @@ -803,23 +803,22 @@ gcov_read_build_info (gcov_unsigned_t length, gcov #if (!IN_LIBGCOV && IN_GCOV != 1) || defined (IN_GCOV_TOOL) /* Read LEN words (unsigned type) and construct MOD_INFO. */ +#include "zlib.h" + GCOV_LINKAGE void gcov_read_module_info (struct gcov_module_info *mod_info, gcov_unsigned_t len) { - gcov_unsigned_t src_filename_len, filename_len, i, num_strings; + gcov_unsigned_t src_filename_len, filename_len, i; + char *compressed_array, *uncompressed_array; + gcov_unsigned_t tag_len; + unsigned long saved_compressed_len, saved_uncompressed_len, result_len; mod_info->ident = gcov_read_unsigned (); mod_info->is_primary = gcov_read_unsigned (); mod_info->flags = gcov_read_unsigned (); mod_info->lang = gcov_read_unsigned (); mod_info->ggc_memory = gcov_read_unsigned (); - mod_info->num_quote_paths = gcov_read_unsigned (); - mod_info->num_bracket_paths = gcov_read_unsigned (); - mod_info->num_system_paths = gcov_read_unsigned (); - mod_info->num_cpp_defines = gcov_read_unsigned (); - mod_info->num_cpp_includes = gcov_read_unsigned (); - mod_info->num_cl_args = gcov_read_unsigned (); - len -= 11; + len -= 5; filename_len = gcov_read_unsigned (); mod_info->da_filename = (char *) xmalloc (filename_len * @@ -830,17 +829,27 @@ gcov_read_module_info (struct gcov_module_info *mo src_filename_len = gcov_read_unsigned (); mod_info->source_filename = (char *) xmalloc (src_filename_len * - sizeof (gcov_unsigned_t)); + sizeof (gcov_unsigned_t)); for (i = 0; i < src_filename_len; i++) ((gcov_unsigned_t *) mod_info->source_filename)[i] = gcov_read_unsigned (); len -= (src_filename_len + 1); - num_strings = mod_info->num_quote_paths + mod_info->num_bracket_paths - + mod_info->num_system_paths - + mod_info->num_cpp_defines + mod_info->num_cpp_includes - + mod_info->num_cl_args; - len -= gcov_read_string_array (mod_info->string_array, num_strings); + saved_compressed_len = (unsigned long) gcov_read_unsigned (); + saved_uncompressed_len = (unsigned long) gcov_read_unsigned (); + tag_len = gcov_read_unsigned (); + len -= (tag_len + 3); gcc_assert (!len); + compressed_array = (char *) xmalloc (tag_len * sizeof (gcov_unsigned_t)); + uncompressed_array = (char *) xmalloc (saved_uncompressed_len); + for (i = 0; i < tag_len; i++) + ((gcov_unsigned_t *) compressed_array)[i] = gcov_read_unsigned (); + + result_len = saved_uncompressed_len; + uncompress ((Bytef *)uncompressed_array, &result_len, + (const Bytef *)compressed_array, saved_compressed_len); + gcc_assert (result_len == saved_uncompressed_len); + mod_info->saved_cc1_strings = uncompressed_array; + free (compressed_array); } #endif Index: gcc/gcov-io.h =================================================================== --- gcc/gcov-io.h (revision 228354) +++ gcc/gcov-io.h (working copy) @@ -421,13 +421,17 @@ struct gcov_module_info gcov_unsigned_t ggc_memory; /* memory needed for parsing in kb */ char *da_filename; char *source_filename; - gcov_unsigned_t num_quote_paths; - gcov_unsigned_t num_bracket_paths; - gcov_unsigned_t num_system_paths; - gcov_unsigned_t num_cpp_defines; - gcov_unsigned_t num_cpp_includes; - gcov_unsigned_t num_cl_args; - char *string_array[1]; + /* we encode and compress various cc1 options to one string + to SAVED_CC1_STRINGS field. CC1_STRLEN is the compressed + size. CC1_UNCOMPRESSED_STRLEN is the original (uncompressed) string + length. For the encoding, all the string options are separated by ']'. + (as the original string can contain ' '. Quoted_paths start with + "[[Q". Bracket_paths start with "[[B". System_paths start with + "[[S". Cpp_defines start with "[[D". Cpp_includes start with + "[[I". Command line arguments (cl_args) start with "[[C". */ + gcov_unsigned_t cc1_strlen; + gcov_unsigned_t cc1_uncompressed_strlen; + char *saved_cc1_strings; }; extern struct gcov_module_info **module_infos; Index: libgcc/dyn-ipa.c =================================================================== --- libgcc/dyn-ipa.c (revision 228272) +++ libgcc/dyn-ipa.c (working copy) @@ -2257,67 +2257,6 @@ gcov_compute_random_module_groups (unsigned max_gr } } -#if 0 -/* Write out MOD_INFO into the gcda file. IS_PRIMARY is a flag - indicating if the module is the primary module in the group. */ - -static void -gcov_write_module_info (const struct gcov_info *mod_info, - unsigned is_primary) -{ - gcov_unsigned_t len = 0, filename_len = 0, src_filename_len = 0, i; - gcov_unsigned_t num_strings; - gcov_unsigned_t *aligned_fname; - struct gcov_module_info *module_info = mod_info->mod_info; - filename_len = (strlen (module_info->da_filename) + - sizeof (gcov_unsigned_t)) / sizeof (gcov_unsigned_t); - src_filename_len = (strlen (module_info->source_filename) + - sizeof (gcov_unsigned_t)) / sizeof (gcov_unsigned_t); - len = filename_len + src_filename_len; - 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_system_paths - + module_info->num_cpp_defines + module_info->num_cpp_includes - + module_info->num_cl_args; - len += gcov_compute_string_array_len (module_info->string_array, - num_strings); - - len += 11; /* 11 more fields */ - - gcov_write_tag_length (GCOV_TAG_MODULE_INFO, len); - gcov_write_unsigned (module_info->ident); - gcov_write_unsigned (is_primary); - if (flag_alg_mode == INCLUSION_BASED_PRIORITY_ALGORITHM && is_primary) - SET_MODULE_INCLUDE_ALL_AUX (module_info); - gcov_write_unsigned (module_info->flags); - gcov_write_unsigned (module_info->lang); - gcov_write_unsigned (module_info->ggc_memory); - gcov_write_unsigned (module_info->num_quote_paths); - gcov_write_unsigned (module_info->num_bracket_paths); - gcov_write_unsigned (module_info->num_system_paths); - gcov_write_unsigned (module_info->num_cpp_defines); - gcov_write_unsigned (module_info->num_cpp_includes); - gcov_write_unsigned (module_info->num_cl_args); - - /* Now write the filenames */ - aligned_fname = (gcov_unsigned_t *) alloca ((filename_len + src_filename_len + 2) * - sizeof (gcov_unsigned_t)); - memset (aligned_fname, 0, - (filename_len + src_filename_len + 2) * sizeof (gcov_unsigned_t)); - aligned_fname[0] = filename_len; - strcpy ((char*) (aligned_fname + 1), module_info->da_filename); - aligned_fname[filename_len + 1] = src_filename_len; - strcpy ((char*) (aligned_fname + filename_len + 2), module_info->source_filename); - - for (i = 0; i < (filename_len + src_filename_len + 2); i++) - gcov_write_unsigned (aligned_fname[i]); - - /* Now write the string array. */ - gcov_write_string_array (module_info->string_array, num_strings); -} -#endif - /* Write out MOD_INFO and its imported modules into gcda file. */ void @@ -2880,21 +2819,6 @@ static gcov_dyn_ipa_merge_fn ctr_merge_functions[G }; #undef DEF_GCOV_COUNTER -#if 0 -static gcov_dyn_ipa_merge_fn ctr_merge_functions[GCOV_COUNTERS] = { - __gcov_dyn_ipa_merge_add, - __gcov_dyn_ipa_merge_add, - __gcov_dyn_ipa_merge_add, - __gcov_dyn_ipa_merge_single, - __gcov_dyn_ipa_merge_delta, - __gcov_dyn_ipa_merge_single, - __gcov_dyn_ipa_merge_add, - __gcov_dyn_ipa_merge_ior, - __gcov_dyn_ipa_merge_icall_topn, - __gcov_dyn_ipa_merge_dc, -}; -#endif - /* Copy counters from SRC_CTRS array to DEST_CTRS array, where SRC_CTRS is indexed by the GCOV_COUNTER type, and DEST_CTRS is an array holding only the mergable counters to emit to the gcda file for DEST_GUID. */ Index: libgcc/libgcov-driver.c =================================================================== --- libgcc/libgcov-driver.c (revision 228272) +++ libgcc/libgcov-driver.c (working copy) @@ -1495,7 +1495,7 @@ gcov_write_module_info (const struct gcov_info *mo { gcov_unsigned_t len = 0, filename_len = 0, src_filename_len = 0, i; gcov_unsigned_t num_strings; - gcov_unsigned_t *aligned_fname; + gcov_unsigned_t *aligned_fname, *aligned_string, saved_cc1_strings_len; struct gcov_module_info *module_info = mod_info->mod_info; filename_len = (strlen (module_info->da_filename) + sizeof (gcov_unsigned_t)) / sizeof (gcov_unsigned_t); @@ -1504,14 +1504,11 @@ gcov_write_module_info (const struct gcov_info *mo len = filename_len + src_filename_len; 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_system_paths - + module_info->num_cpp_defines + module_info->num_cpp_includes - + module_info->num_cl_args; - len += gcov_compute_string_array_len (module_info->string_array, - num_strings); + saved_cc1_strings_len = (module_info->cc1_strlen + + sizeof (gcov_unsigned_t)) / sizeof (gcov_unsigned_t); + len += saved_cc1_strings_len + 1; /* prepend the length. */ - len += 11; /* 11 more fields */ + len += 7; /* 7 more fields */ gcov_write_tag_length (GCOV_TAG_MODULE_INFO, len); gcov_write_unsigned (module_info->ident); @@ -1519,12 +1516,6 @@ gcov_write_module_info (const struct gcov_info *mo gcov_write_unsigned (module_info->flags); gcov_write_unsigned (module_info->lang); gcov_write_unsigned (module_info->ggc_memory); - gcov_write_unsigned (module_info->num_quote_paths); - gcov_write_unsigned (module_info->num_bracket_paths); - gcov_write_unsigned (module_info->num_system_paths); - gcov_write_unsigned (module_info->num_cpp_defines); - gcov_write_unsigned (module_info->num_cpp_includes); - gcov_write_unsigned (module_info->num_cl_args); /* Now write the filenames */ aligned_fname = (gcov_unsigned_t *) alloca ((filename_len + src_filename_len + 2) * @@ -1539,8 +1530,17 @@ gcov_write_module_info (const struct gcov_info *mo for (i = 0; i < (filename_len + src_filename_len + 2); i++) gcov_write_unsigned (aligned_fname[i]); - /* Now write the string array. */ - gcov_write_string_array (module_info->string_array, num_strings); + gcov_write_unsigned (module_info->cc1_strlen); + gcov_write_unsigned (module_info->cc1_uncompressed_strlen); + /* Now write the saved cc1 strings. */ + aligned_string = (gcov_unsigned_t *) alloca ((saved_cc1_strings_len + 1) * + sizeof (gcov_unsigned_t)); + memset (aligned_string, 0, (saved_cc1_strings_len + 1) * sizeof (gcov_unsigned_t)); + aligned_string[0] = saved_cc1_strings_len; + memcpy (aligned_string + 1, module_info->saved_cc1_strings, + module_info->cc1_strlen); + for (i = 0; i < saved_cc1_strings_len + 1; i++) + gcov_write_unsigned (aligned_string[i]); } #endif /* L_gcov */