diff mbox

[google,gcc-4_9] encode and compress cc1 option strings in gcov_module_info

Message ID CAF1bQ=QbkF0cjarT1YO_geh+tv=U9T0nHZGXEOZ=wjEwWjCBQA@mail.gmail.com
State New
Headers show

Commit Message

Rong Xu Oct. 5, 2015, 10:51 p.m. UTC
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  <xur@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.

Comments

Xinliang David Li Oct. 6, 2015, 12:33 a.m. UTC | #1
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++)


Do not use hard coded number. Use the enum defined in coverage.c.


+        string_array[j] = xstrdup (gcov_read_string ());
+
+      k = 0;
+      for (unsigned j = 1; j < 7; j++)

Do not use hard coded number.


+        {
+          if (num_array[j] == 0)
+            continue;
+          marker += num_array[j];

It is better to read if the name of variable 'marker' is changed to
'j_end' or something similar

For all the substrings of 'j' kind, there should be just one marker,
right? It looks like here you introduce one marker per string, not one
marker per string kind.

+          len += 3; /* [[<FLAG>  */

Same here for hard coded value.

+          for (; k < marker; k++)
+            len += strlen (string_array[k]) + 1; /* 1 for delimter of ']'  */

Why do we need one ']' per string?


+        }
+      saved_cc1_strings = (char *) xmalloc (len + 1);
+      saved_cc1_strings[0] = 0;
+
+      marker = 0;
+      k = 0;
+      for (unsigned j = 1; j < 7; j++)

Same here for 7.

+        {
+          static const char lipo_string_flags[6] = {'Q', 'B', 'S',
'D','I', 'C'};
+          if (num_array[j] == 0)
+            continue;
+          marker += num_array[j];

Suggest changing marker to j_end

+          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]);

+#define DELIMTER            "[["

Why double '[' ?

+#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);
+

Declare above in a header file.


 /* 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)

Fix formating.

 {
     {
@@ -1647,7 +1679,7 @@ build_var (tree fn_decl, tree type, int counter)
 /* Creates the gcov_fn_info RECORD_TYPE.  */

                       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;


Why do we need to store uncompressed string length? If there is need
to do that, I suggest combine uncompressed length and compressed
length into one 32bit integer. (16/16, or 17/15 split)


 David

On Mon, Oct 5, 2015 at 3:51 PM, Rong Xu <xur@google.com> wrote:
> 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
Rong Xu Oct. 6, 2015, 4:26 p.m. UTC | #2
On Mon, Oct 5, 2015 at 5:33 PM, Xinliang David Li <davidxl@google.com> wrote:
>        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++)
>
>
> Do not use hard coded number. Use the enum defined in coverage.c.

OK.

>
>
> +        string_array[j] = xstrdup (gcov_read_string ());
> +
> +      k = 0;
> +      for (unsigned j = 1; j < 7; j++)
>
> Do not use hard coded number.

OK.

>
>
> +        {
> +          if (num_array[j] == 0)
> +            continue;
> +          marker += num_array[j];
>
> It is better to read if the name of variable 'marker' is changed to
> 'j_end' or something similar
>
> For all the substrings of 'j' kind, there should be just one marker,
> right? It looks like here you introduce one marker per string, not one
> marker per string kind.

I don't understand what you meant here. "marker" is fixed for each j
substring (one option kind) -- it the end index of the sub-string
array. k-loop is for each string.

>
> +          len += 3; /* [[<FLAG>  */
>
> Same here for hard coded value.
>
> +          for (; k < marker; k++)
> +            len += strlen (string_array[k]) + 1; /* 1 for delimter of ']'  */
>
> Why do we need one ']' per string?

This is because the options strings can contain space '  '. I cannot
use space as the delimiter, neither is \0 as it is the end of the
string of the encoded string.

>
>
> +        }
> +      saved_cc1_strings = (char *) xmalloc (len + 1);
> +      saved_cc1_strings[0] = 0;
> +
> +      marker = 0;
> +      k = 0;
> +      for (unsigned j = 1; j < 7; j++)
>
> Same here for 7.

will fix in the new patch.

>
> +        {
> +          static const char lipo_string_flags[6] = {'Q', 'B', 'S',
> 'D','I', 'C'};
> +          if (num_array[j] == 0)
> +            continue;
> +          marker += num_array[j];
>
> Suggest changing marker to j_end
OK.

>
> +          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]);
>
> +#define DELIMTER            "[["
>
> Why double '[' ?
I will change to single '['.

>
> +#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);
> +
>
> Declare above in a header file.

OK.

