diff mbox

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

Message ID CAF1bQ=TR0rizY9g+o4aJr9ECsiA9QvEfs-r=T+iQiF4WKnDJ4w@mail.gmail.com
State New
Headers show

Commit Message

Rong Xu Oct. 6, 2015, 6:40 p.m. UTC
Here is the patch set 2 that integrates David's comments. Note that
this uses the combined strlen (i.e. encoding compressed and
uncompressed strlen into one gcov_unsigned_t).

Testing is ongoing.

-Rong

On Tue, Oct 6, 2015 at 11:30 AM, Rong Xu <xur@google.com> wrote:
> 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
2015-10-06  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.
        (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.
        (enum lipo_cc1_string_kind): new define.
        (struct lipo_parsed_cc1_string): new define.
        * 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, 11:37 p.m. UTC | #1
ok with the following changes (and after testing).

+                                       * 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 < (unsigned)num_lipo_cc1_string_kind; j++)

missing space.

+        {
+          if (num_array[j] == 0)
+            continue;
+          j_end += num_array[j];
+          len += strlen (DELIMITER) + 1; /* [<FLAG>  */
+          for (; k < j_end; k++)
+            len += strlen (string_array[k]) + 1; /* 1 for delimiter of ']'  */
+        }
+      saved_cc1_strings = (char *) xmalloc (len + 1);
+      saved_cc1_strings[0] = 0;
+
+      j_end = 0;
+      k = 0;
+      for (unsigned j = 1; j < (unsigned)num_lipo_cc1_string_kind; j++)

missing space.

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

use XCNEW instead to allocate and initialize.

+  ret->source_filename = src;
+
+  substr_begin = find_substr (str);
+  if (substr_begin == str + strlen(str))

  if (*substr_begin == '\0') is faster.

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

 2 --> strlen(DELIMITER) + 1

+/* The following defines are for the saved_cc1_strings encoding.  */
+
+#define DELIMITER           "["
+#define DELIMITER2          "]"

Suggest changing DELIMITER to LIPO_STR_DELIM

On Tue, Oct 6, 2015 at 11:40 AM, Rong Xu <xur@google.com> wrote:
> Here is the patch set 2 that integrates David's comments. Note that
> this uses the combined strlen (i.e. encoding compressed and
> uncompressed strlen into one gcov_unsigned_t).
>
> Testing is ongoing.
>
> -Rong
>
> On Tue, Oct 6, 2015 at 11:30 AM, Rong Xu <xur@google.com> wrote:
>> 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
@@ -968,11 +967,14 @@  autofdo_module_profile::read ()
     {
       char *name = xstrdup (gcov_read_string ());
       unsigned total_num = 0;
-      unsigned num_array[7];
+      unsigned num_array[num_lipo_cc1_string_kind];
       unsigned exported = gcov_read_unsigned ();
       unsigned lang = gcov_read_unsigned ();
       unsigned ggc_memory = gcov_read_unsigned ();
-      for (unsigned j = 0; j < 7; j++)
+      unsigned j_end = 0, len = 0, k;
+      char **string_array, *saved_cc1_strings;
+
+      for (unsigned j = 0; j < (unsigned)num_lipo_cc1_string_kind; j++)
         {
           num_array[j] = gcov_read_unsigned ();
           total_num += num_array[j];
@@ -988,19 +990,55 @@  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 < (unsigned)num_lipo_cc1_string_kind; j++)
+        {
+          if (num_array[j] == 0)
+            continue;
+          j_end += num_array[j];
+          len += strlen (DELIMITER) + 1; /* [<FLAG>  */
+          for (; k < j_end; k++)
+            len += strlen (string_array[k]) + 1; /* 1 for delimiter of ']'  */
+        }
+      saved_cc1_strings = (char *) xmalloc (len + 1);
+      saved_cc1_strings[0] = 0;
+
+      j_end = 0;
+      k = 0;
+      for (unsigned j = 1; j < (unsigned)num_lipo_cc1_string_kind; j++)
+        {
+          static const char lipo_string_flags[] = {
+            QUOTE_PATH_FLAG,
+            BRACKET_PATH_FLAG,
+            SYSTEM_PATH_FLAG,
+            D_U_OPTION_FLAG,
+            INCLUDE_OPTION_FLAG,
+            COMMAND_ARG_FLAG };
+
+          if (num_array[j] == 0)
+            continue;
+          j_end += num_array[j];
+          sprintf (saved_cc1_strings, "%s%s%c", saved_cc1_strings,
+                   DELIMITER, lipo_string_flags[j - 1]);
+          for (; k < j_end; k++)
+            {
+              sprintf (saved_cc1_strings, "%s%s%s", saved_cc1_strings,
+                       string_array[k], DELIMITER2);
+              free (string_array[k]);
+            }
+        }
+      module->saved_cc1_strings = saved_cc1_strings;
     }
   return true;
 }
