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.
Related show

Commit Message

Martin Liška April 21, 2021, 8:12 a.m.
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(-)

-- 
2.31.1

Comments

Martin Sebor via Gcc-patches April 29, 2021, 12:22 p.m. | #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 via Gcc-patches April 29, 2021, 3:19 p.m. | #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. | #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

>>

>
From 6bfa86b423fd8017a80fd12e609dfee15b0befbe Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>

Date: Fri, 12 Mar 2021 11:53:47 +0100
Subject: [PATCH] lto-wrapper: Use vec<cl_decoded_option> data type.

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 | 396 +++++++++++++++++++++-------------------------
 1 file changed, 176 insertions(+), 220 deletions(-)

diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
index d6be7f016bf..11d4d20c494 100644
--- a/gcc/lto-wrapper.c
+++ b/gcc/lto-wrapper.c
@@ -139,12 +139,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;
@@ -157,57 +157,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.  -1 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 int
+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 i;
 
-/* Remove option number INDEX from DECODED_OPTIONS, update
-   DECODED_OPTIONS_COUNT.  */
+  return -1;
+}
 
-static void
-remove_option (struct cl_decoded_option **decoded_options,
-	       int index, unsigned int *decoded_options_count)
+static int
+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
@@ -224,9 +216,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;
@@ -235,9 +227,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];
+      int existing_opt = find_option (decoded_options, foption);
       switch (foption->opt_index)
 	{
 	case OPT_SPECIAL_unknown:
@@ -265,11 +258,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 == -1)
+	    decoded_options.safe_push (*foption);
 	  break;
 
 	/* Figure out what PIC/PIE level wins and merge the results.  */
@@ -285,25 +275,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 == -1)
+	    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 > decoded_options[existing_opt].value)
+	    decoded_options[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 == -1)
+	    decoded_options.safe_push (*foption);
+	  else if (strcmp (decoded_options[existing_opt].arg, foption->arg))
 	    fatal_error (input_location,
 			 "option %s with different values",
 			 foption->orig_option_with_args_text);
@@ -314,12 +298,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 == -1)
+		decoded_options.safe_push (*foption);
+	      else if (decoded_options[existing_opt].value != foption->value)
 		{
 		  if (cf_protection_option
 		      && cf_protection_option->value == CF_CHECK)
@@ -327,22 +308,23 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
 				 "option %qs with mismatching values"
 				 " (%s, %s)",
 				 "-fcf-protection",
-				 (*decoded_options)[j].arg, foption->arg);
+				 decoded_options[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)
+		      decoded_options[existing_opt].value
+			&= (foption->value & CF_FULL);
+		      switch (decoded_options[existing_opt].value)
 			{
 			case CF_NONE:
-			  (*decoded_options)[j].arg = "none";
+			  decoded_options[existing_opt].arg = "none";
 			  break;
 			case CF_BRANCH:
-			  (*decoded_options)[j].arg = "branch";
+			  decoded_options[existing_opt].arg = "branch";
 			  break;
 			case CF_RETURN:
-			  (*decoded_options)[j].arg = "return";
+			  decoded_options[existing_opt].arg = "return";
 			  break;
 			default:
 			  gcc_unreachable ();
@@ -356,15 +338,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 = -1;
+	  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 = j;
+		break;
+	      }
+	  if (existing_opt == -1)
+	    decoded_options.safe_push (*foption);
+	  else if (decoded_options[existing_opt].opt_index == foption->opt_index
 		   && foption->opt_index != OPT_O)
 	    /* Exact same options get merged.  */
 	    ;
@@ -394,13 +380,14 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
 		default:
 		  gcc_unreachable ();
 		}
-	      switch ((*decoded_options)[j].opt_index)
+	      switch (decoded_options[existing_opt].opt_index)
 		{
 		case OPT_O:
-		  if ((*decoded_options)[j].arg[0] == '\0')
+		  if (decoded_options[existing_opt].arg[0] == '\0')
 		    level = MAX (level, 1);
 		  else
-		    level = MAX (level, atoi ((*decoded_options)[j].arg));
+		    level = MAX (level,
+				 atoi (decoded_options[existing_opt].arg));
 		  break;
 		case OPT_Ofast:
 		  level = MAX (level, 3);
@@ -414,23 +401,20 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
 		default:
 		  gcc_unreachable ();
 		}
-	      (*decoded_options)[j].opt_index = OPT_O;
+	      decoded_options[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;
+	      decoded_options[existing_opt].arg = &tem[2];
+	      decoded_options[existing_opt].canonical_option[0] = tem;
+	      decoded_options[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 == -1)
+	    decoded_options.safe_push (*foption);
+	  else if (foption->value != decoded_options[existing_opt].value)
 	    fatal_error (input_location,
 			 "option %s not used consistently in all LTO input"
 			 " files", foption->orig_option_with_args_text);
@@ -438,7 +422,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;
 	}
     }
@@ -458,12 +442,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.  */
@@ -472,41 +456,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.  */
@@ -517,32 +501,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
@@ -554,37 +538,41 @@ 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;
-
-	if (i == *decoded_options_count && j == fdecoded_options_count)
+	int existing_opt_index
+	  = find_option (decoded_options, OPT_Xassembler);
+	int existing_opt2_index
+	  = find_option (fdecoded_options, OPT_Xassembler);
+
+	cl_decoded_option *existing_opt = NULL;
+	cl_decoded_option *existing_opt2 = NULL;
+	if (existing_opt_index != -1)
+	  existing_opt = &decoded_options[existing_opt_index];
+	if (existing_opt2_index != -1)
+	  existing_opt2 = &fdecoded_options[existing_opt2_index];
+
+	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;
 	  }
@@ -655,13 +643,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)
@@ -722,16 +709,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)
 	{
@@ -758,14 +744,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
@@ -803,15 +788,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;
@@ -883,10 +867,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;
@@ -943,19 +925,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 **);
@@ -974,10 +953,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);
@@ -997,8 +974,7 @@ compile_images_for_offload_targets (unsigned in_argc, char *in_argv[],
     {
       offload_names[next_name_entry]
 	= 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[next_name_entry])
 #if OFFLOAD_DEFAULTED
 	continue;
@@ -1080,25 +1056,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",
@@ -1120,24 +1093,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;
     }
@@ -1146,7 +1114,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;
 }
 
@@ -1391,12 +1358,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;
@@ -1438,9 +1402,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.  */
@@ -1489,8 +1452,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;
@@ -1505,14 +1467,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:
@@ -1731,9 +1692,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);
@@ -1742,10 +1701,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 via Gcc-patches May 12, 2021, 9:15 a.m. | #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

> >>

> >

>

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