>
>
>  /* 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)
>
> Fix formating.
OK.
>
>  {
>      {
> @@ -1647,7 +1679,7 @@ build_var (tree fn_decl, tree type, int counter)
>  /* Creates the gcov_fn_info RECORD_TYPE.  */
>
>                        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;
>
>
> Why do we need to store uncompressed string length? If there is need
> to do that, I suggest combine uncompressed length and compressed
> length into one 32bit integer. (16/16, or 17/15 split)

In theory, I don't need the uncompressed length, But I would need to
guess the uncompressed length to allocate the buffer. If the
decompressing fails with insufficient space, I need to have another
guess and do it again.  I think it's easier just save the uncompressed
size to the struct. I think combine the two sizes into one
gcov_unsigned_t is a good idea. We don't expect the string size are
very big.
>
>
>  David
>
> On Mon, Oct 5, 2015 at 3:51 PM, Rong Xu <xur@google.com> wrote:
>> 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
Xinliang David Li Oct. 6, 2015, 5:21 p.m. UTC | #3
On Tue, Oct 6, 2015 at 9:26 AM, Rong Xu <xur@google.com> wrote:
> On Mon, Oct 5, 2015 at 5:33 PM, Xinliang David Li <davidxl@google.com> wrote:
>>        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++)
>>
>>
>> Do not use hard coded number. Use the enum defined in coverage.c.
>
> OK.
>
>>
>>
>> +        string_array[j] = xstrdup (gcov_read_string ());
>> +
>> +      k = 0;
>> +      for (unsigned j = 1; j < 7; j++)
>>
>> Do not use hard coded number.
>
> OK.
>
>>
>>
>> +        {
>> +          if (num_array[j] == 0)
>> +            continue;
>> +          marker += num_array[j];
>>
>> It is better to read if the name of variable 'marker' is changed to
>> 'j_end' or something similar
>>
>> For all the substrings of 'j' kind, there should be just one marker,
>> right? It looks like here you introduce one marker per string, not one
>> marker per string kind.
>
> I don't understand what you meant here. "marker" is fixed for each j
> substring (one option kind) -- it the end index of the sub-string
> array. k-loop is for each string.
>

That was a wrong comment from me. Discard it.

>>
>> +          len += 3; /* [[<FLAG>  */
>>
>> Same here for hard coded value.
>>
>> +          for (; k < marker; k++)
>> +            len += strlen (string_array[k]) + 1; /* 1 for delimter of ']'  */
>>
>> Why do we need one ']' per string?
>
> This is because the options strings can contain space '  '. I cannot
> use space as the delimiter, neither is \0 as it is the end of the
> string of the encoded string.

Ok -- this allows you to avoid string copy during parsing.
>
>>
>>
>> +        }
>> +      saved_cc1_strings = (char *) xmalloc (len + 1);
>> +      saved_cc1_strings[0] = 0;
>> +
>> +      marker = 0;
>> +      k = 0;
>> +      for (unsigned j = 1; j < 7; j++)
>>
>> Same here for 7.
>
> will fix in the new patch.
>
>>
>> +        {
>> +          static const char lipo_string_flags[6] = {'Q', 'B', 'S',
>> 'D','I', 'C'};
>> +          if (num_array[j] == 0)
>> +            continue;
>> +          marker += num_array[j];
>>
>> Suggest changing marker to j_end
> OK.
>
>>
>> +          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]);
>>
>> +#define DELIMTER            "[["
>>
>> Why double '[' ?
> I will change to single '['.
>
>>
>> +#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);
>> +
>>
>> Declare above in a header file.
>
> OK.
>
>>
>>
>>  /* 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)
>>
>> Fix formating.
> OK.
>>
>>  {
>>      {
>> @@ -1647,7 +1679,7 @@ build_var (tree fn_decl, tree type, int counter)
>>  /* Creates the gcov_fn_info RECORD_TYPE.  */
>>
>>                        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;
>>
>>
>> Why do we need to store uncompressed string length? If there is need
>> to do that, I suggest combine uncompressed length and compressed
>> length into one 32bit integer. (16/16, or 17/15 split)
>
> In theory, I don't need the uncompressed length, But I would need to
> guess the uncompressed length to allocate the buffer. If the
> decompressing fails with insufficient space, I need to have another
> guess and do it again.  I think it's easier just save the uncompressed
> size to the struct. I think combine the two sizes into one
> gcov_unsigned_t is a good idea. We don't expect the string size are
> very big.

What is the usual compression ratio? If you guess it right most of the
time, just get rid of the uncompressed length.

David