@@ -1071,6 +1109,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 +1149,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);
@@ -345,13 +346,18 @@  has_incompatible_cg_opts (bool *cg_opts1, bool *cg
 /* 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 +365,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 +387,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 +410,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 +708,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 +890,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 +898,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 +911,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 +919,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 +948,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 +1011,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 +1023,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 +1649,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 +1956,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 +2010,148 @@  build_gcov_module_info_type (void)
   DECL_CHAIN (field) = fields;
   fields = field;
 
-  /* Num quote paths  */
+  /* combined_strlen field */
   field = build_decl (BUILTINS_LOCATION, FIELD_DECL,
                       NULL_TREE, get_gcov_unsigned_t ());
   DECL_CHAIN (field) = fields;
   fields = field;
 
-  /* Num bracket 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 system paths  */
-  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 -D/-U options.  */
-  field = build_decl (BUILTINS_LOCATION, FIELD_DECL,
-                      NULL_TREE, get_gcov_unsigned_t ());
-  DECL_CHAIN (field) = fields;
-  fields = field;
+  return type;
+}
 
-  /* Num -imacro/-include options.  */
-  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.  */
 
-  /* Num command-line args.  */
-  field = build_decl (BUILTINS_LOCATION, FIELD_DECL,
-		      NULL_TREE, get_gcov_unsigned_t ());
-  DECL_CHAIN (field) = fields;
-  fields = field;
+void
+free_parsed_string (struct lipo_parsed_cc1_string *string)
+{
+  unsigned k;
 
-  get_include_chains (&quote_paths, &bracket_paths, &system_paths);
-  for (pdir = quote_paths; pdir; pdir = pdir->next)
-    {
-      if (pdir == bracket_paths)
+  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, DELIMITER);
+  char ch;
+  size_t index = strlen (DELIMITER);
+
+  if (substr == NULL || strlen(substr) < index + 1)
+    return str + strlen(str);;
+  ch = substr[index];
+  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[strlen (DELIMITER)]) {
+      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 + strlen (DELIMITER) + 1;
+        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, DELIMITER);
+  i = strlen (strings);
+  strings[i] = tag;
+  strings[i + 1] = 0;
 }
 
 /* Returns the value of the module info associated with the
@@ -2092,12 +2163,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 +2257,127 @@  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 += strlen (DELIMITER) + 1; /* 1 for tag flag.  */
+  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 += strlen (DELIMITER) + 1; /* 1 for tag flag.  */
+  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 += strlen (DELIMITER) + 1; /* 1 for tag flag.  */
+  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 += strlen (DELIMITER) + 1; /* 1 for tag flag.  */
+  head = cpp_defines_head;
+  while (head)
+    {
+      total_length += strlen (head->str) + 1;
+      head = head->next;
+    }
 
