diff mbox series

lto-wrapper: Use vec<cl_decoded_option> data type.

Message ID 3ac2694a-9388-220d-aa35-72567f01c1d8@suse.cz
State New
Headers show
Series lto-wrapper: Use vec<cl_decoded_option> data type. | expand

Commit Message

Martin Liška April 21, 2021, 8:12 a.m. UTC
Now living in the 21st century, we don't longer need using the following tuple:
cl_decoded_option **decoded_options,
 unsigned int *decoded_options_count)
but we can rather use a standard (our) vector.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

gcc/ChangeLog:

	* lto-wrapper.c (get_options_from_collect_gcc_options): Change
	return type.
	(append_option): Remove.
	(find_option): Rework to use the vector type.
	(remove_option): Remove.
	(merge_and_complain): Use vectors for cl_decoded_option data
	type arguments.
	(append_compiler_options): Likewise.
	(append_diag_options): Likewise.
	(append_linker_options): Likewise.
	(append_offload_options): Likewise.
	(compile_offload_image): Likewise.
	(compile_images_for_offload_targets): Likewise.
	(find_and_merge_options): Likewise.
	(run_gcc): Likewise.
---
 gcc/lto-wrapper.c | 384 ++++++++++++++++++++--------------------------
 1 file changed, 165 insertions(+), 219 deletions(-)

Comments

Richard Biener April 29, 2021, 12:22 p.m. UTC | #1
On Wed, Apr 21, 2021 at 11:12 AM Martin Liška <mliska@suse.cz> wrote:
>
> Now living in the 21st century, we don't longer need using the following tuple:
> cl_decoded_option **decoded_options,
>  unsigned int *decoded_options_count)
> but we can rather use a standard (our) vector.
>
> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>
> Ready to be installed?
> Thanks,
> Martin
>
> gcc/ChangeLog:
>
>         * lto-wrapper.c (get_options_from_collect_gcc_options): Change
>         return type.
>         (append_option): Remove.
>         (find_option): Rework to use the vector type.
>         (remove_option): Remove.
>         (merge_and_complain): Use vectors for cl_decoded_option data
>         type arguments.
>         (append_compiler_options): Likewise.
>         (append_diag_options): Likewise.
>         (append_linker_options): Likewise.
>         (append_offload_options): Likewise.
>         (compile_offload_image): Likewise.
>         (compile_images_for_offload_targets): Likewise.
>         (find_and_merge_options): Likewise.
>         (run_gcc): Likewise.
> ---
>  gcc/lto-wrapper.c | 384 ++++++++++++++++++++--------------------------
>  1 file changed, 165 insertions(+), 219 deletions(-)
>
> diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
> index 03a5922f8ea..5ccf729b249 100644
> --- a/gcc/lto-wrapper.c
> +++ b/gcc/lto-wrapper.c
> @@ -138,12 +138,12 @@ maybe_unlink (const char *file)
>  /* Create decoded options from the COLLECT_GCC and COLLECT_GCC_OPTIONS
>     environment.  */
>
> -static void
> +static vec<cl_decoded_option>

bonus points for handling ownership transfer via returning an
auto_vec<> (not sure if possible, but maybe it is).

>  get_options_from_collect_gcc_options (const char *collect_gcc,
> -                                     const char *collect_gcc_options,
> -                                     struct cl_decoded_option **decoded_options,
> -                                     unsigned int *decoded_options_count)
> +                                     const char *collect_gcc_options)
>  {
> +  cl_decoded_option *decoded_options;
> +  unsigned int decoded_options_count;
>    struct obstack argv_obstack;
>    const char **argv;
>    int argc;
> @@ -156,57 +156,49 @@ get_options_from_collect_gcc_options (const char *collect_gcc,
>    argv = XOBFINISH (&argv_obstack, const char **);
>
>    decode_cmdline_options_to_array (argc, (const char **)argv, CL_DRIVER,
> -                                  decoded_options, decoded_options_count);
> +                                  &decoded_options, &decoded_options_count);
> +  vec<cl_decoded_option> decoded;
> +  decoded.create (decoded_options_count);
> +  for (unsigned i = 0; i < decoded_options_count; ++i)
> +    decoded.quick_push (decoded_options[i]);
> +  free (decoded_options);
> +
>    obstack_free (&argv_obstack, NULL);
> +
> +  return decoded;
>  }
>
> -/* Append OPTION to the options array DECODED_OPTIONS with size
> -   DECODED_OPTIONS_COUNT.  */
> +/* Find option in OPTIONS based on OPT_INDEX.  NULL value is returned
> +   if the option is not present.  */
>
> -static void
> -append_option (struct cl_decoded_option **decoded_options,
> -              unsigned int *decoded_options_count,
> -              struct cl_decoded_option *option)
> +static cl_decoded_option *
> +find_option (vec<cl_decoded_option> &options, size_t opt_index)
>  {
> -  ++*decoded_options_count;
> -  *decoded_options
> -    = (struct cl_decoded_option *)
> -       xrealloc (*decoded_options,
> -                 (*decoded_options_count
> -                  * sizeof (struct cl_decoded_option)));
> -  memcpy (&(*decoded_options)[*decoded_options_count - 1], option,
> -         sizeof (struct cl_decoded_option));
> -}
> +  for (unsigned i = 0; i < options.length (); ++i)
> +    if (options[i].opt_index == opt_index)
> +      return &options[i];

You're returning a pointer into the vector here...