>>
>>
>>  David
>>
>> On Mon, Oct 5, 2015 at 3:51 PM, Rong Xu <xur@google.com> wrote:
>>> 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
Rong Xu Oct. 6, 2015, 6:30 p.m. UTC | #4
It's 1:3 to 1:4 in the programs I tested. But it really depends on how
the options are used. I think your idea of using combined strlen works
better.
I just make the code a little clumsy but it does not cause any
performance issue.

On Tue, Oct 6, 2015 at 10:21 AM, Xinliang David Li <davidxl@google.com> wrote:
> On Tue, Oct 6, 2015 at 9:26 AM, Rong Xu <xur@google.com> wrote:
>> On Mon, Oct 5, 2015 at 5:33 PM, Xinliang David Li <davidxl@google.com> wrote:
>>>        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++)
>>>
>>>
>>> Do not use hard coded number. Use the enum defined in coverage.c.
>>
>> OK.
>>
>>>
>>>
>>> +        string_array[j] = xstrdup (gcov_read_string ());
>>> +
>>> +      k = 0;
>>> +      for (unsigned j = 1; j < 7; j++)
>>>
>>> Do not use hard coded number.
>>
>> OK.
>>
>>>
>>>
>>> +        {
>>> +          if (num_array[j] == 0)
>>> +            continue;
>>> +          marker += num_array[j];
>>>
>>> It is better to read if the name of variable 'marker' is changed to
>>> 'j_end' or something similar
>>>
>>> For all the substrings of 'j' kind, there should be just one marker,
>>> right? It looks like here you introduce one marker per string, not one
>>> marker per string kind.
>>
>> I don't understand what you meant here. "marker" is fixed for each j
>> substring (one option kind) -- it the end index of the sub-string
>> array. k-loop is for each string.
>>
>
> That was a wrong comment from me. Discard it.
>
>>>
>>> +          len += 3; /* [[<FLAG>  */
>>>
>>> Same here for hard coded value.
>>>
>>> +          for (; k < marker; k++)
>>> +            len += strlen (string_array[k]) + 1; /* 1 for delimter of ']'  */
>>>
>>> Why do we need one ']' per string?
>>
>> This is because the options strings can contain space '  '. I cannot
>> use space as the delimiter, neither is \0 as it is the end of the
>> string of the encoded string.
>
> Ok -- this allows you to avoid string copy during parsing.
>>
>>>
>>>
>>> +        }
>>> +      saved_cc1_strings = (char *) xmalloc (len + 1);
>>> +      saved_cc1_strings[0] = 0;
>>> +
>>> +      marker = 0;
>>> +      k = 0;
>>> +      for (unsigned j = 1; j < 7; j++)
>>>
>>> Same here for 7.
>>
>> will fix in the new patch.
>>
>>>
>>> +        {
>>> +          static const char lipo_string_flags[6] = {'Q', 'B', 'S',
>>> 'D','I', 'C'};
>>> +          if (num_array[j] == 0)
>>> +            continue;
>>> +          marker += num_array[j];
>>>
>>> Suggest changing marker to j_end
>> OK.
>>
>>>
>>> +          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]);
>>>
>>> +#define DELIMTER            "[["
>>>
>>> Why double '[' ?
>> I will change to single '['.
>>
>>>
>>> +#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);
>>> +
>>>
>>> Declare above in a header file.
>>
>> OK.
>>
>>>
>>>
>>>  /* 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)
>>>
>>> Fix formating.
>> OK.
>>>
>>>  {
>>>      {
>>> @@ -1647,7 +1679,7 @@ build_var (tree fn_decl, tree type, int counter)
>>>  /* Creates the gcov_fn_info RECORD_TYPE.  */
>>>
>>>                        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;
>>>
>>>
>>> Why do we need to store uncompressed string length? If there is need
>>> to do that, I suggest combine uncompressed length and compressed
>>> length into one 32bit integer. (16/16, or 17/15 split)
>>
>> In theory, I don't need the uncompressed length, But I would need to
>> guess the uncompressed length to allocate the buffer. If the
>> decompressing fails with insufficient space, I need to have another
>> guess and do it again.  I think it's easier just save the uncompressed
>> size to the struct. I think combine the two sizes into one
>> gcov_unsigned_t is a good idea. We don't expect the string size are
>> very big.
>
> What is the usual compression ratio? If you guess it right most of the
> time, just get rid of the uncompressed length.
>
> David
>
>>>
>>>
>>>  David
>>>
>>> On Mon, Oct 5, 2015 at 3:51 PM, Rong Xu <xur@google.com> wrote:
>>>> 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
diff mbox

Patch

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 (&quote_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 */