-  /* Num -imacro/-include options.  */
-  CONSTRUCTOR_APPEND_ELT (v, info_fields,
-                          build_int_cstu (get_gcov_unsigned_t (),
-                                          num_cpp_includes));
-  info_fields = DECL_CHAIN (info_fields);
+  /* -imacro/-include options  */
+  total_length += strlen (DELIMITER) + 1; /* 1 for tag flag.  */
+  head = cpp_includes_head;
+  while (head)
+    {
+      total_length += strlen (head->str) + 1;
+      head = head->next;
+    }
 
-  /* Num command-line args.  */
+  /* Num command-line args  */
+  total_length += strlen (DELIMITER) + 1; /* 1 for tag flag.  */
+  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, DELIMITER2);
+      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, DELIMITER2);
+      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, DELIMITER2);
+      pdir = pdir->next;
+    }
+
+  lipo_append_tag (strings, D_U_OPTION_FLAG);
+  head = cpp_defines_head;
+  while (head)
+    {
+      strcat(strings, head->str);
+      strcat(strings, DELIMITER2);
+      head = head->next;
+    }
+
+  lipo_append_tag (strings, INCLUDE_OPTION_FLAG);
+  head = cpp_includes_head;
+  while (head)
+    {
+      strcat(strings, head->str);
+      strcat(strings, DELIMITER2);
+      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, DELIMITER2);
+    }
+  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);
+
+  gcc_assert (dest_len < 0xFFFF);
+  gcc_assert (src_len < 0xFFFF);
+  /* combined_strlen field */
   CONSTRUCTOR_APPEND_ELT (v, info_fields,
                           build_int_cstu (get_gcov_unsigned_t (),
-                                          num_lipo_cl_args));
+                          (src_len << 16 | dest_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 +2669,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 +2849,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 +2892,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 +2913,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 +2936,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 +2961,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,28 @@  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  = saved_compressed_len >> 16;
+  saved_compressed_len &= 0xFFFF;
+  tag_len = gcov_read_unsigned ();
+  len -= (tag_len + 2);
   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)
@@ -402,6 +402,35 @@  struct gcov_summary
 #define GCOV_MODULE_ASM_STMTS (1 << 16)
 #define GCOV_MODULE_LANG_MASK 0xffff
 
+/* The following defines are for the saved_cc1_strings encoding.  */
+
+#define DELIMITER           "["
+#define DELIMITER2          "]"
+#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'
+
+/* Define various kind of option for saved_cc1_strings.  */
+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
+};
+
+/* The struct for parsed (decoding) string for saved_cc1_strings.  */
+struct lipo_parsed_cc1_string {
+  const char* source_filename;
+  unsigned num[num_lipo_cc1_string_kind];
+  char **strings[num_lipo_cc1_string_kind];
+};
+
 /* Source module info. The data structure is used in
    both runtime and profile-use phase. Make sure to allocate
    enough space for the variable length member.  */
@@ -421,13 +450,18 @@  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.
+     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".
+     COMBINED_STRLEN contains the compressed size and the original
+     (uncompressed) string length. Bit[0..15] is the compressed size and
+     bit [16,31] is the uncompressed string length.  */
+  gcov_unsigned_t combined_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)
@@ -1494,8 +1494,8 @@  gcov_write_module_info (const struct gcov_info *mo
                         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;
+  gcov_unsigned_t num_strings, cc1_strlen;
+  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,12 @@  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);
+  cc1_strlen = module_info->combined_strlen & 0xFFFF;
+  saved_cc1_strings_len = (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 += 6; /* 6 more fields */
 
   gcov_write_tag_length (GCOV_TAG_MODULE_INFO, len);
   gcov_write_unsigned (module_info->ident);
@@ -1519,12 +1517,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 +1531,15 @@  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->combined_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, cc1_strlen);
+  for (i = 0; i < saved_cc1_strings_len + 1; i++)
+    gcov_write_unsigned (aligned_string[i]);
 }
 
 #endif /* L_gcov */