> -/* Remove option number INDEX from DECODED_OPTIONS, update
> -   DECODED_OPTIONS_COUNT.  */
> +  return NULL;
> +}
>
> -static void
> -remove_option (struct cl_decoded_option **decoded_options,
> -              int index, unsigned int *decoded_options_count)
> +static cl_decoded_option *
> +find_option (vec<cl_decoded_option> &options, cl_decoded_option *option)
>  {
> -  --*decoded_options_count;
> -  memmove (&(*decoded_options)[index + 1],
> -          &(*decoded_options)[index],
> -          sizeof (struct cl_decoded_option)
> -          * (*decoded_options_count - index));
> +  return find_option (options, option->opt_index);
>  }
>
>  /* Try to merge and complain about options FDECODED_OPTIONS when applied
>     ontop of DECODED_OPTIONS.  */
>
>  static void
> -merge_and_complain (struct cl_decoded_option **decoded_options,
> -                   unsigned int *decoded_options_count,
> -                   struct cl_decoded_option *fdecoded_options,
> -                   unsigned int fdecoded_options_count,
> -                   struct cl_decoded_option *decoded_cl_options,
> -                   unsigned int decoded_cl_options_count)
> +merge_and_complain (vec<cl_decoded_option> decoded_options,
> +                   vec<cl_decoded_option> fdecoded_options,
> +                   vec<cl_decoded_option> decoded_cl_options)
>  {
>    unsigned int i, j;
> -  struct cl_decoded_option *pic_option = NULL;
> -  struct cl_decoded_option *pie_option = NULL;
> -  struct cl_decoded_option *cf_protection_option = NULL;
> +  cl_decoded_option *pic_option = NULL;
> +  cl_decoded_option *pie_option = NULL;
> +  cl_decoded_option *cf_protection_option = NULL;
>
>    /* ???  Merge options from files.  Most cases can be
>       handled by either unioning or intersecting
> @@ -223,9 +215,9 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>
>    /* Look for a -fcf-protection option in the link-time options
>       which overrides any -fcf-protection from the lto sections.  */
> -  for (i = 0; i < decoded_cl_options_count; ++i)
> +  for (i = 0; i < decoded_cl_options.length (); ++i)
>      {
> -      struct cl_decoded_option *foption = &decoded_cl_options[i];
> +      cl_decoded_option *foption = &decoded_cl_options[i];
>        if (foption->opt_index == OPT_fcf_protection_)
>         {
>           cf_protection_option = foption;
> @@ -234,9 +226,10 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>
>    /* The following does what the old LTO option code did,
>       union all target and a selected set of common options.  */
> -  for (i = 0; i < fdecoded_options_count; ++i)
> +  for (i = 0; i < fdecoded_options.length (); ++i)
>      {
> -      struct cl_decoded_option *foption = &fdecoded_options[i];
> +      cl_decoded_option *foption = &fdecoded_options[i];
> +      cl_decoded_option *existing_opt = find_option (decoded_options, foption);
>        switch (foption->opt_index)
>         {
>         case OPT_SPECIAL_unknown:
> @@ -264,11 +257,8 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>              setting per OPT code, we pick the first we encounter.
>              ???  This doesn't make too much sense, but when it doesn't
>              then we should complain.  */
> -         for (j = 0; j < *decoded_options_count; ++j)
> -           if ((*decoded_options)[j].opt_index == foption->opt_index)
> -             break;
> -         if (j == *decoded_options_count)
> -           append_option (decoded_options, decoded_options_count, foption);
> +         if (existing_opt == NULL)
> +           decoded_options.safe_push (*foption);

and you end up re-allocating that here.  That's an eventually dangerous
pattern ... please consider to instead returning an index from find()
(and -1 for not found or so).

>           break;
>
>         /* Figure out what PIC/PIE level wins and merge the results.  */
> @@ -284,25 +274,19 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>         case OPT_fopenmp:
>         case OPT_fopenacc:
>           /* For selected options we can merge conservatively.  */
> -         for (j = 0; j < *decoded_options_count; ++j)
> -           if ((*decoded_options)[j].opt_index == foption->opt_index)
> -             break;
> -         if (j == *decoded_options_count)
> -           append_option (decoded_options, decoded_options_count, foption);
> +         if (existing_opt == NULL)
> +           decoded_options.safe_push (*foption);
>           /* -fopenmp > -fno-openmp,
>              -fopenacc > -fno-openacc  */
> -         else if (foption->value > (*decoded_options)[j].value)
> -           (*decoded_options)[j] = *foption;
> +         else if (foption->value > existing_opt->value)
> +           *existing_opt = *foption;
>           break;
>
>         case OPT_fopenacc_dim_:
>           /* Append or check identical.  */
> -         for (j = 0; j < *decoded_options_count; ++j)
> -           if ((*decoded_options)[j].opt_index == foption->opt_index)
> -             break;
> -         if (j == *decoded_options_count)
> -           append_option (decoded_options, decoded_options_count, foption);
> -         else if (strcmp ((*decoded_options)[j].arg, foption->arg))
> +         if (existing_opt == NULL)
> +           decoded_options.safe_push (*foption);
> +         else if (strcmp (existing_opt->arg, foption->arg))
>             fatal_error (input_location,
>                          "option %s with different values",
>                          foption->orig_option_with_args_text);
> @@ -313,12 +297,9 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>           if (!cf_protection_option
>               || cf_protection_option->value == CF_CHECK)
>             {
> -             for (j = 0; j < *decoded_options_count; ++j)
> -               if ((*decoded_options)[j].opt_index == foption->opt_index)
> -                 break;
> -             if (j == *decoded_options_count)
> -               append_option (decoded_options, decoded_options_count, foption);
> -             else if ((*decoded_options)[j].value != foption->value)
> +             if (existing_opt == NULL)
> +               decoded_options.safe_push (*foption);
> +             else if (existing_opt->value != foption->value)
>                 {
>                   if (cf_protection_option
>                       && cf_protection_option->value == CF_CHECK)
> @@ -326,22 +307,21 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>                                  "option %qs with mismatching values"
>                                  " (%s, %s)",
>                                  "-fcf-protection",
> -                                (*decoded_options)[j].arg, foption->arg);
> +                                existing_opt->arg, foption->arg);
>                   else
>                     {
>                       /* Merge and update the -fcf-protection option.  */
> -                     (*decoded_options)[j].value &= (foption->value
> -                                                     & CF_FULL);
> -                     switch ((*decoded_options)[j].value)
> +                     existing_opt->value &= (foption->value & CF_FULL);
> +                     switch (existing_opt->value)
>                         {
>                         case CF_NONE:
> -                         (*decoded_options)[j].arg = "none";
> +                         existing_opt->arg = "none";
>                           break;
>                         case CF_BRANCH:
> -                         (*decoded_options)[j].arg = "branch";
> +                         existing_opt->arg = "branch";
>                           break;
>                         case CF_RETURN:
> -                         (*decoded_options)[j].arg = "return";
> +                         existing_opt->arg = "return";
>                           break;
>                         default:
>                           gcc_unreachable ();
> @@ -355,15 +335,19 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>         case OPT_Ofast:
>         case OPT_Og:
>         case OPT_Os:
> -         for (j = 0; j < *decoded_options_count; ++j)
> -           if ((*decoded_options)[j].opt_index == OPT_O
> -               || (*decoded_options)[j].opt_index == OPT_Ofast
> -               || (*decoded_options)[j].opt_index == OPT_Og
> -               || (*decoded_options)[j].opt_index == OPT_Os)
> -             break;
> -         if (j == *decoded_options_count)
> -           append_option (decoded_options, decoded_options_count, foption);
> -         else if ((*decoded_options)[j].opt_index == foption->opt_index
> +         existing_opt = NULL;
> +         for (j = 0; j < decoded_options.length (); ++j)
> +           if (decoded_options[j].opt_index == OPT_O
> +               || decoded_options[j].opt_index == OPT_Ofast
> +               || decoded_options[j].opt_index == OPT_Og
> +               || decoded_options[j].opt_index == OPT_Os)
> +             {
> +               existing_opt = &decoded_options[j];
> +               break;
> +             }
> +         if (existing_opt == NULL)
> +           decoded_options.safe_push (*foption);
> +         else if (existing_opt->opt_index == foption->opt_index
>                    && foption->opt_index != OPT_O)
>             /* Exact same options get merged.  */
>             ;
> @@ -393,13 +377,13 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>                 default:
>                   gcc_unreachable ();
>                 }
> -             switch ((*decoded_options)[j].opt_index)
> +             switch (existing_opt->opt_index)
>                 {
>                 case OPT_O:
> -                 if ((*decoded_options)[j].arg[0] == '\0')
> +                 if (existing_opt->arg[0] == '\0')
>                     level = MAX (level, 1);
>                   else
> -                   level = MAX (level, atoi ((*decoded_options)[j].arg));
> +                   level = MAX (level, atoi (existing_opt->arg));
>                   break;
>                 case OPT_Ofast:
>                   level = MAX (level, 3);
> @@ -413,23 +397,20 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>                 default:
>                   gcc_unreachable ();
>                 }
> -             (*decoded_options)[j].opt_index = OPT_O;
> +             existing_opt->opt_index = OPT_O;
>               char *tem;
>               tem = xasprintf ("-O%d", level);
> -             (*decoded_options)[j].arg = &tem[2];
> -             (*decoded_options)[j].canonical_option[0] = tem;
> -             (*decoded_options)[j].value = 1;
> +             existing_opt->arg = &tem[2];
> +             existing_opt->canonical_option[0] = tem;
> +             existing_opt->value = 1;
>             }
>           break;
>
>
>         case OPT_foffload_abi_:
> -         for (j = 0; j < *decoded_options_count; ++j)
> -           if ((*decoded_options)[j].opt_index == foption->opt_index)
> -             break;
> -         if (j == *decoded_options_count)
> -           append_option (decoded_options, decoded_options_count, foption);
> -         else if (foption->value != (*decoded_options)[j].value)
> +         if (existing_opt == NULL)
> +           decoded_options.safe_push (*foption);
> +         else if (foption->value != existing_opt->value)
>             fatal_error (input_location,
>                          "option %s not used consistently in all LTO input"
>                          " files", foption->orig_option_with_args_text);
> @@ -437,7 +418,7 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>
>
>         case OPT_foffload_:
> -         append_option (decoded_options, decoded_options_count, foption);
> +         decoded_options.safe_push (*foption);
>           break;
>         }
>      }
> @@ -457,12 +438,12 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>       It would be good to warn on mismatches, but it is bit hard to do as
>       we do not know what nothing translates to.  */
>
> -  for (unsigned int j = 0; j < *decoded_options_count;)
> -    if ((*decoded_options)[j].opt_index == OPT_fPIC
> -        || (*decoded_options)[j].opt_index == OPT_fpic)
> +  for (unsigned int j = 0; j < decoded_options.length ();)
> +    if (decoded_options[j].opt_index == OPT_fPIC
> +       || decoded_options[j].opt_index == OPT_fpic)
>        {
>         /* -fno-pic in one unit implies -fno-pic everywhere.  */
> -       if ((*decoded_options)[j].value == 0)
> +       if (decoded_options[j].value == 0)
>           j++;
>         /* If we have no pic option or merge in -fno-pic, we still may turn
>            existing pic/PIC mode into pie/PIE if -fpie/-fPIE is present.  */
> @@ -471,41 +452,41 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>           {
>             if (pie_option)
>               {
> -               bool big = (*decoded_options)[j].opt_index == OPT_fPIC
> +               bool big = decoded_options[j].opt_index == OPT_fPIC
>                            && pie_option->opt_index == OPT_fPIE;
> -               (*decoded_options)[j].opt_index = big ? OPT_fPIE : OPT_fpie;
> +               decoded_options[j].opt_index = big ? OPT_fPIE : OPT_fpie;
>                 if (pie_option->value)
> -                 (*decoded_options)[j].canonical_option[0]
> +                 decoded_options[j].canonical_option[0]
>                     = big ? "-fPIE" : "-fpie";
>                 else
> -                 (*decoded_options)[j].canonical_option[0] = "-fno-pie";
> -               (*decoded_options)[j].value = pie_option->value;
> -               j++;
> +                 decoded_options[j].canonical_option[0] = "-fno-pie";
> +               decoded_options[j].value = pie_option->value;
> +               j++;
>               }
>             else if (pic_option)
>               {
> -               (*decoded_options)[j] = *pic_option;
> -               j++;
> +               decoded_options[j] = *pic_option;
> +               j++;
>               }
>             /* We do not know if target defaults to pic or not, so just remove
>                option if it is missing in one unit but enabled in other.  */
>             else
> -             remove_option (decoded_options, j, decoded_options_count);
> +             decoded_options.ordered_remove (j);
>           }
>         else if (pic_option->opt_index == OPT_fpic
> -                && (*decoded_options)[j].opt_index == OPT_fPIC)
> +                && decoded_options[j].opt_index == OPT_fPIC)
>           {
> -           (*decoded_options)[j] = *pic_option;
> +           decoded_options[j] = *pic_option;
>             j++;
>           }
>         else
>           j++;
>        }
> -   else if ((*decoded_options)[j].opt_index == OPT_fPIE
> -            || (*decoded_options)[j].opt_index == OPT_fpie)
> +   else if (decoded_options[j].opt_index == OPT_fPIE
> +           || decoded_options[j].opt_index == OPT_fpie)
>        {
>         /* -fno-pie in one unit implies -fno-pie everywhere.  */
> -       if ((*decoded_options)[j].value == 0)
> +       if (decoded_options[j].value == 0)
>           j++;
>         /* If we have no pie option or merge in -fno-pie, we still preserve
>            PIE/pie if pic/PIC is present.  */
> @@ -516,32 +497,32 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>             if (pic_option)
>               {
>                 if (pic_option->opt_index == OPT_fpic
> -                   && (*decoded_options)[j].opt_index == OPT_fPIE)
> +                   && decoded_options[j].opt_index == OPT_fPIE)
>                   {
> -                   (*decoded_options)[j].opt_index = OPT_fpie;
> -                   (*decoded_options)[j].canonical_option[0]
> +                   decoded_options[j].opt_index = OPT_fpie;
> +                   decoded_options[j].canonical_option[0]
>                       = pic_option->value ? "-fpie" : "-fno-pie";
>                   }
>                 else if (!pic_option->value)
> -                 (*decoded_options)[j].canonical_option[0] = "-fno-pie";
> -               (*decoded_options)[j].value = pic_option->value;
> +                 decoded_options[j].canonical_option[0] = "-fno-pie";
> +               decoded_options[j].value = pic_option->value;
>                 j++;
>               }
>             else if (pie_option)
>               {
> -               (*decoded_options)[j] = *pie_option;
> +               decoded_options[j] = *pie_option;
>                 j++;
>               }
>             /* Because we always append pic/PIE options this code path should
>                not happen unless the LTO object was built by old lto1 which
>                did not contain that logic yet.  */
>             else
> -             remove_option (decoded_options, j, decoded_options_count);
> +             decoded_options.ordered_remove (j);
>           }
>         else if (pie_option->opt_index == OPT_fpie
> -                && (*decoded_options)[j].opt_index == OPT_fPIE)
> +                && decoded_options[j].opt_index == OPT_fPIE)
>           {
> -           (*decoded_options)[j] = *pie_option;
> +           decoded_options[j] = *pie_option;
>             j++;
>           }
>         else
> @@ -553,37 +534,34 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>    if (!xassembler_options_error)
>      for (i = j = 0; ; i++, j++)
>        {
> -       for (; i < *decoded_options_count; i++)
> -         if ((*decoded_options)[i].opt_index == OPT_Xassembler)
> -           break;
> -
> -       for (; j < fdecoded_options_count; j++)
> -         if (fdecoded_options[j].opt_index == OPT_Xassembler)
> -           break;
> +       cl_decoded_option *existing_opt
> +         = find_option (decoded_options, OPT_Xassembler);
> +       cl_decoded_option *existing_opt2
> +         = find_option (fdecoded_options, OPT_Xassembler);
>
> -       if (i == *decoded_options_count && j == fdecoded_options_count)
> +       if (existing_opt == NULL && existing_opt2 == NULL)
>           break;
> -       else if (i < *decoded_options_count && j == fdecoded_options_count)
> +       else if (existing_opt != NULL && existing_opt2 == NULL)
>           {
>             warning (0, "Extra option to %<-Xassembler%>: %s,"
>                      " dropping all %<-Xassembler%> and %<-Wa%> options.",
> -                    (*decoded_options)[i].arg);
> +                    existing_opt->arg);
>             xassembler_options_error = true;
>             break;
>           }
> -       else if (i == *decoded_options_count && j < fdecoded_options_count)
> +       else if (existing_opt == NULL && existing_opt2 != NULL)
>           {
>             warning (0, "Extra option to %<-Xassembler%>: %s,"
>                      " dropping all %<-Xassembler%> and %<-Wa%> options.",
> -                    fdecoded_options[j].arg);
> +                    existing_opt2->arg);
>             xassembler_options_error = true;
>             break;
>           }
> -       else if (strcmp ((*decoded_options)[i].arg, fdecoded_options[j].arg))
> +       else if (strcmp (existing_opt->arg, existing_opt2->arg) != 0)
>           {
>             warning (0, "Options to %<-Xassembler%> do not match: %s, %s,"
>                      " dropping all %<-Xassembler%> and %<-Wa%> options.",
> -                    (*decoded_options)[i].arg, fdecoded_options[j].arg);
> +                    existing_opt->arg, existing_opt2->arg);
>             xassembler_options_error = true;
>             break;
>           }
> @@ -654,13 +632,12 @@ parse_env_var (const char *str, char ***pvalues, const char *append)
>  /* Append options OPTS from lto or offload_lto sections to ARGV_OBSTACK.  */
>
>  static void
> -append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts,
> -                        unsigned int count)
> +append_compiler_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
>  {
>    /* Append compiler driver arguments as far as they were merged.  */
> -  for (unsigned int j = 1; j < count; ++j)
> +  for (unsigned int j = 1; j < opts.length (); ++j)
>      {
> -      struct cl_decoded_option *option = &opts[j];
> +      cl_decoded_option *option = &opts[j];
>
>        /* File options have been properly filtered by lto-opts.c.  */
>        switch (option->opt_index)
> @@ -721,16 +698,15 @@ append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts,
>      }
>  }
>
> -/* Append diag options in OPTS with length COUNT to ARGV_OBSTACK.  */
> +/* Append diag options in OPTS to ARGV_OBSTACK.  */
>
>  static void
> -append_diag_options (obstack *argv_obstack, struct cl_decoded_option *opts,
> -                    unsigned int count)
> +append_diag_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
>  {
>    /* Append compiler driver arguments as far as they were merged.  */
> -  for (unsigned int j = 1; j < count; ++j)
> +  for (unsigned int j = 1; j < opts.length (); ++j)
>      {
> -      struct cl_decoded_option *option = &opts[j];
> +      cl_decoded_option *option = &opts[j];
>
>        switch (option->opt_index)
>         {
> @@ -757,14 +733,13 @@ append_diag_options (obstack *argv_obstack, struct cl_decoded_option *opts,
>  /* Append linker options OPTS to ARGV_OBSTACK.  */
>
>  static void
> -append_linker_options (obstack *argv_obstack, struct cl_decoded_option *opts,
> -                      unsigned int count)
> +append_linker_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
>  {
>    /* Append linker driver arguments.  Compiler options from the linker
>       driver arguments will override / merge with those from the compiler.  */
> -  for (unsigned int j = 1; j < count; ++j)
> +  for (unsigned int j = 1; j < opts.length (); ++j)
>      {
> -      struct cl_decoded_option *option = &opts[j];
> +      cl_decoded_option *option = &opts[j];
>
>        /* Do not pass on frontend specific flags not suitable for lto.  */
>        if (!(cl_options[option->opt_index].flags
> @@ -802,15 +777,14 @@ append_linker_options (obstack *argv_obstack, struct cl_decoded_option *opts,
>
>  static void
>  append_offload_options (obstack *argv_obstack, const char *target,
> -                       struct cl_decoded_option *options,
> -                       unsigned int options_count)
> +                       vec<cl_decoded_option> options)
>  {
> -  for (unsigned i = 0; i < options_count; i++)
> +  for (unsigned i = 0; i < options.length (); i++)
>      {
>        const char *cur, *next, *opts;
>        char **argv;
>        unsigned argc;
> -      struct cl_decoded_option *option = &options[i];
> +      cl_decoded_option *option = &options[i];
>
>        if (option->opt_index != OPT_foffload_)
>         continue;
> @@ -882,10 +856,8 @@ access_check (const char *name, int mode)
>  static char *
>  compile_offload_image (const char *target, const char *compiler_path,
>                        unsigned in_argc, char *in_argv[],
> -                      struct cl_decoded_option *compiler_opts,
> -                      unsigned int compiler_opt_count,
> -                      struct cl_decoded_option *linker_opts,
> -                      unsigned int linker_opt_count)
> +                      vec<cl_decoded_option> compiler_opts,
> +                      vec<cl_decoded_option> linker_opts)
>  {
>    char *filename = NULL;
>    char *dumpbase;
> @@ -935,19 +907,16 @@ compile_offload_image (const char *target, const char *compiler_path,
>      obstack_ptr_grow (&argv_obstack, in_argv[i]);
>
>    /* Append options from offload_lto sections.  */
> -  append_compiler_options (&argv_obstack, compiler_opts,
> -                          compiler_opt_count);
> -  append_diag_options (&argv_obstack, linker_opts, linker_opt_count);
> +  append_compiler_options (&argv_obstack, compiler_opts);
> +  append_diag_options (&argv_obstack, linker_opts);
>
>    obstack_ptr_grow (&argv_obstack, "-dumpbase");
>    obstack_ptr_grow (&argv_obstack, dumpbase);
>
>    /* Append options specified by -foffload last.  In case of conflicting
>       options we expect offload compiler to choose the latest.  */
> -  append_offload_options (&argv_obstack, target, compiler_opts,
> -                         compiler_opt_count);
> -  append_offload_options (&argv_obstack, target, linker_opts,
> -                         linker_opt_count);
> +  append_offload_options (&argv_obstack, target, compiler_opts);
> +  append_offload_options (&argv_obstack, target, linker_opts);
>
>    obstack_ptr_grow (&argv_obstack, NULL);
>    argv = XOBFINISH (&argv_obstack, char **);
> @@ -966,10 +935,8 @@ compile_offload_image (const char *target, const char *compiler_path,
>
>  static void
>  compile_images_for_offload_targets (unsigned in_argc, char *in_argv[],
> -                                   struct cl_decoded_option *compiler_opts,
> -                                   unsigned int compiler_opt_count,
> -                                   struct cl_decoded_option *linker_opts,
> -                                   unsigned int linker_opt_count)
> +                                   vec<cl_decoded_option> compiler_opts,
> +                                   vec<cl_decoded_option> linker_opts)
>  {
>    char **names = NULL;
>    const char *target_names = getenv (OFFLOAD_TARGET_NAMES_ENV);
> @@ -988,8 +955,7 @@ compile_images_for_offload_targets (unsigned in_argc, char *in_argv[],
>      {
>        offload_names[i]
>         = compile_offload_image (names[i], compiler_path, in_argc, in_argv,
> -                                compiler_opts, compiler_opt_count,
> -                                linker_opts, linker_opt_count);
> +                                compiler_opts, linker_opts);
>        if (!offload_names[i])
>         fatal_error (input_location,
>                      "problem with building target image for %s", names[i]);
> @@ -1058,25 +1024,22 @@ find_crtoffloadtable (int save_temps, const char *dumppfx)
>  }
>
>  /* A subroutine of run_gcc.  Examine the open file FD for lto sections with
> -   name prefix PREFIX, at FILE_OFFSET, and store any options we find in OPTS
> -   and OPT_COUNT.  Return true if we found a matching section, false
> +   name prefix PREFIX, at FILE_OFFSET, and store any options we find in OPTS.
> +   Return true if we found a matching section, false
>     otherwise.  COLLECT_GCC holds the value of the environment variable with
>     the same name.  */
>
>  static bool
>  find_and_merge_options (int fd, off_t file_offset, const char *prefix,
> -                       struct cl_decoded_option *decoded_cl_options,
> -                       unsigned int decoded_cl_options_count,
> -                       struct cl_decoded_option **opts,
> -                       unsigned int *opt_count, const char *collect_gcc)
> +                       vec<cl_decoded_option> decoded_cl_options,
> +                       vec<cl_decoded_option> *opts, const char *collect_gcc)
>  {
>    off_t offset, length;
>    char *data;
>    char *fopts;
>    const char *errmsg;
>    int err;
> -  struct cl_decoded_option *fdecoded_options = *opts;
> -  unsigned int fdecoded_options_count = *opt_count;
> +  vec<cl_decoded_option> fdecoded_options;
>
>    simple_object_read *sobj;
>    sobj = simple_object_start_read (fd, file_offset, "__GNU_LTO",
> @@ -1098,24 +1061,19 @@ find_and_merge_options (int fd, off_t file_offset, const char *prefix,
>    data = (char *)xmalloc (length);
>    read (fd, data, length);
>    fopts = data;
> +  bool first = true;
>    do
>      {
> -      struct cl_decoded_option *f2decoded_options;
> -      unsigned int f2decoded_options_count;
> -      get_options_from_collect_gcc_options (collect_gcc, fopts,
> -                                           &f2decoded_options,
> -                                           &f2decoded_options_count);
> -      if (!fdecoded_options)
> -       {
> -        fdecoded_options = f2decoded_options;
> -        fdecoded_options_count = f2decoded_options_count;
> -       }
> +      vec<cl_decoded_option> f2decoded_options
> +       = get_options_from_collect_gcc_options (collect_gcc, fopts);
> +      if (first)
> +       {
> +         fdecoded_options = f2decoded_options;
> +         first = false;
> +       }
>        else
> -       merge_and_complain (&fdecoded_options,
> -                           &fdecoded_options_count,
> -                           f2decoded_options, f2decoded_options_count,
> -                           decoded_cl_options,
> -                           decoded_cl_options_count);
> +       merge_and_complain (fdecoded_options, f2decoded_options,
> +                           decoded_cl_options);
>
>        fopts += strlen (fopts) + 1;
>      }
> @@ -1124,7 +1082,6 @@ find_and_merge_options (int fd, off_t file_offset, const char *prefix,
>    free (data);
>    simple_object_release_read (sobj);
>    *opts = fdecoded_options;
> -  *opt_count = fdecoded_options_count;
>    return true;
>  }
>
> @@ -1371,12 +1328,9 @@ run_gcc (unsigned argc, char *argv[])
>    int jobserver = 0;
>    int auto_parallel = 0;
>    bool no_partition = false;
> -  struct cl_decoded_option *fdecoded_options = NULL;
> -  struct cl_decoded_option *offload_fdecoded_options = NULL;
> -  unsigned int fdecoded_options_count = 0;
> -  unsigned int offload_fdecoded_options_count = 0;
> -  struct cl_decoded_option *decoded_options;
> -  unsigned int decoded_options_count;
> +  vec<cl_decoded_option> fdecoded_options;
> +  fdecoded_options.create (16);
> +  vec<cl_decoded_option> offload_fdecoded_options = vNULL;
>    struct obstack argv_obstack;
>    int new_head_argc;
>    bool have_lto = false;
> @@ -1418,9 +1372,8 @@ run_gcc (unsigned argc, char *argv[])
>                                     NULL);
>      }
>
> -  get_options_from_collect_gcc_options (collect_gcc, collect_gcc_options,
> -                                       &decoded_options,
> -                                       &decoded_options_count);
> +  vec<cl_decoded_option> decoded_options
> +    = get_options_from_collect_gcc_options (collect_gcc, collect_gcc_options);
>
>    /* Allocate array for input object files with LTO IL,
>       and for possible preceding arguments.  */
> @@ -1470,8 +1423,7 @@ run_gcc (unsigned argc, char *argv[])
>         }
>
>        if (find_and_merge_options (fd, file_offset, LTO_SECTION_NAME_PREFIX,
> -                                 decoded_options, decoded_options_count,
> -                                 &fdecoded_options, &fdecoded_options_count,
> +                                 decoded_options, &fdecoded_options,
>                                   collect_gcc))
>         {
>           have_lto = true;
> @@ -1486,14 +1438,13 @@ run_gcc (unsigned argc, char *argv[])
>    obstack_ptr_grow (&argv_obstack, "-xlto");
>    obstack_ptr_grow (&argv_obstack, "-c");
>
> -  append_compiler_options (&argv_obstack, fdecoded_options,
> -                          fdecoded_options_count);
> -  append_linker_options (&argv_obstack, decoded_options, decoded_options_count);
> +  append_compiler_options (&argv_obstack, fdecoded_options);
> +  append_linker_options (&argv_obstack, decoded_options);
>
>    /* Scan linker driver arguments for things that are of relevance to us.  */
> -  for (j = 1; j < decoded_options_count; ++j)
> +  for (j = 1; j < decoded_options.length (); ++j)
>      {
> -      struct cl_decoded_option *option = &decoded_options[j];
> +      cl_decoded_option *option = &decoded_options[j];
>        switch (option->opt_index)
>         {
>         case OPT_o:
> @@ -1711,9 +1662,7 @@ cont1:
>             fatal_error (input_location, "cannot open %s: %m", filename);
>           if (!find_and_merge_options (fd, file_offset,
>                                        OFFLOAD_SECTION_NAME_PREFIX,
> -                                      decoded_options, decoded_options_count,
> -                                      &offload_fdecoded_options,
> -                                      &offload_fdecoded_options_count,
> +                                      decoded_options, &offload_fdecoded_options,
>                                        collect_gcc))
>             fatal_error (input_location, "cannot read %s: %m", filename);
>           close (fd);
> @@ -1722,10 +1671,7 @@ cont1:
>         }
>
>        compile_images_for_offload_targets (num_offload_files, offload_argv,
> -                                         offload_fdecoded_options,
> -                                         offload_fdecoded_options_count,
> -                                         decoded_options,
> -                                         decoded_options_count);
> +                                         offload_fdecoded_options, decoded_options);
>
>        free_array_of_ptrs ((void **) offload_argv, num_offload_files);
>
> --
> 2.31.1
>
Martin Sebor April 29, 2021, 3:19 p.m. UTC | #2
On 4/29/21 6:22 AM, Richard Biener via Gcc-patches wrote:
> On Wed, Apr 21, 2021 at 11:12 AM Martin Liška <mliska@suse.cz> wrote:
>>
>> Now living in the 21st century, we don't longer need using the following tuple:
>> cl_decoded_option **decoded_options,
>>   unsigned int *decoded_options_count)
>> but we can rather use a standard (our) vector.
>>
>> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>>
>> Ready to be installed?
>> Thanks,
>> Martin
>>
>> gcc/ChangeLog:
>>
>>          * lto-wrapper.c (get_options_from_collect_gcc_options): Change
>>          return type.
>>          (append_option): Remove.
>>          (find_option): Rework to use the vector type.
>>          (remove_option): Remove.
>>          (merge_and_complain): Use vectors for cl_decoded_option data
>>          type arguments.
>>          (append_compiler_options): Likewise.
>>          (append_diag_options): Likewise.
>>          (append_linker_options): Likewise.
>>          (append_offload_options): Likewise.
>>          (compile_offload_image): Likewise.
>>          (compile_images_for_offload_targets): Likewise.
>>          (find_and_merge_options): Likewise.
>>          (run_gcc): Likewise.
>> ---
>>   gcc/lto-wrapper.c | 384 ++++++++++++++++++++--------------------------
>>   1 file changed, 165 insertions(+), 219 deletions(-)
>>
>> diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
>> index 03a5922f8ea..5ccf729b249 100644
>> --- a/gcc/lto-wrapper.c
>> +++ b/gcc/lto-wrapper.c
>> @@ -138,12 +138,12 @@ maybe_unlink (const char *file)
>>   /* Create decoded options from the COLLECT_GCC and COLLECT_GCC_OPTIONS
>>      environment.  */
>>
>> -static void
>> +static vec<cl_decoded_option>
> 
> bonus points for handling ownership transfer via returning an
> auto_vec<> (not sure if possible, but maybe it is).

The auto_vec move ctor you added makes it possible.  It matches either
a plain vec argument or an auto_vec.

(The copy ctor patch I submitted earlier this week matches in contexts
where the argument cannot be moved.)

Martin


> 
>>   get_options_from_collect_gcc_options (const char *collect_gcc,
>> -                                     const char *collect_gcc_options,
>> -                                     struct cl_decoded_option **decoded_options,
>> -                                     unsigned int *decoded_options_count)
>> +                                     const char *collect_gcc_options)
>>   {
>> +  cl_decoded_option *decoded_options;
>> +  unsigned int decoded_options_count;
>>     struct obstack argv_obstack;
>>     const char **argv;
>>     int argc;
>> @@ -156,57 +156,49 @@ get_options_from_collect_gcc_options (const char *collect_gcc,
>>     argv = XOBFINISH (&argv_obstack, const char **);
>>
>>     decode_cmdline_options_to_array (argc, (const char **)argv, CL_DRIVER,
>> -                                  decoded_options, decoded_options_count);
>> +                                  &decoded_options, &decoded_options_count);
>> +  vec<cl_decoded_option> decoded;
>> +  decoded.create (decoded_options_count);
>> +  for (unsigned i = 0; i < decoded_options_count; ++i)
>> +    decoded.quick_push (decoded_options[i]);
>> +  free (decoded_options);
>> +
>>     obstack_free (&argv_obstack, NULL);
>> +
>> +  return decoded;
>>   }
>>
>> -/* Append OPTION to the options array DECODED_OPTIONS with size
>> -   DECODED_OPTIONS_COUNT.  */
>> +/* Find option in OPTIONS based on OPT_INDEX.  NULL value is returned
>> +   if the option is not present.  */
>>
>> -static void
>> -append_option (struct cl_decoded_option **decoded_options,
>> -              unsigned int *decoded_options_count,
>> -              struct cl_decoded_option *option)
>> +static cl_decoded_option *
>> +find_option (vec<cl_decoded_option> &options, size_t opt_index)
>>   {
>> -  ++*decoded_options_count;
>> -  *decoded_options
>> -    = (struct cl_decoded_option *)
>> -       xrealloc (*decoded_options,
>> -                 (*decoded_options_count
>> -                  * sizeof (struct cl_decoded_option)));
>> -  memcpy (&(*decoded_options)[*decoded_options_count - 1], option,
>> -         sizeof (struct cl_decoded_option));
>> -}
>> +  for (unsigned i = 0; i < options.length (); ++i)
>> +    if (options[i].opt_index == opt_index)
>> +      return &options[i];
> 
> You're returning a pointer into the vector here...
> 
>> -/* Remove option number INDEX from DECODED_OPTIONS, update
>> -   DECODED_OPTIONS_COUNT.  */
>> +  return NULL;
>> +}
>>
>> -static void
>> -remove_option (struct cl_decoded_option **decoded_options,
>> -              int index, unsigned int *decoded_options_count)
>> +static cl_decoded_option *
>> +find_option (vec<cl_decoded_option> &options, cl_decoded_option *option)
>>   {
>> -  --*decoded_options_count;
>> -  memmove (&(*decoded_options)[index + 1],
>> -          &(*decoded_options)[index],
>> -          sizeof (struct cl_decoded_option)
>> -          * (*decoded_options_count - index));
>> +  return find_option (options, option->opt_index);
>>   }
>>
>>   /* Try to merge and complain about options FDECODED_OPTIONS when applied
>>      ontop of DECODED_OPTIONS.  */
>>
>>   static void
>> -merge_and_complain (struct cl_decoded_option **decoded_options,
>> -                   unsigned int *decoded_options_count,
>> -                   struct cl_decoded_option *fdecoded_options,
>> -                   unsigned int fdecoded_options_count,
>> -                   struct cl_decoded_option *decoded_cl_options,
>> -                   unsigned int decoded_cl_options_count)
>> +merge_and_complain (vec<cl_decoded_option> decoded_options,
>> +                   vec<cl_decoded_option> fdecoded_options,
>> +                   vec<cl_decoded_option> decoded_cl_options)
>>   {
>>     unsigned int i, j;
>> -  struct cl_decoded_option *pic_option = NULL;
>> -  struct cl_decoded_option *pie_option = NULL;
>> -  struct cl_decoded_option *cf_protection_option = NULL;
>> +  cl_decoded_option *pic_option = NULL;
>> +  cl_decoded_option *pie_option = NULL;
>> +  cl_decoded_option *cf_protection_option = NULL;
>>
>>     /* ???  Merge options from files.  Most cases can be
>>        handled by either unioning or intersecting
>> @@ -223,9 +215,9 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>
>>     /* Look for a -fcf-protection option in the link-time options
>>        which overrides any -fcf-protection from the lto sections.  */
>> -  for (i = 0; i < decoded_cl_options_count; ++i)
>> +  for (i = 0; i < decoded_cl_options.length (); ++i)
>>       {
>> -      struct cl_decoded_option *foption = &decoded_cl_options[i];
>> +      cl_decoded_option *foption = &decoded_cl_options[i];
>>         if (foption->opt_index == OPT_fcf_protection_)
>>          {
>>            cf_protection_option = foption;
>> @@ -234,9 +226,10 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>
>>     /* The following does what the old LTO option code did,
>>        union all target and a selected set of common options.  */
>> -  for (i = 0; i < fdecoded_options_count; ++i)
>> +  for (i = 0; i < fdecoded_options.length (); ++i)
>>       {
>> -      struct cl_decoded_option *foption = &fdecoded_options[i];
>> +      cl_decoded_option *foption = &fdecoded_options[i];
>> +      cl_decoded_option *existing_opt = find_option (decoded_options, foption);
>>         switch (foption->opt_index)
>>          {
>>          case OPT_SPECIAL_unknown:
>> @@ -264,11 +257,8 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>               setting per OPT code, we pick the first we encounter.
>>               ???  This doesn't make too much sense, but when it doesn't
>>               then we should complain.  */
>> -         for (j = 0; j < *decoded_options_count; ++j)
>> -           if ((*decoded_options)[j].opt_index == foption->opt_index)
>> -             break;
>> -         if (j == *decoded_options_count)
>> -           append_option (decoded_options, decoded_options_count, foption);
>> +         if (existing_opt == NULL)
>> +           decoded_options.safe_push (*foption);
> 
> and you end up re-allocating that here.  That's an eventually dangerous
> pattern ... please consider to instead returning an index from find()
> (and -1 for not found or so).
> 
>>            break;
>>
>>          /* Figure out what PIC/PIE level wins and merge the results.  */
>> @@ -284,25 +274,19 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>          case OPT_fopenmp:
>>          case OPT_fopenacc:
>>            /* For selected options we can merge conservatively.  */
>> -         for (j = 0; j < *decoded_options_count; ++j)
>> -           if ((*decoded_options)[j].opt_index == foption->opt_index)
>> -             break;
>> -         if (j == *decoded_options_count)
>> -           append_option (decoded_options, decoded_options_count, foption);
>> +         if (existing_opt == NULL)
>> +           decoded_options.safe_push (*foption);
>>            /* -fopenmp > -fno-openmp,
>>               -fopenacc > -fno-openacc  */
>> -         else if (foption->value > (*decoded_options)[j].value)
>> -           (*decoded_options)[j] = *foption;
>> +         else if (foption->value > existing_opt->value)
>> +           *existing_opt = *foption;
>>            break;
>>
>>          case OPT_fopenacc_dim_:
>>            /* Append or check identical.  */
>> -         for (j = 0; j < *decoded_options_count; ++j)
>> -           if ((*decoded_options)[j].opt_index == foption->opt_index)
>> -             break;
>> -         if (j == *decoded_options_count)
>> -           append_option (decoded_options, decoded_options_count, foption);
>> -         else if (strcmp ((*decoded_options)[j].arg, foption->arg))
>> +         if (existing_opt == NULL)
>> +           decoded_options.safe_push (*foption);
>> +         else if (strcmp (existing_opt->arg, foption->arg))
>>              fatal_error (input_location,
>>                           "option %s with different values",
>>                           foption->orig_option_with_args_text);
>> @@ -313,12 +297,9 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>            if (!cf_protection_option
>>                || cf_protection_option->value == CF_CHECK)
>>              {
>> -             for (j = 0; j < *decoded_options_count; ++j)
>> -               if ((*decoded_options)[j].opt_index == foption->opt_index)
>> -                 break;
>> -             if (j == *decoded_options_count)
>> -               append_option (decoded_options, decoded_options_count, foption);
>> -             else if ((*decoded_options)[j].value != foption->value)
>> +             if (existing_opt == NULL)
>> +               decoded_options.safe_push (*foption);
>> +             else if (existing_opt->value != foption->value)
>>                  {
>>                    if (cf_protection_option
>>                        && cf_protection_option->value == CF_CHECK)
>> @@ -326,22 +307,21 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>                                   "option %qs with mismatching values"
>>                                   " (%s, %s)",
>>                                   "-fcf-protection",
>> -                                (*decoded_options)[j].arg, foption->arg);
>> +                                existing_opt->arg, foption->arg);
>>                    else
>>                      {
>>                        /* Merge and update the -fcf-protection option.  */
>> -                     (*decoded_options)[j].value &= (foption->value
>> -                                                     & CF_FULL);
>> -                     switch ((*decoded_options)[j].value)
>> +                     existing_opt->value &= (foption->value & CF_FULL);
>> +                     switch (existing_opt->value)
>>                          {
>>                          case CF_NONE:
>> -                         (*decoded_options)[j].arg = "none";
>> +                         existing_opt->arg = "none";
>>                            break;
>>                          case CF_BRANCH:
>> -                         (*decoded_options)[j].arg = "branch";
>> +                         existing_opt->arg = "branch";
>>                            break;
>>                          case CF_RETURN:
>> -                         (*decoded_options)[j].arg = "return";
>> +                         existing_opt->arg = "return";
>>                            break;
>>                          default:
>>                            gcc_unreachable ();
>> @@ -355,15 +335,19 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>          case OPT_Ofast:
>>          case OPT_Og:
>>          case OPT_Os:
>> -         for (j = 0; j < *decoded_options_count; ++j)
>> -           if ((*decoded_options)[j].opt_index == OPT_O
>> -               || (*decoded_options)[j].opt_index == OPT_Ofast
>> -               || (*decoded_options)[j].opt_index == OPT_Og
>> -               || (*decoded_options)[j].opt_index == OPT_Os)
>> -             break;
>> -         if (j == *decoded_options_count)
>> -           append_option (decoded_options, decoded_options_count, foption);
>> -         else if ((*decoded_options)[j].opt_index == foption->opt_index
>> +         existing_opt = NULL;
>> +         for (j = 0; j < decoded_options.length (); ++j)
>> +           if (decoded_options[j].opt_index == OPT_O
>> +               || decoded_options[j].opt_index == OPT_Ofast
>> +               || decoded_options[j].opt_index == OPT_Og
>> +               || decoded_options[j].opt_index == OPT_Os)
>> +             {
>> +               existing_opt = &decoded_options[j];
>> +               break;
>> +             }
>> +         if (existing_opt == NULL)
>> +           decoded_options.safe_push (*foption);
>> +         else if (existing_opt->opt_index == foption->opt_index
>>                     && foption->opt_index != OPT_O)
>>              /* Exact same options get merged.  */
>>              ;
>> @@ -393,13 +377,13 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>                  default:
>>                    gcc_unreachable ();
>>                  }
>> -             switch ((*decoded_options)[j].opt_index)
>> +             switch (existing_opt->opt_index)
>>                  {
>>                  case OPT_O:
>> -                 if ((*decoded_options)[j].arg[0] == '\0')
>> +                 if (existing_opt->arg[0] == '\0')
>>                      level = MAX (level, 1);
>>                    else
>> -                   level = MAX (level, atoi ((*decoded_options)[j].arg));
>> +                   level = MAX (level, atoi (existing_opt->arg));
>>                    break;
>>                  case OPT_Ofast:
>>                    level = MAX (level, 3);
>> @@ -413,23 +397,20 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>                  default:
>>                    gcc_unreachable ();
>>                  }
>> -             (*decoded_options)[j].opt_index = OPT_O;
>> +             existing_opt->opt_index = OPT_O;
>>                char *tem;
>>                tem = xasprintf ("-O%d", level);
>> -             (*decoded_options)[j].arg = &tem[2];
>> -             (*decoded_options)[j].canonical_option[0] = tem;
>> -             (*decoded_options)[j].value = 1;
>> +             existing_opt->arg = &tem[2];
>> +             existing_opt->canonical_option[0] = tem;
>> +             existing_opt->value = 1;
>>              }
>>            break;
>>
>>
>>          case OPT_foffload_abi_:
>> -         for (j = 0; j < *decoded_options_count; ++j)
>> -           if ((*decoded_options)[j].opt_index == foption->opt_index)
>> -             break;
>> -         if (j == *decoded_options_count)
>> -           append_option (decoded_options, decoded_options_count, foption);
>> -         else if (foption->value != (*decoded_options)[j].value)
>> +         if (existing_opt == NULL)
>> +           decoded_options.safe_push (*foption);
>> +         else if (foption->value != existing_opt->value)
>>              fatal_error (input_location,
>>                           "option %s not used consistently in all LTO input"
>>                           " files", foption->orig_option_with_args_text);
>> @@ -437,7 +418,7 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>
>>
>>          case OPT_foffload_:
>> -         append_option (decoded_options, decoded_options_count, foption);
>> +         decoded_options.safe_push (*foption);
>>            break;
>>          }
>>       }
>> @@ -457,12 +438,12 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>        It would be good to warn on mismatches, but it is bit hard to do as
>>        we do not know what nothing translates to.  */
>>
>> -  for (unsigned int j = 0; j < *decoded_options_count;)
>> -    if ((*decoded_options)[j].opt_index == OPT_fPIC
>> -        || (*decoded_options)[j].opt_index == OPT_fpic)
>> +  for (unsigned int j = 0; j < decoded_options.length ();)
>> +    if (decoded_options[j].opt_index == OPT_fPIC
>> +       || decoded_options[j].opt_index == OPT_fpic)
>>         {
>>          /* -fno-pic in one unit implies -fno-pic everywhere.  */
>> -       if ((*decoded_options)[j].value == 0)
>> +       if (decoded_options[j].value == 0)
>>            j++;
>>          /* If we have no pic option or merge in -fno-pic, we still may turn
>>             existing pic/PIC mode into pie/PIE if -fpie/-fPIE is present.  */
>> @@ -471,41 +452,41 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>            {
>>              if (pie_option)
>>                {
>> -               bool big = (*decoded_options)[j].opt_index == OPT_fPIC
>> +               bool big = decoded_options[j].opt_index == OPT_fPIC
>>                             && pie_option->opt_index == OPT_fPIE;
>> -               (*decoded_options)[j].opt_index = big ? OPT_fPIE : OPT_fpie;
>> +               decoded_options[j].opt_index = big ? OPT_fPIE : OPT_fpie;
>>                  if (pie_option->value)
>> -                 (*decoded_options)[j].canonical_option[0]
>> +                 decoded_options[j].canonical_option[0]
>>                      = big ? "-fPIE" : "-fpie";
>>                  else
>> -                 (*decoded_options)[j].canonical_option[0] = "-fno-pie";
>> -               (*decoded_options)[j].value = pie_option->value;
>> -               j++;
>> +                 decoded_options[j].canonical_option[0] = "-fno-pie";
>> +               decoded_options[j].value = pie_option->value;
>> +               j++;
>>                }
>>              else if (pic_option)
>>                {
>> -               (*decoded_options)[j] = *pic_option;
>> -               j++;
>> +               decoded_options[j] = *pic_option;
>> +               j++;
>>                }
>>              /* We do not know if target defaults to pic or not, so just remove
>>                 option if it is missing in one unit but enabled in other.  */
>>              else
>> -             remove_option (decoded_options, j, decoded_options_count);
>> +             decoded_options.ordered_remove (j);
>>            }
>>          else if (pic_option->opt_index == OPT_fpic
>> -                && (*decoded_options)[j].opt_index == OPT_fPIC)
>> +                && decoded_options[j].opt_index == OPT_fPIC)
>>            {
>> -           (*decoded_options)[j] = *pic_option;
>> +           decoded_options[j] = *pic_option;
>>              j++;
>>            }
>>          else
>>            j++;
>>         }
>> -   else if ((*decoded_options)[j].opt_index == OPT_fPIE
>> -            || (*decoded_options)[j].opt_index == OPT_fpie)
>> +   else if (decoded_options[j].opt_index == OPT_fPIE
>> +           || decoded_options[j].opt_index == OPT_fpie)
>>         {
>>          /* -fno-pie in one unit implies -fno-pie everywhere.  */
>> -       if ((*decoded_options)[j].value == 0)
>> +       if (decoded_options[j].value == 0)
>>            j++;
>>          /* If we have no pie option or merge in -fno-pie, we still preserve
>>             PIE/pie if pic/PIC is present.  */
>> @@ -516,32 +497,32 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>              if (pic_option)
>>                {
>>                  if (pic_option->opt_index == OPT_fpic
>> -                   && (*decoded_options)[j].opt_index == OPT_fPIE)
>> +                   && decoded_options[j].opt_index == OPT_fPIE)
>>                    {
>> -                   (*decoded_options)[j].opt_index = OPT_fpie;
>> -                   (*decoded_options)[j].canonical_option[0]
>> +                   decoded_options[j].opt_index = OPT_fpie;
>> +                   decoded_options[j].canonical_option[0]
>>                        = pic_option->value ? "-fpie" : "-fno-pie";
>>                    }
>>                  else if (!pic_option->value)
>> -                 (*decoded_options)[j].canonical_option[0] = "-fno-pie";
>> -               (*decoded_options)[j].value = pic_option->value;
>> +                 decoded_options[j].canonical_option[0] = "-fno-pie";
>> +               decoded_options[j].value = pic_option->value;
>>                  j++;
>>                }
>>              else if (pie_option)
>>                {
>> -               (*decoded_options)[j] = *pie_option;
>> +               decoded_options[j] = *pie_option;
>>                  j++;
>>                }
>>              /* Because we always append pic/PIE options this code path should
>>                 not happen unless the LTO object was built by old lto1 which
>>                 did not contain that logic yet.  */
>>              else
>> -             remove_option (decoded_options, j, decoded_options_count);
>> +             decoded_options.ordered_remove (j);
>>            }
>>          else if (pie_option->opt_index == OPT_fpie
>> -                && (*decoded_options)[j].opt_index == OPT_fPIE)
>> +                && decoded_options[j].opt_index == OPT_fPIE)
>>            {
>> -           (*decoded_options)[j] = *pie_option;
>> +           decoded_options[j] = *pie_option;
>>              j++;
>>            }
>>          else
>> @@ -553,37 +534,34 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>     if (!xassembler_options_error)
>>       for (i = j = 0; ; i++, j++)
>>         {
>> -       for (; i < *decoded_options_count; i++)
>> -         if ((*decoded_options)[i].opt_index == OPT_Xassembler)
>> -           break;
>> -
>> -       for (; j < fdecoded_options_count; j++)
>> -         if (fdecoded_options[j].opt_index == OPT_Xassembler)
>> -           break;
>> +       cl_decoded_option *existing_opt
>> +         = find_option (decoded_options, OPT_Xassembler);
>> +       cl_decoded_option *existing_opt2
>> +         = find_option (fdecoded_options, OPT_Xassembler);
>>
>> -       if (i == *decoded_options_count && j == fdecoded_options_count)
>> +       if (existing_opt == NULL && existing_opt2 == NULL)
>>            break;
>> -       else if (i < *decoded_options_count && j == fdecoded_options_count)
>> +       else if (existing_opt != NULL && existing_opt2 == NULL)
>>            {
>>              warning (0, "Extra option to %<-Xassembler%>: %s,"
>>                       " dropping all %<-Xassembler%> and %<-Wa%> options.",
>> -                    (*decoded_options)[i].arg);
>> +                    existing_opt->arg);
>>              xassembler_options_error = true;
>>              break;
>>            }
>> -       else if (i == *decoded_options_count && j < fdecoded_options_count)
>> +       else if (existing_opt == NULL && existing_opt2 != NULL)
>>            {
>>              warning (0, "Extra option to %<-Xassembler%>: %s,"
>>                       " dropping all %<-Xassembler%> and %<-Wa%> options.",
>> -                    fdecoded_options[j].arg);
>> +                    existing_opt2->arg);
>>              xassembler_options_error = true;
>>              break;
>>            }
>> -       else if (strcmp ((*decoded_options)[i].arg, fdecoded_options[j].arg))
>> +       else if (strcmp (existing_opt->arg, existing_opt2->arg) != 0)
>>            {
>>              warning (0, "Options to %<-Xassembler%> do not match: %s, %s,"
>>                       " dropping all %<-Xassembler%> and %<-Wa%> options.",
>> -                    (*decoded_options)[i].arg, fdecoded_options[j].arg);
>> +                    existing_opt->arg, existing_opt2->arg);
>>              xassembler_options_error = true;
>>              break;
>>            }
>> @@ -654,13 +632,12 @@ parse_env_var (const char *str, char ***pvalues, const char *append)
>>   /* Append options OPTS from lto or offload_lto sections to ARGV_OBSTACK.  */
>>
>>   static void
>> -append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts,
>> -                        unsigned int count)
>> +append_compiler_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
>>   {
>>     /* Append compiler driver arguments as far as they were merged.  */
>> -  for (unsigned int j = 1; j < count; ++j)
>> +  for (unsigned int j = 1; j < opts.length (); ++j)
>>       {
>> -      struct cl_decoded_option *option = &opts[j];
>> +      cl_decoded_option *option = &opts[j];
>>
>>         /* File options have been properly filtered by lto-opts.c.  */
>>         switch (option->opt_index)
>> @@ -721,16 +698,15 @@ append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts,
>>       }
>>   }
>>
>> -/* Append diag options in OPTS with length COUNT to ARGV_OBSTACK.  */
>> +/* Append diag options in OPTS to ARGV_OBSTACK.  */
>>
>>   static void
>> -append_diag_options (obstack *argv_obstack, struct cl_decoded_option *opts,
>> -                    unsigned int count)
>> +append_diag_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
>>   {
>>     /* Append compiler driver arguments as far as they were merged.  */
>> -  for (unsigned int j = 1; j < count; ++j)
>> +  for (unsigned int j = 1; j < opts.length (); ++j)
>>       {
>> -      struct cl_decoded_option *option = &opts[j];
>> +      cl_decoded_option *option = &opts[j];
>>
>>         switch (option->opt_index)
>>          {
>> @@ -757,14 +733,13 @@ append_diag_options (obstack *argv_obstack, struct cl_decoded_option *opts,
>>   /* Append linker options OPTS to ARGV_OBSTACK.  */
>>
>>   static void
>> -append_linker_options (obstack *argv_obstack, struct cl_decoded_option *opts,
>> -                      unsigned int count)
>> +append_linker_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
>>   {
>>     /* Append linker driver arguments.  Compiler options from the linker
>>        driver arguments will override / merge with those from the compiler.  */
>> -  for (unsigned int j = 1; j < count; ++j)
>> +  for (unsigned int j = 1; j < opts.length (); ++j)
>>       {
>> -      struct cl_decoded_option *option = &opts[j];
>> +      cl_decoded_option *option = &opts[j];
>>
>>         /* Do not pass on frontend specific flags not suitable for lto.  */
>>         if (!(cl_options[option->opt_index].flags
>> @@ -802,15 +777,14 @@ append_linker_options (obstack *argv_obstack, struct cl_decoded_option *opts,
>>
>>   static void
>>   append_offload_options (obstack *argv_obstack, const char *target,
>> -                       struct cl_decoded_option *options,
>> -                       unsigned int options_count)
>> +                       vec<cl_decoded_option> options)
>>   {
>> -  for (unsigned i = 0; i < options_count; i++)
>> +  for (unsigned i = 0; i < options.length (); i++)
>>       {
>>         const char *cur, *next, *opts;
>>         char **argv;
>>         unsigned argc;
>> -      struct cl_decoded_option *option = &options[i];
>> +      cl_decoded_option *option = &options[i];
>>
>>         if (option->opt_index != OPT_foffload_)
>>          continue;
>> @@ -882,10 +856,8 @@ access_check (const char *name, int mode)
>>   static char *
>>   compile_offload_image (const char *target, const char *compiler_path,
>>                         unsigned in_argc, char *in_argv[],
>> -                      struct cl_decoded_option *compiler_opts,
>> -                      unsigned int compiler_opt_count,
>> -                      struct cl_decoded_option *linker_opts,
>> -                      unsigned int linker_opt_count)
>> +                      vec<cl_decoded_option> compiler_opts,
>> +                      vec<cl_decoded_option> linker_opts)
>>   {
>>     char *filename = NULL;
>>     char *dumpbase;
>> @@ -935,19 +907,16 @@ compile_offload_image (const char *target, const char *compiler_path,
>>       obstack_ptr_grow (&argv_obstack, in_argv[i]);
>>
>>     /* Append options from offload_lto sections.  */
>> -  append_compiler_options (&argv_obstack, compiler_opts,
>> -                          compiler_opt_count);
>> -  append_diag_options (&argv_obstack, linker_opts, linker_opt_count);
>> +  append_compiler_options (&argv_obstack, compiler_opts);
>> +  append_diag_options (&argv_obstack, linker_opts);
>>
>>     obstack_ptr_grow (&argv_obstack, "-dumpbase");
>>     obstack_ptr_grow (&argv_obstack, dumpbase);
>>
>>     /* Append options specified by -foffload last.  In case of conflicting
>>        options we expect offload compiler to choose the latest.  */
>> -  append_offload_options (&argv_obstack, target, compiler_opts,
>> -                         compiler_opt_count);
>> -  append_offload_options (&argv_obstack, target, linker_opts,
>> -                         linker_opt_count);
>> +  append_offload_options (&argv_obstack, target, compiler_opts);
>> +  append_offload_options (&argv_obstack, target, linker_opts);
>>
>>     obstack_ptr_grow (&argv_obstack, NULL);
>>     argv = XOBFINISH (&argv_obstack, char **);
>> @@ -966,10 +935,8 @@ compile_offload_image (const char *target, const char *compiler_path,
>>
>>   static void
>>   compile_images_for_offload_targets (unsigned in_argc, char *in_argv[],
>> -                                   struct cl_decoded_option *compiler_opts,
>> -                                   unsigned int compiler_opt_count,
>> -                                   struct cl_decoded_option *linker_opts,
>> -                                   unsigned int linker_opt_count)
>> +                                   vec<cl_decoded_option> compiler_opts,
>> +                                   vec<cl_decoded_option> linker_opts)
>>   {
>>     char **names = NULL;
>>     const char *target_names = getenv (OFFLOAD_TARGET_NAMES_ENV);
>> @@ -988,8 +955,7 @@ compile_images_for_offload_targets (unsigned in_argc, char *in_argv[],
>>       {
>>         offload_names[i]
>>          = compile_offload_image (names[i], compiler_path, in_argc, in_argv,
>> -                                compiler_opts, compiler_opt_count,
>> -                                linker_opts, linker_opt_count);
>> +                                compiler_opts, linker_opts);
>>         if (!offload_names[i])
>>          fatal_error (input_location,
>>                       "problem with building target image for %s", names[i]);
>> @@ -1058,25 +1024,22 @@ find_crtoffloadtable (int save_temps, const char *dumppfx)
>>   }
>>
>>   /* A subroutine of run_gcc.  Examine the open file FD for lto sections with
>> -   name prefix PREFIX, at FILE_OFFSET, and store any options we find in OPTS
>> -   and OPT_COUNT.  Return true if we found a matching section, false
>> +   name prefix PREFIX, at FILE_OFFSET, and store any options we find in OPTS.
>> +   Return true if we found a matching section, false
>>      otherwise.  COLLECT_GCC holds the value of the environment variable with
>>      the same name.  */
>>
>>   static bool
>>   find_and_merge_options (int fd, off_t file_offset, const char *prefix,
>> -                       struct cl_decoded_option *decoded_cl_options,
>> -                       unsigned int decoded_cl_options_count,
>> -                       struct cl_decoded_option **opts,
>> -                       unsigned int *opt_count, const char *collect_gcc)
>> +                       vec<cl_decoded_option> decoded_cl_options,
>> +                       vec<cl_decoded_option> *opts, const char *collect_gcc)
>>   {
>>     off_t offset, length;
>>     char *data;
>>     char *fopts;
>>     const char *errmsg;
>>     int err;
>> -  struct cl_decoded_option *fdecoded_options = *opts;
>> -  unsigned int fdecoded_options_count = *opt_count;
>> +  vec<cl_decoded_option> fdecoded_options;
>>
>>     simple_object_read *sobj;
>>     sobj = simple_object_start_read (fd, file_offset, "__GNU_LTO",
>> @@ -1098,24 +1061,19 @@ find_and_merge_options (int fd, off_t file_offset, const char *prefix,
>>     data = (char *)xmalloc (length);
>>     read (fd, data, length);
>>     fopts = data;
>> +  bool first = true;
>>     do
>>       {
>> -      struct cl_decoded_option *f2decoded_options;
>> -      unsigned int f2decoded_options_count;
>> -      get_options_from_collect_gcc_options (collect_gcc, fopts,
>> -                                           &f2decoded_options,
>> -                                           &f2decoded_options_count);
>> -      if (!fdecoded_options)
>> -       {
>> -        fdecoded_options = f2decoded_options;
>> -        fdecoded_options_count = f2decoded_options_count;
>> -       }
>> +      vec<cl_decoded_option> f2decoded_options
>> +       = get_options_from_collect_gcc_options (collect_gcc, fopts);
>> +      if (first)
>> +       {
>> +         fdecoded_options = f2decoded_options;
>> +         first = false;
>> +       }
>>         else
>> -       merge_and_complain (&fdecoded_options,
>> -                           &fdecoded_options_count,
>> -                           f2decoded_options, f2decoded_options_count,
>> -                           decoded_cl_options,
>> -                           decoded_cl_options_count);
>> +       merge_and_complain (fdecoded_options, f2decoded_options,
>> +                           decoded_cl_options);
>>
>>         fopts += strlen (fopts) + 1;
>>       }
>> @@ -1124,7 +1082,6 @@ find_and_merge_options (int fd, off_t file_offset, const char *prefix,
>>     free (data);
>>     simple_object_release_read (sobj);
>>     *opts = fdecoded_options;
>> -  *opt_count = fdecoded_options_count;
>>     return true;
>>   }
>>
>> @@ -1371,12 +1328,9 @@ run_gcc (unsigned argc, char *argv[])
>>     int jobserver = 0;
>>     int auto_parallel = 0;
>>     bool no_partition = false;
>> -  struct cl_decoded_option *fdecoded_options = NULL;
>> -  struct cl_decoded_option *offload_fdecoded_options = NULL;
>> -  unsigned int fdecoded_options_count = 0;
>> -  unsigned int offload_fdecoded_options_count = 0;
>> -  struct cl_decoded_option *decoded_options;
>> -  unsigned int decoded_options_count;
>> +  vec<cl_decoded_option> fdecoded_options;
>> +  fdecoded_options.create (16);
>> +  vec<cl_decoded_option> offload_fdecoded_options = vNULL;
>>     struct obstack argv_obstack;
>>     int new_head_argc;
>>     bool have_lto = false;
>> @@ -1418,9 +1372,8 @@ run_gcc (unsigned argc, char *argv[])
>>                                      NULL);
>>       }
>>
>> -  get_options_from_collect_gcc_options (collect_gcc, collect_gcc_options,
>> -                                       &decoded_options,
>> -                                       &decoded_options_count);
>> +  vec<cl_decoded_option> decoded_options
>> +    = get_options_from_collect_gcc_options (collect_gcc, collect_gcc_options);
>>
>>     /* Allocate array for input object files with LTO IL,
>>        and for possible preceding arguments.  */
>> @@ -1470,8 +1423,7 @@ run_gcc (unsigned argc, char *argv[])
>>          }
>>
>>         if (find_and_merge_options (fd, file_offset, LTO_SECTION_NAME_PREFIX,
>> -                                 decoded_options, decoded_options_count,
>> -                                 &fdecoded_options, &fdecoded_options_count,
>> +                                 decoded_options, &fdecoded_options,
>>                                    collect_gcc))
>>          {
>>            have_lto = true;
>> @@ -1486,14 +1438,13 @@ run_gcc (unsigned argc, char *argv[])
>>     obstack_ptr_grow (&argv_obstack, "-xlto");
>>     obstack_ptr_grow (&argv_obstack, "-c");
>>
>> -  append_compiler_options (&argv_obstack, fdecoded_options,
>> -                          fdecoded_options_count);
>> -  append_linker_options (&argv_obstack, decoded_options, decoded_options_count);
>> +  append_compiler_options (&argv_obstack, fdecoded_options);
>> +  append_linker_options (&argv_obstack, decoded_options);
>>
>>     /* Scan linker driver arguments for things that are of relevance to us.  */
>> -  for (j = 1; j < decoded_options_count; ++j)
>> +  for (j = 1; j < decoded_options.length (); ++j)
>>       {
>> -      struct cl_decoded_option *option = &decoded_options[j];
>> +      cl_decoded_option *option = &decoded_options[j];
>>         switch (option->opt_index)
>>          {
>>          case OPT_o:
>> @@ -1711,9 +1662,7 @@ cont1:
>>              fatal_error (input_location, "cannot open %s: %m", filename);
>>            if (!find_and_merge_options (fd, file_offset,
>>                                         OFFLOAD_SECTION_NAME_PREFIX,
>> -                                      decoded_options, decoded_options_count,
>> -                                      &offload_fdecoded_options,
>> -                                      &offload_fdecoded_options_count,
>> +                                      decoded_options, &offload_fdecoded_options,
>>                                         collect_gcc))
>>              fatal_error (input_location, "cannot read %s: %m", filename);
>>            close (fd);
>> @@ -1722,10 +1671,7 @@ cont1:
>>          }
>>
>>         compile_images_for_offload_targets (num_offload_files, offload_argv,
>> -                                         offload_fdecoded_options,
>> -                                         offload_fdecoded_options_count,
>> -                                         decoded_options,
>> -                                         decoded_options_count);
>> +                                         offload_fdecoded_options, decoded_options);
>>
>>         free_array_of_ptrs ((void **) offload_argv, num_offload_files);
>>
>> --
>> 2.31.1
>>
Martin Liška May 12, 2021, 9:08 a.m. UTC | #3
On 4/29/21 2:22 PM, Richard Biener wrote:
> On Wed, Apr 21, 2021 at 11:12 AM Martin Liška <mliska@suse.cz> wrote:
>>
>> Now living in the 21st century, we don't longer need using the following tuple:
>> cl_decoded_option **decoded_options,
>>   unsigned int *decoded_options_count)
>> but we can rather use a standard (our) vector.
>>
>> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>>
>> Ready to be installed?
>> Thanks,
>> Martin
>>
>> gcc/ChangeLog:
>>
>>          * lto-wrapper.c (get_options_from_collect_gcc_options): Change
>>          return type.
>>          (append_option): Remove.
>>          (find_option): Rework to use the vector type.
>>          (remove_option): Remove.
>>          (merge_and_complain): Use vectors for cl_decoded_option data
>>          type arguments.
>>          (append_compiler_options): Likewise.
>>          (append_diag_options): Likewise.
>>          (append_linker_options): Likewise.
>>          (append_offload_options): Likewise.
>>          (compile_offload_image): Likewise.
>>          (compile_images_for_offload_targets): Likewise.
>>          (find_and_merge_options): Likewise.
>>          (run_gcc): Likewise.
>> ---
>>   gcc/lto-wrapper.c | 384 ++++++++++++++++++++--------------------------
>>   1 file changed, 165 insertions(+), 219 deletions(-)
>>
>> diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
>> index 03a5922f8ea..5ccf729b249 100644
>> --- a/gcc/lto-wrapper.c
>> +++ b/gcc/lto-wrapper.c
>> @@ -138,12 +138,12 @@ maybe_unlink (const char *file)
>>   /* Create decoded options from the COLLECT_GCC and COLLECT_GCC_OPTIONS
>>      environment.  */
>>
>> -static void
>> +static vec<cl_decoded_option>
> 
> bonus points for handling ownership transfer via returning an
> auto_vec<> (not sure if possible, but maybe it is).

Heh, about the bonus points: changing return type of get_options_from_collect_gcc_options to auto_vec<...>
leads to:

==26737== Invalid read of size 4

==26737==    at 0x406969: length (vec.h:589)

==26737==    by 0x406969: length (vec.h:1439)

==26737==    by 0x406969: append_compiler_options(obstack*, vec<cl_decoded_option, va_heap, vl_ptr>) (lto-wrapper.c:649)

==26737==    by 0x408E35: run_gcc(unsigned int, char**) (lto-wrapper.c:1470)

==26737==    by 0x406565: main (lto-wrapper.c:2070)

==26737==  Address 0x57838a4 is 4 bytes inside a block of size 1,152 free'd

==26737==    at 0x483FEC0: free (vg_replace_malloc.c:755)

==26737==    by 0x4078B5: release<cl_decoded_option> (vec.h:316)

==26737==    by 0x4078B5: release (vec.h:1832)

==26737==    by 0x4078B5: ~auto_vec (vec.h:1552)

==26737==    by 0x4078B5: find_and_merge_options(int, long, char const*, vec<cl_decoded_option, va_heap, vl_ptr>, vec<cl_decoded_option, va_heap, vl_ptr>*, char const*) (lto-wrapper.c:1100)

==26737==    by 0x408D0E: run_gcc(unsigned int, char**) (lto-wrapper.c:1454)

==26737==    by 0x406565: main (lto-wrapper.c:2070)

==26737==  Block was alloc'd at

==26737==    at 0x483D70F: malloc (vg_replace_malloc.c:380)

==26737==    by 0x49554F: xrealloc (xmalloc.c:177)

==26737==    by 0x4076CC: reserve<cl_decoded_option> (vec.h:290)

==26737==    by 0x4076CC: reserve (vec.h:1778)

==26737==    by 0x4076CC: reserve_exact (vec.h:1798)

==26737==    by 0x4076CC: create (vec.h:1813)

==26737==    by 0x4076CC: get_options_from_collect_gcc_options(char const*, char const*) (lto-wrapper.c:162)

==26737==    by 0x4078FC: find_and_merge_options(int, long, char const*, vec<cl_decoded_option, va_heap, vl_ptr>, vec<cl_decoded_option, va_heap, vl_ptr>*, char const*) (lto-wrapper.c:1100)

==26737==    by 0x408D0E: run_gcc(unsigned int, char**) (lto-wrapper.c:1454)

==26737==    by 0x406565: main (lto-wrapper.c:2070)


> 
>>   get_options_from_collect_gcc_options (const char *collect_gcc,
>> -                                     const char *collect_gcc_options,
>> -                                     struct cl_decoded_option **decoded_options,
>> -                                     unsigned int *decoded_options_count)
>> +                                     const char *collect_gcc_options)
>>   {
>> +  cl_decoded_option *decoded_options;
>> +  unsigned int decoded_options_count;
>>     struct obstack argv_obstack;
>>     const char **argv;
>>     int argc;
>> @@ -156,57 +156,49 @@ get_options_from_collect_gcc_options (const char *collect_gcc,
>>     argv = XOBFINISH (&argv_obstack, const char **);
>>
>>     decode_cmdline_options_to_array (argc, (const char **)argv, CL_DRIVER,
>> -                                  decoded_options, decoded_options_count);
>> +                                  &decoded_options, &decoded_options_count);
>> +  vec<cl_decoded_option> decoded;
>> +  decoded.create (decoded_options_count);
>> +  for (unsigned i = 0; i < decoded_options_count; ++i)
>> +    decoded.quick_push (decoded_options[i]);
>> +  free (decoded_options);
>> +
>>     obstack_free (&argv_obstack, NULL);
>> +
>> +  return decoded;
>>   }
>>
>> -/* Append OPTION to the options array DECODED_OPTIONS with size
>> -   DECODED_OPTIONS_COUNT.  */
>> +/* Find option in OPTIONS based on OPT_INDEX.  NULL value is returned
>> +   if the option is not present.  */
>>
>> -static void
>> -append_option (struct cl_decoded_option **decoded_options,
>> -              unsigned int *decoded_options_count,
>> -              struct cl_decoded_option *option)
>> +static cl_decoded_option *
>> +find_option (vec<cl_decoded_option> &options, size_t opt_index)
>>   {
>> -  ++*decoded_options_count;
>> -  *decoded_options
>> -    = (struct cl_decoded_option *)
>> -       xrealloc (*decoded_options,
>> -                 (*decoded_options_count
>> -                  * sizeof (struct cl_decoded_option)));
>> -  memcpy (&(*decoded_options)[*decoded_options_count - 1], option,
>> -         sizeof (struct cl_decoded_option));
>> -}
>> +  for (unsigned i = 0; i < options.length (); ++i)
>> +    if (options[i].opt_index == opt_index)
>> +      return &options[i];
> 
> You're returning a pointer into the vector here...
> 
>> -/* Remove option number INDEX from DECODED_OPTIONS, update
>> -   DECODED_OPTIONS_COUNT.  */
>> +  return NULL;
>> +}
>>
>> -static void
>> -remove_option (struct cl_decoded_option **decoded_options,
>> -              int index, unsigned int *decoded_options_count)
>> +static cl_decoded_option *
>> +find_option (vec<cl_decoded_option> &options, cl_decoded_option *option)
>>   {
>> -  --*decoded_options_count;
>> -  memmove (&(*decoded_options)[index + 1],
>> -          &(*decoded_options)[index],
>> -          sizeof (struct cl_decoded_option)
>> -          * (*decoded_options_count - index));
>> +  return find_option (options, option->opt_index);
>>   }
>>
>>   /* Try to merge and complain about options FDECODED_OPTIONS when applied
>>      ontop of DECODED_OPTIONS.  */
>>
>>   static void
>> -merge_and_complain (struct cl_decoded_option **decoded_options,
>> -                   unsigned int *decoded_options_count,
>> -                   struct cl_decoded_option *fdecoded_options,
>> -                   unsigned int fdecoded_options_count,
>> -                   struct cl_decoded_option *decoded_cl_options,
>> -                   unsigned int decoded_cl_options_count)
>> +merge_and_complain (vec<cl_decoded_option> decoded_options,
>> +                   vec<cl_decoded_option> fdecoded_options,
>> +                   vec<cl_decoded_option> decoded_cl_options)
>>   {
>>     unsigned int i, j;
>> -  struct cl_decoded_option *pic_option = NULL;
>> -  struct cl_decoded_option *pie_option = NULL;
>> -  struct cl_decoded_option *cf_protection_option = NULL;
>> +  cl_decoded_option *pic_option = NULL;
>> +  cl_decoded_option *pie_option = NULL;
>> +  cl_decoded_option *cf_protection_option = NULL;
>>
>>     /* ???  Merge options from files.  Most cases can be
>>        handled by either unioning or intersecting
>> @@ -223,9 +215,9 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>
>>     /* Look for a -fcf-protection option in the link-time options
>>        which overrides any -fcf-protection from the lto sections.  */
>> -  for (i = 0; i < decoded_cl_options_count; ++i)
>> +  for (i = 0; i < decoded_cl_options.length (); ++i)
>>       {
>> -      struct cl_decoded_option *foption = &decoded_cl_options[i];
>> +      cl_decoded_option *foption = &decoded_cl_options[i];
>>         if (foption->opt_index == OPT_fcf_protection_)
>>          {
>>            cf_protection_option = foption;
>> @@ -234,9 +226,10 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>
>>     /* The following does what the old LTO option code did,
>>        union all target and a selected set of common options.  */
>> -  for (i = 0; i < fdecoded_options_count; ++i)
>> +  for (i = 0; i < fdecoded_options.length (); ++i)
>>       {
>> -      struct cl_decoded_option *foption = &fdecoded_options[i];
>> +      cl_decoded_option *foption = &fdecoded_options[i];
>> +      cl_decoded_option *existing_opt = find_option (decoded_options, foption);
>>         switch (foption->opt_index)
>>          {
>>          case OPT_SPECIAL_unknown:
>> @@ -264,11 +257,8 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>               setting per OPT code, we pick the first we encounter.
>>               ???  This doesn't make too much sense, but when it doesn't
>>               then we should complain.  */
>> -         for (j = 0; j < *decoded_options_count; ++j)
>> -           if ((*decoded_options)[j].opt_index == foption->opt_index)
>> -             break;
>> -         if (j == *decoded_options_count)
>> -           append_option (decoded_options, decoded_options_count, foption);
>> +         if (existing_opt == NULL)
>> +           decoded_options.safe_push (*foption);
> 
> and you end up re-allocating that here.  That's an eventually dangerous
> pattern ... please consider to instead returning an index from find()
> (and -1 for not found or so).

You are right. I've done that in the patch and it survives regression tests.
May I install it? The auto_vec can be done incrementally I guess.

Martin

> 
>>            break;
>>
>>          /* Figure out what PIC/PIE level wins and merge the results.  */
>> @@ -284,25 +274,19 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>          case OPT_fopenmp:
>>          case OPT_fopenacc:
>>            /* For selected options we can merge conservatively.  */
>> -         for (j = 0; j < *decoded_options_count; ++j)
>> -           if ((*decoded_options)[j].opt_index == foption->opt_index)
>> -             break;
>> -         if (j == *decoded_options_count)
>> -           append_option (decoded_options, decoded_options_count, foption);
>> +         if (existing_opt == NULL)
>> +           decoded_options.safe_push (*foption);
>>            /* -fopenmp > -fno-openmp,
>>               -fopenacc > -fno-openacc  */
>> -         else if (foption->value > (*decoded_options)[j].value)
>> -           (*decoded_options)[j] = *foption;
>> +         else if (foption->value > existing_opt->value)
>> +           *existing_opt = *foption;
>>            break;
>>
>>          case OPT_fopenacc_dim_:
>>            /* Append or check identical.  */
>> -         for (j = 0; j < *decoded_options_count; ++j)
>> -           if ((*decoded_options)[j].opt_index == foption->opt_index)
>> -             break;
>> -         if (j == *decoded_options_count)
>> -           append_option (decoded_options, decoded_options_count, foption);
>> -         else if (strcmp ((*decoded_options)[j].arg, foption->arg))
>> +         if (existing_opt == NULL)
>> +           decoded_options.safe_push (*foption);
>> +         else if (strcmp (existing_opt->arg, foption->arg))
>>              fatal_error (input_location,
>>                           "option %s with different values",
>>                           foption->orig_option_with_args_text);
>> @@ -313,12 +297,9 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>            if (!cf_protection_option
>>                || cf_protection_option->value == CF_CHECK)
>>              {
>> -             for (j = 0; j < *decoded_options_count; ++j)
>> -               if ((*decoded_options)[j].opt_index == foption->opt_index)
>> -                 break;
>> -             if (j == *decoded_options_count)
>> -               append_option (decoded_options, decoded_options_count, foption);
>> -             else if ((*decoded_options)[j].value != foption->value)
>> +             if (existing_opt == NULL)
>> +               decoded_options.safe_push (*foption);
>> +             else if (existing_opt->value != foption->value)
>>                  {
>>                    if (cf_protection_option
>>                        && cf_protection_option->value == CF_CHECK)
>> @@ -326,22 +307,21 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>                                   "option %qs with mismatching values"
>>                                   " (%s, %s)",
>>                                   "-fcf-protection",
>> -                                (*decoded_options)[j].arg, foption->arg);
>> +                                existing_opt->arg, foption->arg);
>>                    else
>>                      {
>>                        /* Merge and update the -fcf-protection option.  */
>> -                     (*decoded_options)[j].value &= (foption->value
>> -                                                     & CF_FULL);
>> -                     switch ((*decoded_options)[j].value)
>> +                     existing_opt->value &= (foption->value & CF_FULL);
>> +                     switch (existing_opt->value)
>>                          {
>>                          case CF_NONE:
>> -                         (*decoded_options)[j].arg = "none";
>> +                         existing_opt->arg = "none";
>>                            break;
>>                          case CF_BRANCH:
>> -                         (*decoded_options)[j].arg = "branch";
>> +                         existing_opt->arg = "branch";
>>                            break;
>>                          case CF_RETURN:
>> -                         (*decoded_options)[j].arg = "return";
>> +                         existing_opt->arg = "return";
>>                            break;
>>                          default:
>>                            gcc_unreachable ();
>> @@ -355,15 +335,19 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>          case OPT_Ofast:
>>          case OPT_Og:
>>          case OPT_Os:
>> -         for (j = 0; j < *decoded_options_count; ++j)
>> -           if ((*decoded_options)[j].opt_index == OPT_O
>> -               || (*decoded_options)[j].opt_index == OPT_Ofast
>> -               || (*decoded_options)[j].opt_index == OPT_Og
>> -               || (*decoded_options)[j].opt_index == OPT_Os)
>> -             break;
>> -         if (j == *decoded_options_count)
>> -           append_option (decoded_options, decoded_options_count, foption);
>> -         else if ((*decoded_options)[j].opt_index == foption->opt_index
>> +         existing_opt = NULL;
>> +         for (j = 0; j < decoded_options.length (); ++j)
>> +           if (decoded_options[j].opt_index == OPT_O
>> +               || decoded_options[j].opt_index == OPT_Ofast
>> +               || decoded_options[j].opt_index == OPT_Og
>> +               || decoded_options[j].opt_index == OPT_Os)
>> +             {
>> +               existing_opt = &decoded_options[j];
>> +               break;
>> +             }
>> +         if (existing_opt == NULL)
>> +           decoded_options.safe_push (*foption);
>> +         else if (existing_opt->opt_index == foption->opt_index
>>                     && foption->opt_index != OPT_O)
>>              /* Exact same options get merged.  */
>>              ;
>> @@ -393,13 +377,13 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>                  default:
>>                    gcc_unreachable ();
>>                  }
>> -             switch ((*decoded_options)[j].opt_index)
>> +             switch (existing_opt->opt_index)
>>                  {
>>                  case OPT_O:
>> -                 if ((*decoded_options)[j].arg[0] == '\0')
>> +                 if (existing_opt->arg[0] == '\0')
>>                      level = MAX (level, 1);
>>                    else
>> -                   level = MAX (level, atoi ((*decoded_options)[j].arg));
>> +                   level = MAX (level, atoi (existing_opt->arg));
>>                    break;
>>                  case OPT_Ofast:
>>                    level = MAX (level, 3);
>> @@ -413,23 +397,20 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>                  default:
>>                    gcc_unreachable ();
>>                  }
>> -             (*decoded_options)[j].opt_index = OPT_O;
>> +             existing_opt->opt_index = OPT_O;
>>                char *tem;
>>                tem = xasprintf ("-O%d", level);
>> -             (*decoded_options)[j].arg = &tem[2];
>> -             (*decoded_options)[j].canonical_option[0] = tem;
>> -             (*decoded_options)[j].value = 1;
>> +             existing_opt->arg = &tem[2];
>> +             existing_opt->canonical_option[0] = tem;
>> +             existing_opt->value = 1;
>>              }
>>            break;
>>
>>
>>          case OPT_foffload_abi_:
>> -         for (j = 0; j < *decoded_options_count; ++j)
>> -           if ((*decoded_options)[j].opt_index == foption->opt_index)
>> -             break;
>> -         if (j == *decoded_options_count)
>> -           append_option (decoded_options, decoded_options_count, foption);
>> -         else if (foption->value != (*decoded_options)[j].value)
>> +         if (existing_opt == NULL)
>> +           decoded_options.safe_push (*foption);
>> +         else if (foption->value != existing_opt->value)
>>              fatal_error (input_location,
>>                           "option %s not used consistently in all LTO input"
>>                           " files", foption->orig_option_with_args_text);
>> @@ -437,7 +418,7 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>
>>
>>          case OPT_foffload_:
>> -         append_option (decoded_options, decoded_options_count, foption);
>> +         decoded_options.safe_push (*foption);
>>            break;
>>          }
>>       }
>> @@ -457,12 +438,12 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>        It would be good to warn on mismatches, but it is bit hard to do as
>>        we do not know what nothing translates to.  */
>>
>> -  for (unsigned int j = 0; j < *decoded_options_count;)
>> -    if ((*decoded_options)[j].opt_index == OPT_fPIC
>> -        || (*decoded_options)[j].opt_index == OPT_fpic)
>> +  for (unsigned int j = 0; j < decoded_options.length ();)
>> +    if (decoded_options[j].opt_index == OPT_fPIC
>> +       || decoded_options[j].opt_index == OPT_fpic)
>>         {
>>          /* -fno-pic in one unit implies -fno-pic everywhere.  */
>> -       if ((*decoded_options)[j].value == 0)
>> +       if (decoded_options[j].value == 0)
>>            j++;
>>          /* If we have no pic option or merge in -fno-pic, we still may turn
>>             existing pic/PIC mode into pie/PIE if -fpie/-fPIE is present.  */
>> @@ -471,41 +452,41 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>            {
>>              if (pie_option)
>>                {
>> -               bool big = (*decoded_options)[j].opt_index == OPT_fPIC
>> +               bool big = decoded_options[j].opt_index == OPT_fPIC
>>                             && pie_option->opt_index == OPT_fPIE;
>> -               (*decoded_options)[j].opt_index = big ? OPT_fPIE : OPT_fpie;
>> +               decoded_options[j].opt_index = big ? OPT_fPIE : OPT_fpie;
>>                  if (pie_option->value)
>> -                 (*decoded_options)[j].canonical_option[0]
>> +                 decoded_options[j].canonical_option[0]
>>                      = big ? "-fPIE" : "-fpie";
>>                  else
>> -                 (*decoded_options)[j].canonical_option[0] = "-fno-pie";
>> -               (*decoded_options)[j].value = pie_option->value;
>> -               j++;
>> +                 decoded_options[j].canonical_option[0] = "-fno-pie";
>> +               decoded_options[j].value = pie_option->value;
>> +               j++;
>>                }
>>              else if (pic_option)
>>                {
>> -               (*decoded_options)[j] = *pic_option;
>> -               j++;
>> +               decoded_options[j] = *pic_option;
>> +               j++;
>>                }
>>              /* We do not know if target defaults to pic or not, so just remove
>>                 option if it is missing in one unit but enabled in other.  */
>>              else
>> -             remove_option (decoded_options, j, decoded_options_count);
>> +             decoded_options.ordered_remove (j);
>>            }
>>          else if (pic_option->opt_index == OPT_fpic
>> -                && (*decoded_options)[j].opt_index == OPT_fPIC)
>> +                && decoded_options[j].opt_index == OPT_fPIC)
>>            {
>> -           (*decoded_options)[j] = *pic_option;
>> +           decoded_options[j] = *pic_option;
>>              j++;
>>            }
>>          else
>>            j++;
>>         }
>> -   else if ((*decoded_options)[j].opt_index == OPT_fPIE
>> -            || (*decoded_options)[j].opt_index == OPT_fpie)
>> +   else if (decoded_options[j].opt_index == OPT_fPIE
>> +           || decoded_options[j].opt_index == OPT_fpie)
>>         {
>>          /* -fno-pie in one unit implies -fno-pie everywhere.  */
>> -       if ((*decoded_options)[j].value == 0)
>> +       if (decoded_options[j].value == 0)
>>            j++;
>>          /* If we have no pie option or merge in -fno-pie, we still preserve
>>             PIE/pie if pic/PIC is present.  */
>> @@ -516,32 +497,32 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>              if (pic_option)
>>                {
>>                  if (pic_option->opt_index == OPT_fpic
>> -                   && (*decoded_options)[j].opt_index == OPT_fPIE)
>> +                   && decoded_options[j].opt_index == OPT_fPIE)
>>                    {
>> -                   (*decoded_options)[j].opt_index = OPT_fpie;
>> -                   (*decoded_options)[j].canonical_option[0]
>> +                   decoded_options[j].opt_index = OPT_fpie;
>> +                   decoded_options[j].canonical_option[0]
>>                        = pic_option->value ? "-fpie" : "-fno-pie";
>>                    }
>>                  else if (!pic_option->value)
>> -                 (*decoded_options)[j].canonical_option[0] = "-fno-pie";
>> -               (*decoded_options)[j].value = pic_option->value;
>> +                 decoded_options[j].canonical_option[0] = "-fno-pie";
>> +               decoded_options[j].value = pic_option->value;
>>                  j++;
>>                }
>>              else if (pie_option)
>>                {
>> -               (*decoded_options)[j] = *pie_option;
>> +               decoded_options[j] = *pie_option;
>>                  j++;
>>                }
>>              /* Because we always append pic/PIE options this code path should
>>                 not happen unless the LTO object was built by old lto1 which
>>                 did not contain that logic yet.  */
>>              else
>> -             remove_option (decoded_options, j, decoded_options_count);
>> +             decoded_options.ordered_remove (j);
>>            }
>>          else if (pie_option->opt_index == OPT_fpie
>> -                && (*decoded_options)[j].opt_index == OPT_fPIE)
>> +                && decoded_options[j].opt_index == OPT_fPIE)
>>            {
>> -           (*decoded_options)[j] = *pie_option;
>> +           decoded_options[j] = *pie_option;
>>              j++;
>>            }
>>          else
>> @@ -553,37 +534,34 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
>>     if (!xassembler_options_error)
>>       for (i = j = 0; ; i++, j++)
>>         {
>> -       for (; i < *decoded_options_count; i++)
>> -         if ((*decoded_options)[i].opt_index == OPT_Xassembler)
>> -           break;
>> -
>> -       for (; j < fdecoded_options_count; j++)
>> -         if (fdecoded_options[j].opt_index == OPT_Xassembler)
>> -           break;
>> +       cl_decoded_option *existing_opt
>> +         = find_option (decoded_options, OPT_Xassembler);
>> +       cl_decoded_option *existing_opt2
>> +         = find_option (fdecoded_options, OPT_Xassembler);
>>
>> -       if (i == *decoded_options_count && j == fdecoded_options_count)
>> +       if (existing_opt == NULL && existing_opt2 == NULL)
>>            break;
>> -       else if (i < *decoded_options_count && j == fdecoded_options_count)
>> +       else if (existing_opt != NULL && existing_opt2 == NULL)
>>            {
>>              warning (0, "Extra option to %<-Xassembler%>: %s,"
>>                       " dropping all %<-Xassembler%> and %<-Wa%> options.",
>> -                    (*decoded_options)[i].arg);
>> +                    existing_opt->arg);
>>              xassembler_options_error = true;
>>              break;
>>            }
>> -       else if (i == *decoded_options_count && j < fdecoded_options_count)
>> +       else if (existing_opt == NULL && existing_opt2 != NULL)
>>            {
>>              warning (0, "Extra option to %<-Xassembler%>: %s,"
>>                       " dropping all %<-Xassembler%> and %<-Wa%> options.",
>> -                    fdecoded_options[j].arg);
>> +                    existing_opt2->arg);
>>              xassembler_options_error = true;
>>              break;
>>            }
>> -       else if (strcmp ((*decoded_options)[i].arg, fdecoded_options[j].arg))
>> +       else if (strcmp (existing_opt->arg, existing_opt2->arg) != 0)
>>            {
>>              warning (0, "Options to %<-Xassembler%> do not match: %s, %s,"
>>                       " dropping all %<-Xassembler%> and %<-Wa%> options.",
>> -                    (*decoded_options)[i].arg, fdecoded_options[j].arg);
>> +                    existing_opt->arg, existing_opt2->arg);
>>              xassembler_options_error = true;
>>              break;
>>            }
>> @@ -654,13 +632,12 @@ parse_env_var (const char *str, char ***pvalues, const char *append)
>>   /* Append options OPTS from lto or offload_lto sections to ARGV_OBSTACK.  */
>>
>>   static void
>> -append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts,
>> -                        unsigned int count)
>> +append_compiler_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
>>   {
>>     /* Append compiler driver arguments as far as they were merged.  */
>> -  for (unsigned int j = 1; j < count; ++j)
>> +  for (unsigned int j = 1; j < opts.length (); ++j)
>>       {
>> -      struct cl_decoded_option *option = &opts[j];
>> +      cl_decoded_option *option = &opts[j];
>>
>>         /* File options have been properly filtered by lto-opts.c.  */
>>         switch (option->opt_index)
>> @@ -721,16 +698,15 @@ append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts,
>>       }
>>   }
>>
>> -/* Append diag options in OPTS with length COUNT to ARGV_OBSTACK.  */
>> +/* Append diag options in OPTS to ARGV_OBSTACK.  */
>>
>>   static void
>> -append_diag_options (obstack *argv_obstack, struct cl_decoded_option *opts,
>> -                    unsigned int count)
>> +append_diag_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
>>   {
>>     /* Append compiler driver arguments as far as they were merged.  */
>> -  for (unsigned int j = 1; j < count; ++j)
>> +  for (unsigned int j = 1; j < opts.length (); ++j)
>>       {
>> -      struct cl_decoded_option *option = &opts[j];
>> +      cl_decoded_option *option = &opts[j];
>>
>>         switch (option->opt_index)
>>          {
>> @@ -757,14 +733,13 @@ append_diag_options (obstack *argv_obstack, struct cl_decoded_option *opts,
>>   /* Append linker options OPTS to ARGV_OBSTACK.  */
>>
>>   static void
>> -append_linker_options (obstack *argv_obstack, struct cl_decoded_option *opts,
>> -                      unsigned int count)
>> +append_linker_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
>>   {
>>     /* Append linker driver arguments.  Compiler options from the linker
>>        driver arguments will override / merge with those from the compiler.  */
>> -  for (unsigned int j = 1; j < count; ++j)
>> +  for (unsigned int j = 1; j < opts.length (); ++j)
>>       {
>> -      struct cl_decoded_option *option = &opts[j];
>> +      cl_decoded_option *option = &opts[j];
>>
>>         /* Do not pass on frontend specific flags not suitable for lto.  */
>>         if (!(cl_options[option->opt_index].flags
>> @@ -802,15 +777,14 @@ append_linker_options (obstack *argv_obstack, struct cl_decoded_option *opts,
>>
>>   static void
>>   append_offload_options (obstack *argv_obstack, const char *target,
>> -                       struct cl_decoded_option *options,
>> -                       unsigned int options_count)
>> +                       vec<cl_decoded_option> options)
>>   {
>> -  for (unsigned i = 0; i < options_count; i++)
>> +  for (unsigned i = 0; i < options.length (); i++)
>>       {
>>         const char *cur, *next, *opts;
>>         char **argv;
>>         unsigned argc;
>> -      struct cl_decoded_option *option = &options[i];
>> +      cl_decoded_option *option = &options[i];
>>
>>         if (option->opt_index != OPT_foffload_)
>>          continue;
>> @@ -882,10 +856,8 @@ access_check (const char *name, int mode)
>>   static char *
>>   compile_offload_image (const char *target, const char *compiler_path,
>>                         unsigned in_argc, char *in_argv[],
>> -                      struct cl_decoded_option *compiler_opts,
>> -                      unsigned int compiler_opt_count,
>> -                      struct cl_decoded_option *linker_opts,
>> -                      unsigned int linker_opt_count)
>> +                      vec<cl_decoded_option> compiler_opts,
>> +                      vec<cl_decoded_option> linker_opts)
>>   {
>>     char *filename = NULL;
>>     char *dumpbase;
>> @@ -935,19 +907,16 @@ compile_offload_image (const char *target, const char *compiler_path,
>>       obstack_ptr_grow (&argv_obstack, in_argv[i]);
>>
>>     /* Append options from offload_lto sections.  */
>> -  append_compiler_options (&argv_obstack, compiler_opts,
>> -                          compiler_opt_count);
>> -  append_diag_options (&argv_obstack, linker_opts, linker_opt_count);
>> +  append_compiler_options (&argv_obstack, compiler_opts);
>> +  append_diag_options (&argv_obstack, linker_opts);
>>
>>     obstack_ptr_grow (&argv_obstack, "-dumpbase");
>>     obstack_ptr_grow (&argv_obstack, dumpbase);
>>
>>     /* Append options specified by -foffload last.  In case of conflicting
>>        options we expect offload compiler to choose the latest.  */
>> -  append_offload_options (&argv_obstack, target, compiler_opts,
>> -                         compiler_opt_count);
>> -  append_offload_options (&argv_obstack, target, linker_opts,
>> -                         linker_opt_count);
>> +  append_offload_options (&argv_obstack, target, compiler_opts);
>> +  append_offload_options (&argv_obstack, target, linker_opts);
>>
>>     obstack_ptr_grow (&argv_obstack, NULL);
>>     argv = XOBFINISH (&argv_obstack, char **);
>> @@ -966,10 +935,8 @@ compile_offload_image (const char *target, const char *compiler_path,
>>
>>   static void
>>   compile_images_for_offload_targets (unsigned in_argc, char *in_argv[],
>> -                                   struct cl_decoded_option *compiler_opts,
>> -                                   unsigned int compiler_opt_count,
>> -                                   struct cl_decoded_option *linker_opts,
>> -                                   unsigned int linker_opt_count)
>> +                                   vec<cl_decoded_option> compiler_opts,
>> +                                   vec<cl_decoded_option> linker_opts)
>>   {
>>     char **names = NULL;
>>     const char *target_names = getenv (OFFLOAD_TARGET_NAMES_ENV);
>> @@ -988,8 +955,7 @@ compile_images_for_offload_targets (unsigned in_argc, char *in_argv[],
>>       {
>>         offload_names[i]
>>          = compile_offload_image (names[i], compiler_path, in_argc, in_argv,
>> -                                compiler_opts, compiler_opt_count,
>> -                                linker_opts, linker_opt_count);
>> +                                compiler_opts, linker_opts);
>>         if (!offload_names[i])
>>          fatal_error (input_location,
>>                       "problem with building target image for %s", names[i]);
>> @@ -1058,25 +1024,22 @@ find_crtoffloadtable (int save_temps, const char *dumppfx)
>>   }
>>
>>   /* A subroutine of run_gcc.  Examine the open file FD for lto sections with
>> -   name prefix PREFIX, at FILE_OFFSET, and store any options we find in OPTS
>> -   and OPT_COUNT.  Return true if we found a matching section, false
>> +   name prefix PREFIX, at FILE_OFFSET, and store any options we find in OPTS.
>> +   Return true if we found a matching section, false
>>      otherwise.  COLLECT_GCC holds the value of the environment variable with
>>      the same name.  */
>>
>>   static bool
>>   find_and_merge_options (int fd, off_t file_offset, const char *prefix,
>> -                       struct cl_decoded_option *decoded_cl_options,
>> -                       unsigned int decoded_cl_options_count,
>> -                       struct cl_decoded_option **opts,
>> -                       unsigned int *opt_count, const char *collect_gcc)
>> +                       vec<cl_decoded_option> decoded_cl_options,
>> +                       vec<cl_decoded_option> *opts, const char *collect_gcc)
>>   {
>>     off_t offset, length;
>>     char *data;
>>     char *fopts;
>>     const char *errmsg;
>>     int err;
>> -  struct cl_decoded_option *fdecoded_options = *opts;
>> -  unsigned int fdecoded_options_count = *opt_count;
>> +  vec<cl_decoded_option> fdecoded_options;
>>
>>     simple_object_read *sobj;
>>     sobj = simple_object_start_read (fd, file_offset, "__GNU_LTO",
>> @@ -1098,24 +1061,19 @@ find_and_merge_options (int fd, off_t file_offset, const char *prefix,
>>     data = (char *)xmalloc (length);
>>     read (fd, data, length);
>>     fopts = data;
>> +  bool first = true;
>>     do
>>       {
>> -      struct cl_decoded_option *f2decoded_options;
>> -      unsigned int f2decoded_options_count;
>> -      get_options_from_collect_gcc_options (collect_gcc, fopts,
>> -                                           &f2decoded_options,
>> -                                           &f2decoded_options_count);
>> -      if (!fdecoded_options)
>> -       {
>> -        fdecoded_options = f2decoded_options;
>> -        fdecoded_options_count = f2decoded_options_count;
>> -       }
>> +      vec<cl_decoded_option> f2decoded_options
>> +       = get_options_from_collect_gcc_options (collect_gcc, fopts);
>> +      if (first)
>> +       {
>> +         fdecoded_options = f2decoded_options;
>> +         first = false;
>> +       }
>>         else
>> -       merge_and_complain (&fdecoded_options,
>> -                           &fdecoded_options_count,
>> -                           f2decoded_options, f2decoded_options_count,
>> -                           decoded_cl_options,
>> -                           decoded_cl_options_count);
>> +       merge_and_complain (fdecoded_options, f2decoded_options,
>> +                           decoded_cl_options);
>>
>>         fopts += strlen (fopts) + 1;
>>       }
>> @@ -1124,7 +1082,6 @@ find_and_merge_options (int fd, off_t file_offset, const char *prefix,
>>     free (data);
>>     simple_object_release_read (sobj);
>>     *opts = fdecoded_options;
>> -  *opt_count = fdecoded_options_count;
>>     return true;
>>   }
>>
>> @@ -1371,12 +1328,9 @@ run_gcc (unsigned argc, char *argv[])
>>     int jobserver = 0;
>>     int auto_parallel = 0;
>>     bool no_partition = false;
>> -  struct cl_decoded_option *fdecoded_options = NULL;
>> -  struct cl_decoded_option *offload_fdecoded_options = NULL;
>> -  unsigned int fdecoded_options_count = 0;
>> -  unsigned int offload_fdecoded_options_count = 0;
>> -  struct cl_decoded_option *decoded_options;
>> -  unsigned int decoded_options_count;
>> +  vec<cl_decoded_option> fdecoded_options;
>> +  fdecoded_options.create (16);
>> +  vec<cl_decoded_option> offload_fdecoded_options = vNULL;
>>     struct obstack argv_obstack;
>>     int new_head_argc;
>>     bool have_lto = false;
>> @@ -1418,9 +1372,8 @@ run_gcc (unsigned argc, char *argv[])
>>                                      NULL);
>>       }
>>
>> -  get_options_from_collect_gcc_options (collect_gcc, collect_gcc_options,
>> -                                       &decoded_options,
>> -                                       &decoded_options_count);
>> +  vec<cl_decoded_option> decoded_options
>> +    = get_options_from_collect_gcc_options (collect_gcc, collect_gcc_options);
>>
>>     /* Allocate array for input object files with LTO IL,
>>        and for possible preceding arguments.  */
>> @@ -1470,8 +1423,7 @@ run_gcc (unsigned argc, char *argv[])
>>          }
>>
>>         if (find_and_merge_options (fd, file_offset, LTO_SECTION_NAME_PREFIX,
>> -                                 decoded_options, decoded_options_count,
>> -                                 &fdecoded_options, &fdecoded_options_count,
>> +                                 decoded_options, &fdecoded_options,
>>                                    collect_gcc))
>>          {
>>            have_lto = true;
>> @@ -1486,14 +1438,13 @@ run_gcc (unsigned argc, char *argv[])
>>     obstack_ptr_grow (&argv_obstack, "-xlto");
>>     obstack_ptr_grow (&argv_obstack, "-c");
>>
>> -  append_compiler_options (&argv_obstack, fdecoded_options,
>> -                          fdecoded_options_count);
>> -  append_linker_options (&argv_obstack, decoded_options, decoded_options_count);
>> +  append_compiler_options (&argv_obstack, fdecoded_options);
>> +  append_linker_options (&argv_obstack, decoded_options);
>>
>>     /* Scan linker driver arguments for things that are of relevance to us.  */
>> -  for (j = 1; j < decoded_options_count; ++j)
>> +  for (j = 1; j < decoded_options.length (); ++j)
>>       {
>> -      struct cl_decoded_option *option = &decoded_options[j];
>> +      cl_decoded_option *option = &decoded_options[j];
>>         switch (option->opt_index)
>>          {
>>          case OPT_o:
>> @@ -1711,9 +1662,7 @@ cont1:
>>              fatal_error (input_location, "cannot open %s: %m", filename);
>>            if (!find_and_merge_options (fd, file_offset,
>>                                         OFFLOAD_SECTION_NAME_PREFIX,
>> -                                      decoded_options, decoded_options_count,
>> -                                      &offload_fdecoded_options,
>> -                                      &offload_fdecoded_options_count,
>> +                                      decoded_options, &offload_fdecoded_options,
>>                                         collect_gcc))
>>              fatal_error (input_location, "cannot read %s: %m", filename);
>>            close (fd);
>> @@ -1722,10 +1671,7 @@ cont1:
>>          }
>>
>>         compile_images_for_offload_targets (num_offload_files, offload_argv,
>> -                                         offload_fdecoded_options,
>> -                                         offload_fdecoded_options_count,
>> -                                         decoded_options,
>> -                                         decoded_options_count);
>> +                                         offload_fdecoded_options, decoded_options);
>>
>>         free_array_of_ptrs ((void **) offload_argv, num_offload_files);
>>
>> --
>> 2.31.1
>>
>
Richard Biener May 12, 2021, 9:15 a.m. UTC | #4
On Wed, May 12, 2021 at 11:08 AM Martin Liška <mliska@suse.cz> wrote:
>
> On 4/29/21 2:22 PM, Richard Biener wrote:
> > On Wed, Apr 21, 2021 at 11:12 AM Martin Liška <mliska@suse.cz> wrote:
> >>
> >> Now living in the 21st century, we don't longer need using the following tuple:
> >> cl_decoded_option **decoded_options,
> >>   unsigned int *decoded_options_count)
> >> but we can rather use a standard (our) vector.
> >>
> >> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> >>
> >> Ready to be installed?
> >> Thanks,
> >> Martin
> >>
> >> gcc/ChangeLog:
> >>
> >>          * lto-wrapper.c (get_options_from_collect_gcc_options): Change
> >>          return type.
> >>          (append_option): Remove.
> >>          (find_option): Rework to use the vector type.
> >>          (remove_option): Remove.
> >>          (merge_and_complain): Use vectors for cl_decoded_option data
> >>          type arguments.
> >>          (append_compiler_options): Likewise.
> >>          (append_diag_options): Likewise.
> >>          (append_linker_options): Likewise.
> >>          (append_offload_options): Likewise.
> >>          (compile_offload_image): Likewise.
> >>          (compile_images_for_offload_targets): Likewise.
> >>          (find_and_merge_options): Likewise.
> >>          (run_gcc): Likewise.
> >> ---
> >>   gcc/lto-wrapper.c | 384 ++++++++++++++++++++--------------------------
> >>   1 file changed, 165 insertions(+), 219 deletions(-)
> >>
> >> diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
> >> index 03a5922f8ea..5ccf729b249 100644
> >> --- a/gcc/lto-wrapper.c
> >> +++ b/gcc/lto-wrapper.c
> >> @@ -138,12 +138,12 @@ maybe_unlink (const char *file)
> >>   /* Create decoded options from the COLLECT_GCC and COLLECT_GCC_OPTIONS
> >>      environment.  */
> >>
> >> -static void
> >> +static vec<cl_decoded_option>
> >
> > bonus points for handling ownership transfer via returning an
> > auto_vec<> (not sure if possible, but maybe it is).
>
> Heh, about the bonus points: changing return type of get_options_from_collect_gcc_options to auto_vec<...>
> leads to:
>
> ==26737== Invalid read of size 4
>
> ==26737==    at 0x406969: length (vec.h:589)
>
> ==26737==    by 0x406969: length (vec.h:1439)
>
> ==26737==    by 0x406969: append_compiler_options(obstack*, vec<cl_decoded_option, va_heap, vl_ptr>) (lto-wrapper.c:649)
>
> ==26737==    by 0x408E35: run_gcc(unsigned int, char**) (lto-wrapper.c:1470)
>
> ==26737==    by 0x406565: main (lto-wrapper.c:2070)
>
> ==26737==  Address 0x57838a4 is 4 bytes inside a block of size 1,152 free'd
>
> ==26737==    at 0x483FEC0: free (vg_replace_malloc.c:755)
>
> ==26737==    by 0x4078B5: release<cl_decoded_option> (vec.h:316)
>
> ==26737==    by 0x4078B5: release (vec.h:1832)
>
> ==26737==    by 0x4078B5: ~auto_vec (vec.h:1552)
>
> ==26737==    by 0x4078B5: find_and_merge_options(int, long, char const*, vec<cl_decoded_option, va_heap, vl_ptr>, vec<cl_decoded_option, va_heap, vl_ptr>*, char const*) (lto-wrapper.c:1100)
>
> ==26737==    by 0x408D0E: run_gcc(unsigned int, char**) (lto-wrapper.c:1454)
>
> ==26737==    by 0x406565: main (lto-wrapper.c:2070)
>
> ==26737==  Block was alloc'd at
>
> ==26737==    at 0x483D70F: malloc (vg_replace_malloc.c:380)
>
> ==26737==    by 0x49554F: xrealloc (xmalloc.c:177)
>
> ==26737==    by 0x4076CC: reserve<cl_decoded_option> (vec.h:290)
>
> ==26737==    by 0x4076CC: reserve (vec.h:1778)
>
> ==26737==    by 0x4076CC: reserve_exact (vec.h:1798)
>
> ==26737==    by 0x4076CC: create (vec.h:1813)
>
> ==26737==    by 0x4076CC: get_options_from_collect_gcc_options(char const*, char const*) (lto-wrapper.c:162)
>
> ==26737==    by 0x4078FC: find_and_merge_options(int, long, char const*, vec<cl_decoded_option, va_heap, vl_ptr>, vec<cl_decoded_option, va_heap, vl_ptr>*, char const*) (lto-wrapper.c:1100)
>
> ==26737==    by 0x408D0E: run_gcc(unsigned int, char**) (lto-wrapper.c:1454)
>
> ==26737==    by 0x406565: main (lto-wrapper.c:2070)

Well, you of course have to be more "careful" then where to
free/forward it.  The auto_vec
serves as a smart pointer then.

OK.

Thanks
Richard.

>
> >
> >>   get_options_from_collect_gcc_options (const char *collect_gcc,
> >> -                                     const char *collect_gcc_options,
> >> -                                     struct cl_decoded_option **decoded_options,
> >> -                                     unsigned int *decoded_options_count)
> >> +                                     const char *collect_gcc_options)
> >>   {
> >> +  cl_decoded_option *decoded_options;
> >> +  unsigned int decoded_options_count;
> >>     struct obstack argv_obstack;
> >>     const char **argv;
> >>     int argc;
> >> @@ -156,57 +156,49 @@ get_options_from_collect_gcc_options (const char *collect_gcc,
> >>     argv = XOBFINISH (&argv_obstack, const char **);
> >>
> >>     decode_cmdline_options_to_array (argc, (const char **)argv, CL_DRIVER,
> >> -                                  decoded_options, decoded_options_count);
> >> +                                  &decoded_options, &decoded_options_count);
> >> +  vec<cl_decoded_option> decoded;
> >> +  decoded.create (decoded_options_count);
> >> +  for (unsigned i = 0; i < decoded_options_count; ++i)
> >> +    decoded.quick_push (decoded_options[i]);
> >> +  free (decoded_options);
> >> +
> >>     obstack_free (&argv_obstack, NULL);
> >> +
> >> +  return decoded;
> >>   }
> >>
> >> -/* Append OPTION to the options array DECODED_OPTIONS with size
> >> -   DECODED_OPTIONS_COUNT.  */
> >> +/* Find option in OPTIONS based on OPT_INDEX.  NULL value is returned
> >> +   if the option is not present.  */
> >>
> >> -static void
> >> -append_option (struct cl_decoded_option **decoded_options,
> >> -              unsigned int *decoded_options_count,
> >> -              struct cl_decoded_option *option)
> >> +static cl_decoded_option *
> >> +find_option (vec<cl_decoded_option> &options, size_t opt_index)
> >>   {
> >> -  ++*decoded_options_count;
> >> -  *decoded_options
> >> -    = (struct cl_decoded_option *)
> >> -       xrealloc (*decoded_options,
> >> -                 (*decoded_options_count
> >> -                  * sizeof (struct cl_decoded_option)));
> >> -  memcpy (&(*decoded_options)[*decoded_options_count - 1], option,
> >> -         sizeof (struct cl_decoded_option));
> >> -}
> >> +  for (unsigned i = 0; i < options.length (); ++i)
> >> +    if (options[i].opt_index == opt_index)
> >> +      return &options[i];
> >
> > You're returning a pointer into the vector here...
> >
> >> -/* Remove option number INDEX from DECODED_OPTIONS, update
> >> -   DECODED_OPTIONS_COUNT.  */
> >> +  return NULL;
> >> +}
> >>
> >> -static void
> >> -remove_option (struct cl_decoded_option **decoded_options,
> >> -              int index, unsigned int *decoded_options_count)
> >> +static cl_decoded_option *
> >> +find_option (vec<cl_decoded_option> &options, cl_decoded_option *option)
> >>   {
> >> -  --*decoded_options_count;
> >> -  memmove (&(*decoded_options)[index + 1],
> >> -          &(*decoded_options)[index],
> >> -          sizeof (struct cl_decoded_option)
> >> -          * (*decoded_options_count - index));
> >> +  return find_option (options, option->opt_index);
> >>   }
> >>
> >>   /* Try to merge and complain about options FDECODED_OPTIONS when applied
> >>      ontop of DECODED_OPTIONS.  */
> >>
> >>   static void
> >> -merge_and_complain (struct cl_decoded_option **decoded_options,
> >> -                   unsigned int *decoded_options_count,
> >> -                   struct cl_decoded_option *fdecoded_options,
> >> -                   unsigned int fdecoded_options_count,
> >> -                   struct cl_decoded_option *decoded_cl_options,
> >> -                   unsigned int decoded_cl_options_count)
> >> +merge_and_complain (vec<cl_decoded_option> decoded_options,
> >> +                   vec<cl_decoded_option> fdecoded_options,
> >> +                   vec<cl_decoded_option> decoded_cl_options)
> >>   {
> >>     unsigned int i, j;
> >> -  struct cl_decoded_option *pic_option = NULL;
> >> -  struct cl_decoded_option *pie_option = NULL;
> >> -  struct cl_decoded_option *cf_protection_option = NULL;
> >> +  cl_decoded_option *pic_option = NULL;
> >> +  cl_decoded_option *pie_option = NULL;
> >> +  cl_decoded_option *cf_protection_option = NULL;
> >>
> >>     /* ???  Merge options from files.  Most cases can be
> >>        handled by either unioning or intersecting
> >> @@ -223,9 +215,9 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
> >>
> >>     /* Look for a -fcf-protection option in the link-time options
> >>        which overrides any -fcf-protection from the lto sections.  */
> >> -  for (i = 0; i < decoded_cl_options_count; ++i)
> >> +  for (i = 0; i < decoded_cl_options.length (); ++i)
> >>       {
> >> -      struct cl_decoded_option *foption = &decoded_cl_options[i];
> >> +      cl_decoded_option *foption = &decoded_cl_options[i];
> >>         if (foption->opt_index == OPT_fcf_protection_)
> >>          {
> >>            cf_protection_option = foption;
> >> @@ -234,9 +226,10 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
> >>
> >>     /* The following does what the old LTO option code did,
> >>        union all target and a selected set of common options.  */
> >> -  for (i = 0; i < fdecoded_options_count; ++i)
> >> +  for (i = 0; i < fdecoded_options.length (); ++i)
> >>       {
> >> -      struct cl_decoded_option *foption = &fdecoded_options[i];
> >> +      cl_decoded_option *foption = &fdecoded_options[i];
> >> +      cl_decoded_option *existing_opt = find_option (decoded_options, foption);
> >>         switch (foption->opt_index)
> >>          {
> >>          case OPT_SPECIAL_unknown:
> >> @@ -264,11 +257,8 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
> >>               setting per OPT code, we pick the first we encounter.
> >>               ???  This doesn't make too much sense, but when it doesn't
> >>               then we should complain.  */
> >> -         for (j = 0; j < *decoded_options_count; ++j)
> >> -           if ((*decoded_options)[j].opt_index == foption->opt_index)
> >> -             break;
> >> -         if (j == *decoded_options_count)
> >> -           append_option (decoded_options, decoded_options_count, foption);
> >> +         if (existing_opt == NULL)
> >> +           decoded_options.safe_push (*foption);
> >
> > and you end up re-allocating that here.  That's an eventually dangerous
> > pattern ... please consider to instead returning an index from find()
> > (and -1 for not found or so).
>
> You are right. I've done that in the patch and it survives regression tests.
> May I install it? The auto_vec can be done incrementally I guess.
>
> Martin
>
> >
> >>            break;
> >>
> >>          /* Figure out what PIC/PIE level wins and merge the results.  */
> >> @@ -284,25 +274,19 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
> >>          case OPT_fopenmp:
> >>          case OPT_fopenacc:
> >>            /* For selected options we can merge conservatively.  */
> >> -         for (j = 0; j < *decoded_options_count; ++j)
> >> -           if ((*decoded_options)[j].opt_index == foption->opt_index)
> >> -             break;
> >> -         if (j == *decoded_options_count)
> >> -           append_option (decoded_options, decoded_options_count, foption);
> >> +         if (existing_opt == NULL)
> >> +           decoded_options.safe_push (*foption);
> >>            /* -fopenmp > -fno-openmp,
> >>               -fopenacc > -fno-openacc  */
> >> -         else if (foption->value > (*decoded_options)[j].value)
> >> -           (*decoded_options)[j] = *foption;
> >> +         else if (foption->value > existing_opt->value)
> >> +           *existing_opt = *foption;
> >>            break;
> >>
> >>          case OPT_fopenacc_dim_:
> >>            /* Append or check identical.  */
> >> -         for (j = 0; j < *decoded_options_count; ++j)
> >> -           if ((*decoded_options)[j].opt_index == foption->opt_index)
> >> -             break;
> >> -         if (j == *decoded_options_count)
> >> -           append_option (decoded_options, decoded_options_count, foption);
> >> -         else if (strcmp ((*decoded_options)[j].arg, foption->arg))
> >> +         if (existing_opt == NULL)
> >> +           decoded_options.safe_push (*foption);
> >> +         else if (strcmp (existing_opt->arg, foption->arg))
> >>              fatal_error (input_location,
> >>                           "option %s with different values",
> >>                           foption->orig_option_with_args_text);
> >> @@ -313,12 +297,9 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
> >>            if (!cf_protection_option
> >>                || cf_protection_option->value == CF_CHECK)
> >>              {
> >> -             for (j = 0; j < *decoded_options_count; ++j)
> >> -               if ((*decoded_options)[j].opt_index == foption->opt_index)
> >> -                 break;
> >> -             if (j == *decoded_options_count)
> >> -               append_option (decoded_options, decoded_options_count, foption);
> >> -             else if ((*decoded_options)[j].value != foption->value)
> >> +             if (existing_opt == NULL)
> >> +               decoded_options.safe_push (*foption);
> >> +             else if (existing_opt->value != foption->value)
> >>                  {
> >>                    if (cf_protection_option
> >>                        && cf_protection_option->value == CF_CHECK)
> >> @@ -326,22 +307,21 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
> >>                                   "option %qs with mismatching values"
> >>                                   " (%s, %s)",
> >>                                   "-fcf-protection",
> >> -                                (*decoded_options)[j].arg, foption->arg);
> >> +                                existing_opt->arg, foption->arg);
> >>                    else
> >>                      {
> >>                        /* Merge and update the -fcf-protection option.  */
> >> -                     (*decoded_options)[j].value &= (foption->value
> >> -                                                     & CF_FULL);
> >> -                     switch ((*decoded_options)[j].value)
> >> +                     existing_opt->value &= (foption->value & CF_FULL);
> >> +                     switch (existing_opt->value)
> >>                          {
> >>                          case CF_NONE:
> >> -                         (*decoded_options)[j].arg = "none";
> >> +                         existing_opt->arg = "none";
> >>                            break;
> >>                          case CF_BRANCH:
> >> -                         (*decoded_options)[j].arg = "branch";
> >> +                         existing_opt->arg = "branch";
> >>                            break;
> >>                          case CF_RETURN:
> >> -                         (*decoded_options)[j].arg = "return";
> >> +                         existing_opt->arg = "return";
> >>                            break;
> >>                          default:
> >>                            gcc_unreachable ();
> >> @@ -355,15 +335,19 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
> >>          case OPT_Ofast:
> >>          case OPT_Og:
> >>          case OPT_Os:
> >> -         for (j = 0; j < *decoded_options_count; ++j)
> >> -           if ((*decoded_options)[j].opt_index == OPT_O
> >> -               || (*decoded_options)[j].opt_index == OPT_Ofast
> >> -               || (*decoded_options)[j].opt_index == OPT_Og
> >> -               || (*decoded_options)[j].opt_index == OPT_Os)
> >> -             break;
> >> -         if (j == *decoded_options_count)
> >> -           append_option (decoded_options, decoded_options_count, foption);
> >> -         else if ((*decoded_options)[j].opt_index == foption->opt_index
> >> +         existing_opt = NULL;
> >> +         for (j = 0; j < decoded_options.length (); ++j)
> >> +           if (decoded_options[j].opt_index == OPT_O
> >> +               || decoded_options[j].opt_index == OPT_Ofast
> >> +               || decoded_options[j].opt_index == OPT_Og
> >> +               || decoded_options[j].opt_index == OPT_Os)
> >> +             {
> >> +               existing_opt = &decoded_options[j];
> >> +               break;
> >> +             }
> >> +         if (existing_opt == NULL)
> >> +           decoded_options.safe_push (*foption);
> >> +         else if (existing_opt->opt_index == foption->opt_index
> >>                     && foption->opt_index != OPT_O)
> >>              /* Exact same options get merged.  */
> >>              ;
> >> @@ -393,13 +377,13 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
> >>                  default:
> >>                    gcc_unreachable ();
> >>                  }
> >> -             switch ((*decoded_options)[j].opt_index)
> >> +             switch (existing_opt->opt_index)
> >>                  {
> >>                  case OPT_O:
> >> -                 if ((*decoded_options)[j].arg[0] == '\0')
> >> +                 if (existing_opt->arg[0] == '\0')
> >>                      level = MAX (level, 1);
> >>                    else
> >> -                   level = MAX (level, atoi ((*decoded_options)[j].arg));
> >> +                   level = MAX (level, atoi (existing_opt->arg));
> >>                    break;
> >>                  case OPT_Ofast:
> >>                    level = MAX (level, 3);
> >> @@ -413,23 +397,20 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
> >>                  default:
> >>                    gcc_unreachable ();
> >>                  }
> >> -             (*decoded_options)[j].opt_index = OPT_O;
> >> +             existing_opt->opt_index = OPT_O;
> >>                char *tem;
> >>                tem = xasprintf ("-O%d", level);
> >> -             (*decoded_options)[j].arg = &tem[2];
> >> -             (*decoded_options)[j].canonical_option[0] = tem;
> >> -             (*decoded_options)[j].value = 1;
> >> +             existing_opt->arg = &tem[2];
> >> +             existing_opt->canonical_option[0] = tem;
> >> +             existing_opt->value = 1;
> >>              }
> >>            break;
> >>
> >>
> >>          case OPT_foffload_abi_:
> >> -         for (j = 0; j < *decoded_options_count; ++j)
> >> -           if ((*decoded_options)[j].opt_index == foption->opt_index)
> >> -             break;
> >> -         if (j == *decoded_options_count)
> >> -           append_option (decoded_options, decoded_options_count, foption);
> >> -         else if (foption->value != (*decoded_options)[j].value)
> >> +         if (existing_opt == NULL)
> >> +           decoded_options.safe_push (*foption);
> >> +         else if (foption->value != existing_opt->value)
> >>              fatal_error (input_location,
> >>                           "option %s not used consistently in all LTO input"
> >>                           " files", foption->orig_option_with_args_text);
> >> @@ -437,7 +418,7 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
> >>
> >>
> >>          case OPT_foffload_:
> >> -         append_option (decoded_options, decoded_options_count, foption);
> >> +         decoded_options.safe_push (*foption);
> >>            break;
> >>          }
> >>       }
> >> @@ -457,12 +438,12 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
> >>        It would be good to warn on mismatches, but it is bit hard to do as
> >>        we do not know what nothing translates to.  */
> >>
> >> -  for (unsigned int j = 0; j < *decoded_options_count;)
> >> -    if ((*decoded_options)[j].opt_index == OPT_fPIC
> >> -        || (*decoded_options)[j].opt_index == OPT_fpic)
> >> +  for (unsigned int j = 0; j < decoded_options.length ();)
> >> +    if (decoded_options[j].opt_index == OPT_fPIC
> >> +       || decoded_options[j].opt_index == OPT_fpic)
> >>         {
> >>          /* -fno-pic in one unit implies -fno-pic everywhere.  */
> >> -       if ((*decoded_options)[j].value == 0)
> >> +       if (decoded_options[j].value == 0)
> >>            j++;
> >>          /* If we have no pic option or merge in -fno-pic, we still may turn
> >>             existing pic/PIC mode into pie/PIE if -fpie/-fPIE is present.  */
> >> @@ -471,41 +452,41 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
> >>            {
> >>              if (pie_option)
> >>                {
> >> -               bool big = (*decoded_options)[j].opt_index == OPT_fPIC
> >> +               bool big = decoded_options[j].opt_index == OPT_fPIC
> >>                             && pie_option->opt_index == OPT_fPIE;
> >> -               (*decoded_options)[j].opt_index = big ? OPT_fPIE : OPT_fpie;
> >> +               decoded_options[j].opt_index = big ? OPT_fPIE : OPT_fpie;
> >>                  if (pie_option->value)
> >> -                 (*decoded_options)[j].canonical_option[0]
> >> +                 decoded_options[j].canonical_option[0]
> >>                      = big ? "-fPIE" : "-fpie";
> >>                  else
> >> -                 (*decoded_options)[j].canonical_option[0] = "-fno-pie";
> >> -               (*decoded_options)[j].value = pie_option->value;
> >> -               j++;
> >> +                 decoded_options[j].canonical_option[0] = "-fno-pie";
> >> +               decoded_options[j].value = pie_option->value;
> >> +               j++;
> >>                }
> >>              else if (pic_option)
> >>                {
> >> -               (*decoded_options)[j] = *pic_option;
> >> -               j++;
> >> +               decoded_options[j] = *pic_option;
> >> +               j++;
> >>                }
> >>              /* We do not know if target defaults to pic or not, so just remove
> >>                 option if it is missing in one unit but enabled in other.  */
> >>              else
> >> -             remove_option (decoded_options, j, decoded_options_count);
> >> +             decoded_options.ordered_remove (j);
> >>            }
> >>          else if (pic_option->opt_index == OPT_fpic
> >> -                && (*decoded_options)[j].opt_index == OPT_fPIC)
> >> +                && decoded_options[j].opt_index == OPT_fPIC)
> >>            {
> >> -           (*decoded_options)[j] = *pic_option;
> >> +           decoded_options[j] = *pic_option;
> >>              j++;
> >>            }
> >>          else
> >>            j++;
> >>         }
> >> -   else if ((*decoded_options)[j].opt_index == OPT_fPIE
> >> -            || (*decoded_options)[j].opt_index == OPT_fpie)
> >> +   else if (decoded_options[j].opt_index == OPT_fPIE
> >> +           || decoded_options[j].opt_index == OPT_fpie)
> >>         {
> >>          /* -fno-pie in one unit implies -fno-pie everywhere.  */
> >> -       if ((*decoded_options)[j].value == 0)
> >> +       if (decoded_options[j].value == 0)
> >>            j++;
> >>          /* If we have no pie option or merge in -fno-pie, we still preserve
> >>             PIE/pie if pic/PIC is present.  */
> >> @@ -516,32 +497,32 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
> >>              if (pic_option)
> >>                {
> >>                  if (pic_option->opt_index == OPT_fpic
> >> -                   && (*decoded_options)[j].opt_index == OPT_fPIE)
> >> +                   && decoded_options[j].opt_index == OPT_fPIE)
> >>                    {
> >> -                   (*decoded_options)[j].opt_index = OPT_fpie;
> >> -                   (*decoded_options)[j].canonical_option[0]
> >> +                   decoded_options[j].opt_index = OPT_fpie;
> >> +                   decoded_options[j].canonical_option[0]
> >>                        = pic_option->value ? "-fpie" : "-fno-pie";
> >>                    }
> >>                  else if (!pic_option->value)
> >> -                 (*decoded_options)[j].canonical_option[0] = "-fno-pie";
> >> -               (*decoded_options)[j].value = pic_option->value;
> >> +                 decoded_options[j].canonical_option[0] = "-fno-pie";
> >> +               decoded_options[j].value = pic_option->value;
> >>                  j++;
> >>                }
> >>              else if (pie_option)
> >>                {
> >> -               (*decoded_options)[j] = *pie_option;
> >> +               decoded_options[j] = *pie_option;
> >>                  j++;
> >>                }
> >>              /* Because we always append pic/PIE options this code path should
> >>                 not happen unless the LTO object was built by old lto1 which
> >>                 did not contain that logic yet.  */
> >>              else
> >> -             remove_option (decoded_options, j, decoded_options_count);
> >> +             decoded_options.ordered_remove (j);
> >>            }
> >>          else if (pie_option->opt_index == OPT_fpie
> >> -                && (*decoded_options)[j].opt_index == OPT_fPIE)
> >> +                && decoded_options[j].opt_index == OPT_fPIE)
> >>            {
> >> -           (*decoded_options)[j] = *pie_option;
> >> +           decoded_options[j] = *pie_option;
> >>              j++;
> >>            }
> >>          else
> >> @@ -553,37 +534,34 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
> >>     if (!xassembler_options_error)
> >>       for (i = j = 0; ; i++, j++)
> >>         {
> >> -       for (; i < *decoded_options_count; i++)
> >> -         if ((*decoded_options)[i].opt_index == OPT_Xassembler)
> >> -           break;
> >> -
> >> -       for (; j < fdecoded_options_count; j++)
> >> -         if (fdecoded_options[j].opt_index == OPT_Xassembler)
> >> -           break;
> >> +       cl_decoded_option *existing_opt
> >> +         = find_option (decoded_options, OPT_Xassembler);
> >> +       cl_decoded_option *existing_opt2
> >> +         = find_option (fdecoded_options, OPT_Xassembler);
> >>
> >> -       if (i == *decoded_options_count && j == fdecoded_options_count)
> >> +       if (existing_opt == NULL && existing_opt2 == NULL)
> >>            break;
> >> -       else if (i < *decoded_options_count && j == fdecoded_options_count)
> >> +       else if (existing_opt != NULL && existing_opt2 == NULL)
> >>            {
> >>              warning (0, "Extra option to %<-Xassembler%>: %s,"
> >>                       " dropping all %<-Xassembler%> and %<-Wa%> options.",
> >> -                    (*decoded_options)[i].arg);
> >> +                    existing_opt->arg);
> >>              xassembler_options_error = true;
> >>              break;
> >>            }
> >> -       else if (i == *decoded_options_count && j < fdecoded_options_count)
> >> +       else if (existing_opt == NULL && existing_opt2 != NULL)
> >>            {
> >>              warning (0, "Extra option to %<-Xassembler%>: %s,"
> >>                       " dropping all %<-Xassembler%> and %<-Wa%> options.",
> >> -                    fdecoded_options[j].arg);
> >> +                    existing_opt2->arg);
> >>              xassembler_options_error = true;
> >>              break;
> >>            }
> >> -       else if (strcmp ((*decoded_options)[i].arg, fdecoded_options[j].arg))
> >> +       else if (strcmp (existing_opt->arg, existing_opt2->arg) != 0)
> >>            {
> >>              warning (0, "Options to %<-Xassembler%> do not match: %s, %s,"
> >>                       " dropping all %<-Xassembler%> and %<-Wa%> options.",
> >> -                    (*decoded_options)[i].arg, fdecoded_options[j].arg);
> >> +                    existing_opt->arg, existing_opt2->arg);
> >>              xassembler_options_error = true;
> >>              break;
> >>            }
> >> @@ -654,13 +632,12 @@ parse_env_var (const char *str, char ***pvalues, const char *append)
> >>   /* Append options OPTS from lto or offload_lto sections to ARGV_OBSTACK.  */
> >>
> >>   static void
> >> -append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts,
> >> -                        unsigned int count)
> >> +append_compiler_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
> >>   {
> >>     /* Append compiler driver arguments as far as they were merged.  */
> >> -  for (unsigned int j = 1; j < count; ++j)
> >> +  for (unsigned int j = 1; j < opts.length (); ++j)
> >>       {
> >> -      struct cl_decoded_option *option = &opts[j];
> >> +      cl_decoded_option *option = &opts[j];
> >>
> >>         /* File options have been properly filtered by lto-opts.c.  */
> >>         switch (option->opt_index)
> >> @@ -721,16 +698,15 @@ append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts,
> >>       }
> >>   }
> >>
> >> -/* Append diag options in OPTS with length COUNT to ARGV_OBSTACK.  */
> >> +/* Append diag options in OPTS to ARGV_OBSTACK.  */
> >>
> >>   static void
> >> -append_diag_options (obstack *argv_obstack, struct cl_decoded_option *opts,
> >> -                    unsigned int count)
> >> +append_diag_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
> >>   {
> >>     /* Append compiler driver arguments as far as they were merged.  */
> >> -  for (unsigned int j = 1; j < count; ++j)
> >> +  for (unsigned int j = 1; j < opts.length (); ++j)
> >>       {
> >> -      struct cl_decoded_option *option = &opts[j];
> >> +      cl_decoded_option *option = &opts[j];
> >>
> >>         switch (option->opt_index)
> >>          {
> >> @@ -757,14 +733,13 @@ append_diag_options (obstack *argv_obstack, struct cl_decoded_option *opts,
> >>   /* Append linker options OPTS to ARGV_OBSTACK.  */
> >>
> >>   static void
> >> -append_linker_options (obstack *argv_obstack, struct cl_decoded_option *opts,
> >> -                      unsigned int count)
> >> +append_linker_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
> >>   {
> >>     /* Append linker driver arguments.  Compiler options from the linker
> >>        driver arguments will override / merge with those from the compiler.  */
> >> -  for (unsigned int j = 1; j < count; ++j)
> >> +  for (unsigned int j = 1; j < opts.length (); ++j)
> >>       {
> >> -      struct cl_decoded_option *option = &opts[j];
> >> +      cl_decoded_option *option = &opts[j];
> >>
> >>         /* Do not pass on frontend specific flags not suitable for lto.  */
> >>         if (!(cl_options[option->opt_index].flags
> >> @@ -802,15 +777,14 @@ append_linker_options (obstack *argv_obstack, struct cl_decoded_option *opts,
> >>
> >>   static void
> >>   append_offload_options (obstack *argv_obstack, const char *target,
> >> -                       struct cl_decoded_option *options,
> >> -                       unsigned int options_count)
> >> +                       vec<cl_decoded_option> options)
> >>   {
> >> -  for (unsigned i = 0; i < options_count; i++)
> >> +  for (unsigned i = 0; i < options.length (); i++)
> >>       {
> >>         const char *cur, *next, *opts;
> >>         char **argv;
> >>         unsigned argc;
> >> -      struct cl_decoded_option *option = &options[i];
> >> +      cl_decoded_option *option = &options[i];
> >>
> >>         if (option->opt_index != OPT_foffload_)
> >>          continue;
> >> @@ -882,10 +856,8 @@ access_check (const char *name, int mode)
> >>   static char *
> >>   compile_offload_image (const char *target, const char *compiler_path,
> >>                         unsigned in_argc, char *in_argv[],
> >> -                      struct cl_decoded_option *compiler_opts,
> >> -                      unsigned int compiler_opt_count,
> >> -                      struct cl_decoded_option *linker_opts,
> >> -                      unsigned int linker_opt_count)
> >> +                      vec<cl_decoded_option> compiler_opts,
> >> +                      vec<cl_decoded_option> linker_opts)
> >>   {
> >>     char *filename = NULL;
> >>     char *dumpbase;
> >> @@ -935,19 +907,16 @@ compile_offload_image (const char *target, const char *compiler_path,
> >>       obstack_ptr_grow (&argv_obstack, in_argv[i]);
> >>
> >>     /* Append options from offload_lto sections.  */
> >> -  append_compiler_options (&argv_obstack, compiler_opts,
> >> -                          compiler_opt_count);
> >> -  append_diag_options (&argv_obstack, linker_opts, linker_opt_count);
> >> +  append_compiler_options (&argv_obstack, compiler_opts);
> >> +  append_diag_options (&argv_obstack, linker_opts);
> >>
> >>     obstack_ptr_grow (&argv_obstack, "-dumpbase");
> >>     obstack_ptr_grow (&argv_obstack, dumpbase);
> >>
> >>     /* Append options specified by -foffload last.  In case of conflicting
> >>        options we expect offload compiler to choose the latest.  */
> >> -  append_offload_options (&argv_obstack, target, compiler_opts,
> >> -                         compiler_opt_count);
> >> -  append_offload_options (&argv_obstack, target, linker_opts,
> >> -                         linker_opt_count);
> >> +  append_offload_options (&argv_obstack, target, compiler_opts);
> >> +  append_offload_options (&argv_obstack, target, linker_opts);
> >>
> >>     obstack_ptr_grow (&argv_obstack, NULL);
> >>     argv = XOBFINISH (&argv_obstack, char **);
> >> @@ -966,10 +935,8 @@ compile_offload_image (const char *target, const char *compiler_path,
> >>
> >>   static void
> >>   compile_images_for_offload_targets (unsigned in_argc, char *in_argv[],
> >> -                                   struct cl_decoded_option *compiler_opts,
> >> -                                   unsigned int compiler_opt_count,
> >> -                                   struct cl_decoded_option *linker_opts,
> >> -                                   unsigned int linker_opt_count)
> >> +                                   vec<cl_decoded_option> compiler_opts,
> >> +                                   vec<cl_decoded_option> linker_opts)
> >>   {
> >>     char **names = NULL;
> >>     const char *target_names = getenv (OFFLOAD_TARGET_NAMES_ENV);
> >> @@ -988,8 +955,7 @@ compile_images_for_offload_targets (unsigned in_argc, char *in_argv[],
> >>       {
> >>         offload_names[i]
> >>          = compile_offload_image (names[i], compiler_path, in_argc, in_argv,
> >> -                                compiler_opts, compiler_opt_count,
> >> -                                linker_opts, linker_opt_count);
> >> +                                compiler_opts, linker_opts);
> >>         if (!offload_names[i])
> >>          fatal_error (input_location,
> >>                       "problem with building target image for %s", names[i]);
> >> @@ -1058,25 +1024,22 @@ find_crtoffloadtable (int save_temps, const char *dumppfx)
> >>   }
> >>
> >>   /* A subroutine of run_gcc.  Examine the open file FD for lto sections with
> >> -   name prefix PREFIX, at FILE_OFFSET, and store any options we find in OPTS
> >> -   and OPT_COUNT.  Return true if we found a matching section, false
> >> +   name prefix PREFIX, at FILE_OFFSET, and store any options we find in OPTS.
> >> +   Return true if we found a matching section, false
> >>      otherwise.  COLLECT_GCC holds the value of the environment variable with
> >>      the same name.  */
> >>
> >>   static bool
> >>   find_and_merge_options (int fd, off_t file_offset, const char *prefix,
> >> -                       struct cl_decoded_option *decoded_cl_options,
> >> -                       unsigned int decoded_cl_options_count,
> >> -                       struct cl_decoded_option **opts,
> >> -                       unsigned int *opt_count, const char *collect_gcc)
> >> +                       vec<cl_decoded_option> decoded_cl_options,
> >> +                       vec<cl_decoded_option> *opts, const char *collect_gcc)
> >>   {
> >>     off_t offset, length;
> >>     char *data;
> >>     char *fopts;
> >>     const char *errmsg;
> >>     int err;
> >> -  struct cl_decoded_option *fdecoded_options = *opts;
> >> -  unsigned int fdecoded_options_count = *opt_count;
> >> +  vec<cl_decoded_option> fdecoded_options;
> >>
> >>     simple_object_read *sobj;
> >>     sobj = simple_object_start_read (fd, file_offset, "__GNU_LTO",
> >> @@ -1098,24 +1061,19 @@ find_and_merge_options (int fd, off_t file_offset, const char *prefix,
> >>     data = (char *)xmalloc (length);
> >>     read (fd, data, length);
> >>     fopts = data;
> >> +  bool first = true;
> >>     do
> >>       {
> >> -      struct cl_decoded_option *f2decoded_options;
> >> -      unsigned int f2decoded_options_count;
> >> -      get_options_from_collect_gcc_options (collect_gcc, fopts,
> >> -                                           &f2decoded_options,
> >> -                                           &f2decoded_options_count);
> >> -      if (!fdecoded_options)
> >> -       {
> >> -        fdecoded_options = f2decoded_options;
> >> -        fdecoded_options_count = f2decoded_options_count;
> >> -       }
> >> +      vec<cl_decoded_option> f2decoded_options
> >> +       = get_options_from_collect_gcc_options (collect_gcc, fopts);
> >> +      if (first)
> >> +       {
> >> +         fdecoded_options = f2decoded_options;
> >> +         first = false;
> >> +       }
> >>         else
> >> -       merge_and_complain (&fdecoded_options,
> >> -                           &fdecoded_options_count,
> >> -                           f2decoded_options, f2decoded_options_count,
> >> -                           decoded_cl_options,
> >> -                           decoded_cl_options_count);
> >> +       merge_and_complain (fdecoded_options, f2decoded_options,
> >> +                           decoded_cl_options);
> >>
> >>         fopts += strlen (fopts) + 1;
> >>       }
> >> @@ -1124,7 +1082,6 @@ find_and_merge_options (int fd, off_t file_offset, const char *prefix,
> >>     free (data);
> >>     simple_object_release_read (sobj);
> >>     *opts = fdecoded_options;
> >> -  *opt_count = fdecoded_options_count;
> >>     return true;
> >>   }
> >>
> >> @@ -1371,12 +1328,9 @@ run_gcc (unsigned argc, char *argv[])
> >>     int jobserver = 0;
> >>     int auto_parallel = 0;
> >>     bool no_partition = false;
> >> -  struct cl_decoded_option *fdecoded_options = NULL;
> >> -  struct cl_decoded_option *offload_fdecoded_options = NULL;
> >> -  unsigned int fdecoded_options_count = 0;
> >> -  unsigned int offload_fdecoded_options_count = 0;
> >> -  struct cl_decoded_option *decoded_options;
> >> -  unsigned int decoded_options_count;
> >> +  vec<cl_decoded_option> fdecoded_options;
> >> +  fdecoded_options.create (16);
> >> +  vec<cl_decoded_option> offload_fdecoded_options = vNULL;
> >>     struct obstack argv_obstack;
> >>     int new_head_argc;
> >>     bool have_lto = false;
> >> @@ -1418,9 +1372,8 @@ run_gcc (unsigned argc, char *argv[])
> >>                                      NULL);
> >>       }
> >>
> >> -  get_options_from_collect_gcc_options (collect_gcc, collect_gcc_options,
> >> -                                       &decoded_options,
> >> -                                       &decoded_options_count);
> >> +  vec<cl_decoded_option> decoded_options
> >> +    = get_options_from_collect_gcc_options (collect_gcc, collect_gcc_options);
> >>
> >>     /* Allocate array for input object files with LTO IL,
> >>        and for possible preceding arguments.  */
> >> @@ -1470,8 +1423,7 @@ run_gcc (unsigned argc, char *argv[])
> >>          }
> >>
> >>         if (find_and_merge_options (fd, file_offset, LTO_SECTION_NAME_PREFIX,
> >> -                                 decoded_options, decoded_options_count,
> >> -                                 &fdecoded_options, &fdecoded_options_count,
> >> +                                 decoded_options, &fdecoded_options,
> >>                                    collect_gcc))
> >>          {
> >>            have_lto = true;
> >> @@ -1486,14 +1438,13 @@ run_gcc (unsigned argc, char *argv[])
> >>     obstack_ptr_grow (&argv_obstack, "-xlto");
> >>     obstack_ptr_grow (&argv_obstack, "-c");
> >>
> >> -  append_compiler_options (&argv_obstack, fdecoded_options,
> >> -                          fdecoded_options_count);
> >> -  append_linker_options (&argv_obstack, decoded_options, decoded_options_count);
> >> +  append_compiler_options (&argv_obstack, fdecoded_options);
> >> +  append_linker_options (&argv_obstack, decoded_options);
> >>
> >>     /* Scan linker driver arguments for things that are of relevance to us.  */
> >> -  for (j = 1; j < decoded_options_count; ++j)
> >> +  for (j = 1; j < decoded_options.length (); ++j)
> >>       {
> >> -      struct cl_decoded_option *option = &decoded_options[j];
> >> +      cl_decoded_option *option = &decoded_options[j];
> >>         switch (option->opt_index)
> >>          {
> >>          case OPT_o:
> >> @@ -1711,9 +1662,7 @@ cont1:
> >>              fatal_error (input_location, "cannot open %s: %m", filename);
> >>            if (!find_and_merge_options (fd, file_offset,
> >>                                         OFFLOAD_SECTION_NAME_PREFIX,
> >> -                                      decoded_options, decoded_options_count,
> >> -                                      &offload_fdecoded_options,
> >> -                                      &offload_fdecoded_options_count,
> >> +                                      decoded_options, &offload_fdecoded_options,
> >>                                         collect_gcc))
> >>              fatal_error (input_location, "cannot read %s: %m", filename);
> >>            close (fd);
> >> @@ -1722,10 +1671,7 @@ cont1:
> >>          }
> >>
> >>         compile_images_for_offload_targets (num_offload_files, offload_argv,
> >> -                                         offload_fdecoded_options,
> >> -                                         offload_fdecoded_options_count,
> >> -                                         decoded_options,
> >> -                                         decoded_options_count);
> >> +                                         offload_fdecoded_options, decoded_options);
> >>
> >>         free_array_of_ptrs ((void **) offload_argv, num_offload_files);
> >>
> >> --
> >> 2.31.1
> >>
> >
>
diff mbox series

Patch

diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
index 03a5922f8ea..5ccf729b249 100644
--- a/gcc/lto-wrapper.c
+++ b/gcc/lto-wrapper.c
@@ -138,12 +138,12 @@  maybe_unlink (const char *file)
 /* Create decoded options from the COLLECT_GCC and COLLECT_GCC_OPTIONS
    environment.  */
 
-static void
+static vec<cl_decoded_option>
 get_options_from_collect_gcc_options (const char *collect_gcc,
-				      const char *collect_gcc_options,
-				      struct cl_decoded_option **decoded_options,
-				      unsigned int *decoded_options_count)
+				      const char *collect_gcc_options)
 {
+  cl_decoded_option *decoded_options;
+  unsigned int decoded_options_count;
   struct obstack argv_obstack;
   const char **argv;
   int argc;
@@ -156,57 +156,49 @@  get_options_from_collect_gcc_options (const char *collect_gcc,
   argv = XOBFINISH (&argv_obstack, const char **);
 
   decode_cmdline_options_to_array (argc, (const char **)argv, CL_DRIVER,
-				   decoded_options, decoded_options_count);
+				   &decoded_options, &decoded_options_count);
+  vec<cl_decoded_option> decoded;
+  decoded.create (decoded_options_count);
+  for (unsigned i = 0; i < decoded_options_count; ++i)
+    decoded.quick_push (decoded_options[i]);
+  free (decoded_options);
+
   obstack_free (&argv_obstack, NULL);
+
+  return decoded;
 }
 
-/* Append OPTION to the options array DECODED_OPTIONS with size
-   DECODED_OPTIONS_COUNT.  */
+/* Find option in OPTIONS based on OPT_INDEX.  NULL value is returned
+   if the option is not present.  */
 
-static void
-append_option (struct cl_decoded_option **decoded_options,
-	       unsigned int *decoded_options_count,
-	       struct cl_decoded_option *option)
+static cl_decoded_option *
+find_option (vec<cl_decoded_option> &options, size_t opt_index)
 {
-  ++*decoded_options_count;
-  *decoded_options
-    = (struct cl_decoded_option *)
-	xrealloc (*decoded_options,
-		  (*decoded_options_count
-		   * sizeof (struct cl_decoded_option)));
-  memcpy (&(*decoded_options)[*decoded_options_count - 1], option,
-	  sizeof (struct cl_decoded_option));
-}
+  for (unsigned i = 0; i < options.length (); ++i)
+    if (options[i].opt_index == opt_index)
+      return &options[i];
 
-/* Remove option number INDEX from DECODED_OPTIONS, update
-   DECODED_OPTIONS_COUNT.  */
+  return NULL;
+}
 
-static void
-remove_option (struct cl_decoded_option **decoded_options,
-	       int index, unsigned int *decoded_options_count)
+static cl_decoded_option *
+find_option (vec<cl_decoded_option> &options, cl_decoded_option *option)
 {
-  --*decoded_options_count;
-  memmove (&(*decoded_options)[index + 1],
-	   &(*decoded_options)[index],
-	   sizeof (struct cl_decoded_option)
-	   * (*decoded_options_count - index));
+  return find_option (options, option->opt_index);
 }
 
 /* Try to merge and complain about options FDECODED_OPTIONS when applied
    ontop of DECODED_OPTIONS.  */
 
 static void
-merge_and_complain (struct cl_decoded_option **decoded_options,
-		    unsigned int *decoded_options_count,
-		    struct cl_decoded_option *fdecoded_options,
-		    unsigned int fdecoded_options_count,
-		    struct cl_decoded_option *decoded_cl_options,
-		    unsigned int decoded_cl_options_count)
+merge_and_complain (vec<cl_decoded_option> decoded_options,
+		    vec<cl_decoded_option> fdecoded_options,
+		    vec<cl_decoded_option> decoded_cl_options)
 {
   unsigned int i, j;
-  struct cl_decoded_option *pic_option = NULL;
-  struct cl_decoded_option *pie_option = NULL;
-  struct cl_decoded_option *cf_protection_option = NULL;
+  cl_decoded_option *pic_option = NULL;
+  cl_decoded_option *pie_option = NULL;
+  cl_decoded_option *cf_protection_option = NULL;
 
   /* ???  Merge options from files.  Most cases can be
      handled by either unioning or intersecting
@@ -223,9 +215,9 @@  merge_and_complain (struct cl_decoded_option **decoded_options,
 
   /* Look for a -fcf-protection option in the link-time options
      which overrides any -fcf-protection from the lto sections.  */
-  for (i = 0; i < decoded_cl_options_count; ++i)
+  for (i = 0; i < decoded_cl_options.length (); ++i)
     {
-      struct cl_decoded_option *foption = &decoded_cl_options[i];
+      cl_decoded_option *foption = &decoded_cl_options[i];
       if (foption->opt_index == OPT_fcf_protection_)
 	{
 	  cf_protection_option = foption;
@@ -234,9 +226,10 @@  merge_and_complain (struct cl_decoded_option **decoded_options,
   
   /* The following does what the old LTO option code did,
      union all target and a selected set of common options.  */
-  for (i = 0; i < fdecoded_options_count; ++i)
+  for (i = 0; i < fdecoded_options.length (); ++i)
     {
-      struct cl_decoded_option *foption = &fdecoded_options[i];
+      cl_decoded_option *foption = &fdecoded_options[i];
+      cl_decoded_option *existing_opt = find_option (decoded_options, foption);
       switch (foption->opt_index)
 	{
 	case OPT_SPECIAL_unknown:
@@ -264,11 +257,8 @@  merge_and_complain (struct cl_decoded_option **decoded_options,
 	     setting per OPT code, we pick the first we encounter.
 	     ???  This doesn't make too much sense, but when it doesn't
 	     then we should complain.  */
-	  for (j = 0; j < *decoded_options_count; ++j)
-	    if ((*decoded_options)[j].opt_index == foption->opt_index)
-	      break;
-	  if (j == *decoded_options_count)
-	    append_option (decoded_options, decoded_options_count, foption);
+	  if (existing_opt == NULL)
+	    decoded_options.safe_push (*foption);
 	  break;
 
 	/* Figure out what PIC/PIE level wins and merge the results.  */
@@ -284,25 +274,19 @@  merge_and_complain (struct cl_decoded_option **decoded_options,
 	case OPT_fopenmp:
 	case OPT_fopenacc:
 	  /* For selected options we can merge conservatively.  */
-	  for (j = 0; j < *decoded_options_count; ++j)
-	    if ((*decoded_options)[j].opt_index == foption->opt_index)
-	      break;
-	  if (j == *decoded_options_count)
-	    append_option (decoded_options, decoded_options_count, foption);
+	  if (existing_opt == NULL)
+	    decoded_options.safe_push (*foption);
 	  /* -fopenmp > -fno-openmp,
 	     -fopenacc > -fno-openacc  */
-	  else if (foption->value > (*decoded_options)[j].value)
-	    (*decoded_options)[j] = *foption;
+	  else if (foption->value > existing_opt->value)
+	    *existing_opt = *foption;
 	  break;
 
 	case OPT_fopenacc_dim_:
 	  /* Append or check identical.  */
-	  for (j = 0; j < *decoded_options_count; ++j)
-	    if ((*decoded_options)[j].opt_index == foption->opt_index)
-	      break;
-	  if (j == *decoded_options_count)
-	    append_option (decoded_options, decoded_options_count, foption);
-	  else if (strcmp ((*decoded_options)[j].arg, foption->arg))
+	  if (existing_opt == NULL)
+	    decoded_options.safe_push (*foption);
+	  else if (strcmp (existing_opt->arg, foption->arg))
 	    fatal_error (input_location,
 			 "option %s with different values",
 			 foption->orig_option_with_args_text);
@@ -313,12 +297,9 @@  merge_and_complain (struct cl_decoded_option **decoded_options,
 	  if (!cf_protection_option
 	      || cf_protection_option->value == CF_CHECK)
 	    {
-	      for (j = 0; j < *decoded_options_count; ++j)
-		if ((*decoded_options)[j].opt_index == foption->opt_index)
-		  break;
-	      if (j == *decoded_options_count)
-		append_option (decoded_options, decoded_options_count, foption);
-	      else if ((*decoded_options)[j].value != foption->value)
+	      if (existing_opt == NULL)
+		decoded_options.safe_push (*foption);
+	      else if (existing_opt->value != foption->value)
 		{
 		  if (cf_protection_option
 		      && cf_protection_option->value == CF_CHECK)
@@ -326,22 +307,21 @@  merge_and_complain (struct cl_decoded_option **decoded_options,
 				 "option %qs with mismatching values"
 				 " (%s, %s)",
 				 "-fcf-protection",
-				 (*decoded_options)[j].arg, foption->arg);
+				 existing_opt->arg, foption->arg);
 		  else
 		    {
 		      /* Merge and update the -fcf-protection option.  */
-		      (*decoded_options)[j].value &= (foption->value
-						      & CF_FULL);
-		      switch ((*decoded_options)[j].value)
+		      existing_opt->value &= (foption->value & CF_FULL);
+		      switch (existing_opt->value)
 			{
 			case CF_NONE:
-			  (*decoded_options)[j].arg = "none";
+			  existing_opt->arg = "none";
 			  break;
 			case CF_BRANCH:
-			  (*decoded_options)[j].arg = "branch";
+			  existing_opt->arg = "branch";
 			  break;
 			case CF_RETURN:
-			  (*decoded_options)[j].arg = "return";
+			  existing_opt->arg = "return";
 			  break;
 			default:
 			  gcc_unreachable ();
@@ -355,15 +335,19 @@  merge_and_complain (struct cl_decoded_option **decoded_options,
 	case OPT_Ofast:
 	case OPT_Og:
 	case OPT_Os:
-	  for (j = 0; j < *decoded_options_count; ++j)
-	    if ((*decoded_options)[j].opt_index == OPT_O
-		|| (*decoded_options)[j].opt_index == OPT_Ofast
-		|| (*decoded_options)[j].opt_index == OPT_Og
-		|| (*decoded_options)[j].opt_index == OPT_Os)
-	      break;
-	  if (j == *decoded_options_count)
-	    append_option (decoded_options, decoded_options_count, foption);
-	  else if ((*decoded_options)[j].opt_index == foption->opt_index
+	  existing_opt = NULL;
+	  for (j = 0; j < decoded_options.length (); ++j)
+	    if (decoded_options[j].opt_index == OPT_O
+		|| decoded_options[j].opt_index == OPT_Ofast
+		|| decoded_options[j].opt_index == OPT_Og
+		|| decoded_options[j].opt_index == OPT_Os)
+	      {
+		existing_opt = &decoded_options[j];
+		break;
+	      }
+	  if (existing_opt == NULL)
+	    decoded_options.safe_push (*foption);
+	  else if (existing_opt->opt_index == foption->opt_index
 		   && foption->opt_index != OPT_O)
 	    /* Exact same options get merged.  */
 	    ;
@@ -393,13 +377,13 @@  merge_and_complain (struct cl_decoded_option **decoded_options,
 		default:
 		  gcc_unreachable ();
 		}
-	      switch ((*decoded_options)[j].opt_index)
+	      switch (existing_opt->opt_index)
 		{
 		case OPT_O:
-		  if ((*decoded_options)[j].arg[0] == '\0')
+		  if (existing_opt->arg[0] == '\0')
 		    level = MAX (level, 1);
 		  else
-		    level = MAX (level, atoi ((*decoded_options)[j].arg));
+		    level = MAX (level, atoi (existing_opt->arg));
 		  break;
 		case OPT_Ofast:
 		  level = MAX (level, 3);
@@ -413,23 +397,20 @@  merge_and_complain (struct cl_decoded_option **decoded_options,
 		default:
 		  gcc_unreachable ();
 		}
-	      (*decoded_options)[j].opt_index = OPT_O;
+	      existing_opt->opt_index = OPT_O;
 	      char *tem;
 	      tem = xasprintf ("-O%d", level);
-	      (*decoded_options)[j].arg = &tem[2];
-	      (*decoded_options)[j].canonical_option[0] = tem;
-	      (*decoded_options)[j].value = 1;
+	      existing_opt->arg = &tem[2];
+	      existing_opt->canonical_option[0] = tem;
+	      existing_opt->value = 1;
 	    }
 	  break;
  
 
 	case OPT_foffload_abi_:
-	  for (j = 0; j < *decoded_options_count; ++j)
-	    if ((*decoded_options)[j].opt_index == foption->opt_index)
-	      break;
-	  if (j == *decoded_options_count)
-	    append_option (decoded_options, decoded_options_count, foption);
-	  else if (foption->value != (*decoded_options)[j].value)
+	  if (existing_opt == NULL)
+	    decoded_options.safe_push (*foption);
+	  else if (foption->value != existing_opt->value)
 	    fatal_error (input_location,
 			 "option %s not used consistently in all LTO input"
 			 " files", foption->orig_option_with_args_text);
@@ -437,7 +418,7 @@  merge_and_complain (struct cl_decoded_option **decoded_options,
 
 
 	case OPT_foffload_:
-	  append_option (decoded_options, decoded_options_count, foption);
+	  decoded_options.safe_push (*foption);
 	  break;
 	}
     }
@@ -457,12 +438,12 @@  merge_and_complain (struct cl_decoded_option **decoded_options,
      It would be good to warn on mismatches, but it is bit hard to do as
      we do not know what nothing translates to.  */
     
-  for (unsigned int j = 0; j < *decoded_options_count;)
-    if ((*decoded_options)[j].opt_index == OPT_fPIC
-        || (*decoded_options)[j].opt_index == OPT_fpic)
+  for (unsigned int j = 0; j < decoded_options.length ();)
+    if (decoded_options[j].opt_index == OPT_fPIC
+	|| decoded_options[j].opt_index == OPT_fpic)
       {
 	/* -fno-pic in one unit implies -fno-pic everywhere.  */
-	if ((*decoded_options)[j].value == 0)
+	if (decoded_options[j].value == 0)
 	  j++;
 	/* If we have no pic option or merge in -fno-pic, we still may turn
 	   existing pic/PIC mode into pie/PIE if -fpie/-fPIE is present.  */
@@ -471,41 +452,41 @@  merge_and_complain (struct cl_decoded_option **decoded_options,
 	  {
 	    if (pie_option)
 	      {
-		bool big = (*decoded_options)[j].opt_index == OPT_fPIC
+		bool big = decoded_options[j].opt_index == OPT_fPIC
 			   && pie_option->opt_index == OPT_fPIE;
-	        (*decoded_options)[j].opt_index = big ? OPT_fPIE : OPT_fpie;
+		decoded_options[j].opt_index = big ? OPT_fPIE : OPT_fpie;
 		if (pie_option->value)
-	          (*decoded_options)[j].canonical_option[0]
+		  decoded_options[j].canonical_option[0]
 		    = big ? "-fPIE" : "-fpie";
 		else
-	          (*decoded_options)[j].canonical_option[0] = "-fno-pie";
-		(*decoded_options)[j].value = pie_option->value;
-	        j++;
+		  decoded_options[j].canonical_option[0] = "-fno-pie";
+		decoded_options[j].value = pie_option->value;
+		j++;
 	      }
 	    else if (pic_option)
 	      {
-	        (*decoded_options)[j] = *pic_option;
-	        j++;
+		decoded_options[j] = *pic_option;
+		j++;
 	      }
 	    /* We do not know if target defaults to pic or not, so just remove
 	       option if it is missing in one unit but enabled in other.  */
 	    else
-	      remove_option (decoded_options, j, decoded_options_count);
+	      decoded_options.ordered_remove (j);
 	  }
 	else if (pic_option->opt_index == OPT_fpic
-		 && (*decoded_options)[j].opt_index == OPT_fPIC)
+		 && decoded_options[j].opt_index == OPT_fPIC)
 	  {
-	    (*decoded_options)[j] = *pic_option;
+	    decoded_options[j] = *pic_option;
 	    j++;
 	  }
 	else
 	  j++;
       }
-   else if ((*decoded_options)[j].opt_index == OPT_fPIE
-            || (*decoded_options)[j].opt_index == OPT_fpie)
+   else if (decoded_options[j].opt_index == OPT_fPIE
+	    || decoded_options[j].opt_index == OPT_fpie)
       {
 	/* -fno-pie in one unit implies -fno-pie everywhere.  */
-	if ((*decoded_options)[j].value == 0)
+	if (decoded_options[j].value == 0)
 	  j++;
 	/* If we have no pie option or merge in -fno-pie, we still preserve
 	   PIE/pie if pic/PIC is present.  */
@@ -516,32 +497,32 @@  merge_and_complain (struct cl_decoded_option **decoded_options,
 	    if (pic_option)
 	      {
 		if (pic_option->opt_index == OPT_fpic
-		    && (*decoded_options)[j].opt_index == OPT_fPIE)
+		    && decoded_options[j].opt_index == OPT_fPIE)
 		  {
-	            (*decoded_options)[j].opt_index = OPT_fpie;
-	            (*decoded_options)[j].canonical_option[0]
+		    decoded_options[j].opt_index = OPT_fpie;
+		    decoded_options[j].canonical_option[0]
 		      = pic_option->value ? "-fpie" : "-fno-pie";
 		  }
 		else if (!pic_option->value)
-		  (*decoded_options)[j].canonical_option[0] = "-fno-pie";
-		(*decoded_options)[j].value = pic_option->value;
+		  decoded_options[j].canonical_option[0] = "-fno-pie";
+		decoded_options[j].value = pic_option->value;
 		j++;
 	      }
 	    else if (pie_option)
 	      {
-	        (*decoded_options)[j] = *pie_option;
+		decoded_options[j] = *pie_option;
 		j++;
 	      }
 	    /* Because we always append pic/PIE options this code path should
 	       not happen unless the LTO object was built by old lto1 which
 	       did not contain that logic yet.  */
 	    else
-	      remove_option (decoded_options, j, decoded_options_count);
+	      decoded_options.ordered_remove (j);
 	  }
 	else if (pie_option->opt_index == OPT_fpie
-		 && (*decoded_options)[j].opt_index == OPT_fPIE)
+		 && decoded_options[j].opt_index == OPT_fPIE)
 	  {
-	    (*decoded_options)[j] = *pie_option;
+	    decoded_options[j] = *pie_option;
 	    j++;
 	  }
 	else
@@ -553,37 +534,34 @@  merge_and_complain (struct cl_decoded_option **decoded_options,
   if (!xassembler_options_error)
     for (i = j = 0; ; i++, j++)
       {
-	for (; i < *decoded_options_count; i++)
-	  if ((*decoded_options)[i].opt_index == OPT_Xassembler)
-	    break;
-
-	for (; j < fdecoded_options_count; j++)
-	  if (fdecoded_options[j].opt_index == OPT_Xassembler)
-	    break;
+	cl_decoded_option *existing_opt
+	  = find_option (decoded_options, OPT_Xassembler);
+	cl_decoded_option *existing_opt2
+	  = find_option (fdecoded_options, OPT_Xassembler);
 
-	if (i == *decoded_options_count && j == fdecoded_options_count)
+	if (existing_opt == NULL && existing_opt2 == NULL)
 	  break;
-	else if (i < *decoded_options_count && j == fdecoded_options_count)
+	else if (existing_opt != NULL && existing_opt2 == NULL)
 	  {
 	    warning (0, "Extra option to %<-Xassembler%>: %s,"
 		     " dropping all %<-Xassembler%> and %<-Wa%> options.",
-		     (*decoded_options)[i].arg);
+		     existing_opt->arg);
 	    xassembler_options_error = true;
 	    break;
 	  }
-	else if (i == *decoded_options_count && j < fdecoded_options_count)
+	else if (existing_opt == NULL && existing_opt2 != NULL)
 	  {
 	    warning (0, "Extra option to %<-Xassembler%>: %s,"
 		     " dropping all %<-Xassembler%> and %<-Wa%> options.",
-		     fdecoded_options[j].arg);
+		     existing_opt2->arg);
 	    xassembler_options_error = true;
 	    break;
 	  }
-	else if (strcmp ((*decoded_options)[i].arg, fdecoded_options[j].arg))
+	else if (strcmp (existing_opt->arg, existing_opt2->arg) != 0)
 	  {
 	    warning (0, "Options to %<-Xassembler%> do not match: %s, %s,"
 		     " dropping all %<-Xassembler%> and %<-Wa%> options.",
-		     (*decoded_options)[i].arg, fdecoded_options[j].arg);
+		     existing_opt->arg, existing_opt2->arg);
 	    xassembler_options_error = true;
 	    break;
 	  }
@@ -654,13 +632,12 @@  parse_env_var (const char *str, char ***pvalues, const char *append)
 /* Append options OPTS from lto or offload_lto sections to ARGV_OBSTACK.  */
 
 static void
-append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts,
-			 unsigned int count)
+append_compiler_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
 {
   /* Append compiler driver arguments as far as they were merged.  */
-  for (unsigned int j = 1; j < count; ++j)
+  for (unsigned int j = 1; j < opts.length (); ++j)
     {
-      struct cl_decoded_option *option = &opts[j];
+      cl_decoded_option *option = &opts[j];
 
       /* File options have been properly filtered by lto-opts.c.  */
       switch (option->opt_index)
@@ -721,16 +698,15 @@  append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts,
     }
 }
 
-/* Append diag options in OPTS with length COUNT to ARGV_OBSTACK.  */
+/* Append diag options in OPTS to ARGV_OBSTACK.  */
 
 static void
-append_diag_options (obstack *argv_obstack, struct cl_decoded_option *opts,
-		     unsigned int count)
+append_diag_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
 {
   /* Append compiler driver arguments as far as they were merged.  */
-  for (unsigned int j = 1; j < count; ++j)
+  for (unsigned int j = 1; j < opts.length (); ++j)
     {
-      struct cl_decoded_option *option = &opts[j];
+      cl_decoded_option *option = &opts[j];
 
       switch (option->opt_index)
 	{
@@ -757,14 +733,13 @@  append_diag_options (obstack *argv_obstack, struct cl_decoded_option *opts,
 /* Append linker options OPTS to ARGV_OBSTACK.  */
 
 static void
-append_linker_options (obstack *argv_obstack, struct cl_decoded_option *opts,
-		       unsigned int count)
+append_linker_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
 {
   /* Append linker driver arguments.  Compiler options from the linker
      driver arguments will override / merge with those from the compiler.  */
-  for (unsigned int j = 1; j < count; ++j)
+  for (unsigned int j = 1; j < opts.length (); ++j)
     {
-      struct cl_decoded_option *option = &opts[j];
+      cl_decoded_option *option = &opts[j];
 
       /* Do not pass on frontend specific flags not suitable for lto.  */
       if (!(cl_options[option->opt_index].flags
@@ -802,15 +777,14 @@  append_linker_options (obstack *argv_obstack, struct cl_decoded_option *opts,
 
 static void
 append_offload_options (obstack *argv_obstack, const char *target,
-			struct cl_decoded_option *options,
-			unsigned int options_count)
+			vec<cl_decoded_option> options)
 {
-  for (unsigned i = 0; i < options_count; i++)
+  for (unsigned i = 0; i < options.length (); i++)
     {
       const char *cur, *next, *opts;
       char **argv;
       unsigned argc;
-      struct cl_decoded_option *option = &options[i];
+      cl_decoded_option *option = &options[i];
 
       if (option->opt_index != OPT_foffload_)
 	continue;
@@ -882,10 +856,8 @@  access_check (const char *name, int mode)
 static char *
 compile_offload_image (const char *target, const char *compiler_path,
 		       unsigned in_argc, char *in_argv[],
-		       struct cl_decoded_option *compiler_opts,
-		       unsigned int compiler_opt_count,
-		       struct cl_decoded_option *linker_opts,
-		       unsigned int linker_opt_count)
+		       vec<cl_decoded_option> compiler_opts,
+		       vec<cl_decoded_option> linker_opts)
 {
   char *filename = NULL;
   char *dumpbase;
@@ -935,19 +907,16 @@  compile_offload_image (const char *target, const char *compiler_path,
     obstack_ptr_grow (&argv_obstack, in_argv[i]);
 
   /* Append options from offload_lto sections.  */
-  append_compiler_options (&argv_obstack, compiler_opts,
-			   compiler_opt_count);
-  append_diag_options (&argv_obstack, linker_opts, linker_opt_count);
+  append_compiler_options (&argv_obstack, compiler_opts);
+  append_diag_options (&argv_obstack, linker_opts);
 
   obstack_ptr_grow (&argv_obstack, "-dumpbase");
   obstack_ptr_grow (&argv_obstack, dumpbase);
 
   /* Append options specified by -foffload last.  In case of conflicting
      options we expect offload compiler to choose the latest.  */
-  append_offload_options (&argv_obstack, target, compiler_opts,
-			  compiler_opt_count);
-  append_offload_options (&argv_obstack, target, linker_opts,
-			  linker_opt_count);
+  append_offload_options (&argv_obstack, target, compiler_opts);
+  append_offload_options (&argv_obstack, target, linker_opts);
 
   obstack_ptr_grow (&argv_obstack, NULL);
   argv = XOBFINISH (&argv_obstack, char **);
@@ -966,10 +935,8 @@  compile_offload_image (const char *target, const char *compiler_path,
 
 static void
 compile_images_for_offload_targets (unsigned in_argc, char *in_argv[],
-				    struct cl_decoded_option *compiler_opts,
-				    unsigned int compiler_opt_count,
-				    struct cl_decoded_option *linker_opts,
-				    unsigned int linker_opt_count)
+				    vec<cl_decoded_option> compiler_opts,
+				    vec<cl_decoded_option> linker_opts)
 {
   char **names = NULL;
   const char *target_names = getenv (OFFLOAD_TARGET_NAMES_ENV);
@@ -988,8 +955,7 @@  compile_images_for_offload_targets (unsigned in_argc, char *in_argv[],
     {
       offload_names[i]
 	= compile_offload_image (names[i], compiler_path, in_argc, in_argv,
-				 compiler_opts, compiler_opt_count,
-				 linker_opts, linker_opt_count);
+				 compiler_opts, linker_opts);
       if (!offload_names[i])
 	fatal_error (input_location,
 		     "problem with building target image for %s", names[i]);
@@ -1058,25 +1024,22 @@  find_crtoffloadtable (int save_temps, const char *dumppfx)
 }
 
 /* A subroutine of run_gcc.  Examine the open file FD for lto sections with
-   name prefix PREFIX, at FILE_OFFSET, and store any options we find in OPTS
-   and OPT_COUNT.  Return true if we found a matching section, false
+   name prefix PREFIX, at FILE_OFFSET, and store any options we find in OPTS.
+   Return true if we found a matching section, false
    otherwise.  COLLECT_GCC holds the value of the environment variable with
    the same name.  */
 
 static bool
 find_and_merge_options (int fd, off_t file_offset, const char *prefix,
-			struct cl_decoded_option *decoded_cl_options,
-			unsigned int decoded_cl_options_count,
-			struct cl_decoded_option **opts,
-			unsigned int *opt_count, const char *collect_gcc)
+			vec<cl_decoded_option> decoded_cl_options,
+			vec<cl_decoded_option> *opts, const char *collect_gcc)
 {
   off_t offset, length;
   char *data;
   char *fopts;
   const char *errmsg;
   int err;
-  struct cl_decoded_option *fdecoded_options = *opts;
-  unsigned int fdecoded_options_count = *opt_count;
+  vec<cl_decoded_option> fdecoded_options;
 
   simple_object_read *sobj;
   sobj = simple_object_start_read (fd, file_offset, "__GNU_LTO",
@@ -1098,24 +1061,19 @@  find_and_merge_options (int fd, off_t file_offset, const char *prefix,
   data = (char *)xmalloc (length);
   read (fd, data, length);
   fopts = data;
+  bool first = true;
   do
     {
-      struct cl_decoded_option *f2decoded_options;
-      unsigned int f2decoded_options_count;
-      get_options_from_collect_gcc_options (collect_gcc, fopts,
-					    &f2decoded_options,
-					    &f2decoded_options_count);
-      if (!fdecoded_options)
-       {
-	 fdecoded_options = f2decoded_options;
-	 fdecoded_options_count = f2decoded_options_count;
-       }
+      vec<cl_decoded_option> f2decoded_options
+	= get_options_from_collect_gcc_options (collect_gcc, fopts);
+      if (first)
+	{
+	  fdecoded_options = f2decoded_options;
+	  first = false;
+	}
       else
-	merge_and_complain (&fdecoded_options,
-			    &fdecoded_options_count,
-			    f2decoded_options, f2decoded_options_count,
-			    decoded_cl_options,
-			    decoded_cl_options_count);
+	merge_and_complain (fdecoded_options, f2decoded_options,
+			    decoded_cl_options);
 
       fopts += strlen (fopts) + 1;
     }
@@ -1124,7 +1082,6 @@  find_and_merge_options (int fd, off_t file_offset, const char *prefix,
   free (data);
   simple_object_release_read (sobj);
   *opts = fdecoded_options;
-  *opt_count = fdecoded_options_count;
   return true;
 }
 
@@ -1371,12 +1328,9 @@  run_gcc (unsigned argc, char *argv[])
   int jobserver = 0;
   int auto_parallel = 0;
   bool no_partition = false;
-  struct cl_decoded_option *fdecoded_options = NULL;
-  struct cl_decoded_option *offload_fdecoded_options = NULL;
-  unsigned int fdecoded_options_count = 0;
-  unsigned int offload_fdecoded_options_count = 0;
-  struct cl_decoded_option *decoded_options;
-  unsigned int decoded_options_count;
+  vec<cl_decoded_option> fdecoded_options;
+  fdecoded_options.create (16);
+  vec<cl_decoded_option> offload_fdecoded_options = vNULL;
   struct obstack argv_obstack;
   int new_head_argc;
   bool have_lto = false;
@@ -1418,9 +1372,8 @@  run_gcc (unsigned argc, char *argv[])
 				    NULL);
     }
 
-  get_options_from_collect_gcc_options (collect_gcc, collect_gcc_options,
-					&decoded_options,
-					&decoded_options_count);
+  vec<cl_decoded_option> decoded_options
+    = get_options_from_collect_gcc_options (collect_gcc, collect_gcc_options);
 
   /* Allocate array for input object files with LTO IL,
      and for possible preceding arguments.  */
@@ -1470,8 +1423,7 @@  run_gcc (unsigned argc, char *argv[])
 	}
 
       if (find_and_merge_options (fd, file_offset, LTO_SECTION_NAME_PREFIX,
-				  decoded_options, decoded_options_count,
-				  &fdecoded_options, &fdecoded_options_count,
+				  decoded_options, &fdecoded_options,
 				  collect_gcc))
 	{
 	  have_lto = true;
@@ -1486,14 +1438,13 @@  run_gcc (unsigned argc, char *argv[])
   obstack_ptr_grow (&argv_obstack, "-xlto");
   obstack_ptr_grow (&argv_obstack, "-c");
 
-  append_compiler_options (&argv_obstack, fdecoded_options,
-			   fdecoded_options_count);
-  append_linker_options (&argv_obstack, decoded_options, decoded_options_count);
+  append_compiler_options (&argv_obstack, fdecoded_options);
+  append_linker_options (&argv_obstack, decoded_options);
 
   /* Scan linker driver arguments for things that are of relevance to us.  */
-  for (j = 1; j < decoded_options_count; ++j)
+  for (j = 1; j < decoded_options.length (); ++j)
     {
-      struct cl_decoded_option *option = &decoded_options[j];
+      cl_decoded_option *option = &decoded_options[j];
       switch (option->opt_index)
 	{
 	case OPT_o:
@@ -1711,9 +1662,7 @@  cont1:
 	    fatal_error (input_location, "cannot open %s: %m", filename);
 	  if (!find_and_merge_options (fd, file_offset,
 				       OFFLOAD_SECTION_NAME_PREFIX,
-				       decoded_options, decoded_options_count,
-				       &offload_fdecoded_options,
-				       &offload_fdecoded_options_count,
+				       decoded_options, &offload_fdecoded_options,
 				       collect_gcc))
 	    fatal_error (input_location, "cannot read %s: %m", filename);
 	  close (fd);
@@ -1722,10 +1671,7 @@  cont1:
 	}
 
       compile_images_for_offload_targets (num_offload_files, offload_argv,
-					  offload_fdecoded_options,
-					  offload_fdecoded_options_count,
-					  decoded_options,
-					  decoded_options_count);
+					  offload_fdecoded_options, decoded_options);
 
       free_array_of_ptrs ((void **) offload_argv, num_offload_files);