On Wed, 26 Oct 2011, Richard Guenther wrote:

> 
> This completely rewrites LTO option merging.  At compile (uselessly
> now at WPA?) time we now stream a COLLECT_GCC_OPTIONS like string
> as it comes from argv of the compiler binary.  Those options are
> read in by the LTO driver (lto-wrapper), merged into a single
> set (very simple merge function right now ;)) and given a place to
> complain about incompatible arguments.  The merged set is then
> prepended to the arguments from the linker driver line
> (what we get in COLLECT_GCC_OPTIONS for lto-wrapper), thus the
> linker command-line may override what the compiler command-line(s)
> provided.
> 
> One visible change is that no optimization option on the link line
> no longer means -O0, unless you explicitly specify -O0 at link time.
> 
> There are probably more obscure differences, especially due to the
> very simple merge and complain function ;))  But this is a RFC ...
> 
> If WPA partitioning at any point wants to do something clever with
> a set of incompatible functions it can re-parse the options and
> do that (we then have to arrange for lto-wrapper to let the options
> slip through).
> 
> I'm LTO bootstrapping and testing this simple variant right now
> (I believe we do not excercise funny option combinations right now).
> 
> I'll still implement a very simple merge/complain function.
> Suggestions for that welcome (I'll probably simply compute the
> intersection of options ... in the long run we'd want to annotate
> our options as to whether they should be unioned/intersected).
> 
> Any comments?

Btw, the following is a variant that actually passes LTO bootstrap
without miscompares in the LTO option sections.

Richard.

2011-10-26  Richard Guenther  <rguent...@suse.de>

        * lto-opts.c: Re-implement.
        * lto-streamer.h (lto_register_user_option): Remove.
        (lto_read_file_options): Likewise.
        (lto_reissue_options): Likewise.
        (lto_clear_user_options): Likewise.
        (lto_clear_file_options): Likewise.
        * opts-global.c (post_handling_callback): Remove LTO specific code.
        (decode_options): Likewise.
        * lto-wrapper.c (merge_and_complain): New function.
        (run_gcc): Read all input file options and
        prepend a merged set before the linker driver options.

        lto/
        * lto-lang.c (lto_post_options): Do not read file options.
        * lto.c (lto_read_all_file_options): Remove.
        (lto_init): Call lto_set_in_hooks here.


Index: trunk/gcc/lto-opts.c
===================================================================
*** trunk.orig/gcc/lto-opts.c   2011-10-26 13:46:24.000000000 +0200
--- trunk/gcc/lto-opts.c        2011-10-26 16:26:20.000000000 +0200
***************
*** 1,6 ****
  /* LTO IL options.
  
!    Copyright 2009, 2010, 2011 Free Software Foundation, Inc.
     Contributed by Simon Baldwin <sim...@google.com>
  
  This file is part of GCC.
--- 1,6 ----
  /* LTO IL options.
  
!    Copyright 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
     Contributed by Simon Baldwin <sim...@google.com>
  
  This file is part of GCC.
*************** along with GCC; see the file COPYING3.
*** 33,422 ****
  #include "common/common-target.h"
  #include "diagnostic.h"
  #include "lto-streamer.h"
! 
! /* When a file is initially compiled, the options used when generating
!    the IL are not necessarily the same as those used when linking the
!    objects into the final executable.  In general, most build systems
!    will proceed with something along the lines of:
! 
!       $ gcc <cc-flags> -flto -c f1.c -o f1.o
!       $ gcc <cc-flags> -flto -c f2.c -o f2.o
!       ...
!       $ gcc <cc-flags> -flto -c fN.c -o fN.o
! 
!    And the final link may or may not include the same <cc-flags> used
!    to generate the initial object files:
! 
!       $ gcc <ld-flags> -flto -o prog f1.o ... fN.o
! 
!    Since we will be generating final code during the link step, some
!    of the flags used during the compile step need to be re-applied
!    during the link step.  For instance, flags in the -m family.
! 
!    The idea is to save a selected set of <cc-flags> in a special
!    section of the initial object files.  This section is then read
!    during linking and the options re-applied.
! 
!    FIXME lto.  Currently the scheme is limited in that only the
!    options saved on the first object file (f1.o) are read back during
!    the link step.  This means that the options used to compile f1.o
!    will be applied to ALL the object files in the final link step.
!    More work needs to be done to implement a merging and validation
!    mechanism, as this will not be enough for all cases.  */
! 
! /* Saved options hold the type of the option (currently CL_TARGET or
!    CL_COMMON), and the code, argument, and value.  */
! 
! typedef struct GTY(()) opt_d
! {
!   unsigned int type;
!   size_t code;
!   char *arg;
!   int value;
! } opt_t;
! 
! DEF_VEC_O (opt_t);
! DEF_VEC_ALLOC_O (opt_t, heap);
! 
! 
! /* Options are held in two vectors, one for those registered by
!    command line handling code, and the other for those read in from
!    any LTO IL input.  */
! static VEC(opt_t, heap) *user_options = NULL;
! static VEC(opt_t, heap) *file_options = NULL;
! 
! /* Iterate FROM in reverse, writing option codes not yet in CODES into *TO.
!    Mark each new option code encountered in CODES.  */
! 
! static void
! reverse_iterate_options (VEC(opt_t, heap) *from, VEC(opt_t, heap) **to,
!                        bitmap codes)
! {
!   int i;
! 
!   for (i = VEC_length (opt_t, from); i > 0; i--)
!     {
!       const opt_t *const o = VEC_index (opt_t, from, i - 1);
! 
!       if (bitmap_set_bit (codes, o->code))
!       VEC_safe_push (opt_t, heap, *to, o);
!     }
! }
! 
! /* Concatenate options vectors FIRST and SECOND, rationalize so that only the
!    final of any given option remains, and return the result.  */
! 
! static VEC(opt_t, heap) *
! concatenate_options (VEC(opt_t, heap) *first, VEC(opt_t, heap) *second)
! {
!   VEC(opt_t, heap) *results = NULL;
!   bitmap codes = lto_bitmap_alloc ();
! 
!   reverse_iterate_options (second, &results, codes);
!   reverse_iterate_options (first, &results, codes);
! 
!   lto_bitmap_free (codes);
!   return results;
! }
! 
! /* Clear the options vector in *OPTS_P and set it to NULL.  */
! 
! static void
! clear_options (VEC(opt_t, heap) **opts_p)
! {
!   int i;
!   opt_t *o;
! 
!   FOR_EACH_VEC_ELT (opt_t, *opts_p, i, o)
!     free (o->arg);
! 
!   VEC_free (opt_t, heap, *opts_p);
! }
! 
! /* Write LENGTH bytes from ADDR to STREAM.  */
! 
! static void
! output_data_stream (struct lto_output_stream *stream,
!                     const void *addr, size_t length)
! {
!   lto_output_data_stream (stream, addr, length);
! }
! 
! /* Write string STRING to STREAM.  */
! 
! static void
! output_string_stream (struct lto_output_stream *stream, const char *string)
! {
!   bool flag = false;
! 
!   if (string != NULL)
!     {
!       const size_t length = strlen (string);
! 
!       flag = true;
!       output_data_stream (stream, &flag, sizeof (flag));
!       output_data_stream (stream, &length, sizeof (length));
!       output_data_stream (stream, string, length);
!     }
!   else
!     output_data_stream (stream, &flag, sizeof (flag));
! }
! 
! /* Return a string from IB.  The string is allocated, and the caller is
!    responsible for freeing it.  */
! 
! static char *
! input_string_block (struct lto_input_block *ib)
! {
!   bool flag;
! 
!   lto_input_data_block (ib, &flag, sizeof (flag));
!   if (flag)
!     {
!       size_t length;
!       char *string;
! 
!       lto_input_data_block (ib, &length, sizeof (length));
!       string = (char *) xcalloc (1, length + 1);
!       lto_input_data_block (ib, string, length);
! 
!       return string;
!     }
!   else
!     return NULL;
! }
! 
! /* Return true if this option is one we need to save in LTO output files.
!    At present, we pass along all target options, and common options that
!    involve position independent code.
! 
!    TODO This list of options requires expansion and rationalization.
!    Among others, optimization options may well be appropriate here.  */
! 
! static bool
! register_user_option_p (size_t code, unsigned int type)
! {
!   if (type == CL_TARGET)
!     return true;
!   else if (type == CL_COMMON)
!     {
!       return (code == OPT_fPIC
!             || code == OPT_fpic
!             || code == OPT_fPIE
!             || code == OPT_fpie
!             || code == OPT_fcommon
!             || code == OPT_fexceptions);
!     }
! 
!   return false;
! }
! 
! /* Note command line option with the given TYPE and CODE, ARG, and VALUE.
!    If relevant to LTO, save it in the user options vector.  */
! 
! void
! lto_register_user_option (size_t code, const char *arg, int value,
!                         unsigned int type)
! {
!   if (register_user_option_p (code, type))
!     {
!       opt_t o;
! 
!       o.type = type;
!       o.code = code;
!       if (arg != NULL)
!       {
!         o.arg = (char *) xmalloc (strlen (arg) + 1);
!         strcpy (o.arg, arg);
!       }
!       else
!       o.arg = NULL;
!       o.value = value;
!       VEC_safe_push (opt_t, heap, user_options, &o);
!     }
! }
! 
! /* Empty the saved user options vector.  */
! 
! void
! lto_clear_user_options (void)
! {
!   clear_options (&user_options);
! }
! 
! /* Empty the saved file options vector.  */
! 
! void
! lto_clear_file_options (void)
! {
!   clear_options (&file_options);
! }
! 
! /* Concatenate the user options and any file options read from an LTO IL
!    file, and serialize them to STREAM.  File options precede user options
!    so that the latter override the former when reissued.  */
! 
! static void
! output_options (struct lto_output_stream *stream)
! {
!   VEC(opt_t, heap) *opts = concatenate_options (file_options, user_options);
!   const size_t length = VEC_length (opt_t, opts);
!   int i;
!   opt_t *o;
! 
!   output_data_stream (stream, &length, sizeof (length));
! 
!   FOR_EACH_VEC_ELT (opt_t, opts, i, o)
!     {
!       output_data_stream (stream, &o->type, sizeof (o->type));
!       output_data_stream (stream, &o->code, sizeof (o->code));
!       output_string_stream (stream, o->arg);
!       output_data_stream (stream, &o->value, sizeof (o->value));
!     }
! 
!   VEC_free (opt_t, heap, opts);
! }
  
  /* Write currently held options to an LTO IL section.  */
  
  void
  lto_write_options (void)
  {
-   char *const section_name = lto_get_section_name (LTO_section_opts, NULL, 
NULL);
    struct lto_output_stream stream;
!   struct lto_simple_header header;
!   struct lto_output_stream *header_stream;
! 
!   /* Targets and languages can provide defaults for -fexceptions but
!      we only process user options from the command-line.  Until we
!      serialize out a white list of options from the new global state
!      explicitly append important options as user options here.  */
!   if (flag_exceptions)
!     lto_register_user_option (OPT_fexceptions, NULL, 1, CL_COMMON);
! 
!   lto_begin_section (section_name, !flag_wpa);
!   free (section_name);
  
    memset (&stream, 0, sizeof (stream));
-   output_options (&stream);
- 
-   memset (&header, 0, sizeof (header));
-   header.lto_header.major_version = LTO_major_version;
-   header.lto_header.minor_version = LTO_minor_version;
-   header.lto_header.section_type = LTO_section_opts;
- 
-   header.compressed_size = 0;
-   header.main_size = stream.total_size;
- 
-   header_stream = ((struct lto_output_stream *)
-                  xcalloc (1, sizeof (*header_stream)));
-   lto_output_data_stream (header_stream, &header, sizeof (header));
-   lto_write_stream (header_stream);
-   free (header_stream);
  
!   lto_write_stream (&stream);
!   lto_end_section ();
! }
! 
! /* Unserialize an options vector from IB, and append to file_options.  */
! 
! static void
! input_options (struct lto_input_block *ib)
! {
!   size_t length, i;
! 
!   lto_input_data_block (ib, &length, sizeof (length));
! 
!   for (i = 0; i < length; i++)
      {
!       opt_t o;
! 
!       lto_input_data_block (ib, &o.type, sizeof (o.type));
!       lto_input_data_block (ib, &o.code, sizeof (o.code));
!       o.arg = input_string_block (ib);
!       lto_input_data_block (ib, &o.value, sizeof (o.value));
!       VEC_safe_push (opt_t, heap, file_options, &o);
!     }
! }
! 
! /* Read options from an LTO IL section.  */
! 
! void
! lto_read_file_options (struct lto_file_decl_data *file_data)
! {
!   size_t len, l, skip;
!   const char *data, *p;
!   const struct lto_simple_header *header;
!   int32_t opts_offset;
!   struct lto_input_block ib;
! 
!   data = lto_get_section_data (file_data, LTO_section_opts, NULL, &len);
!   if (!data)
!         return;
! 
!   /* Option could be multiple sections merged (through ld -r) 
!      Keep reading all options.  This is ok right now because
!      the options just get mashed together anyways.
!      This will have to be done differently once lto-opts knows
!      how to associate options with different files. */
!   l = len;
!   p = data;
!   do 
!     { 
!       header = (const struct lto_simple_header *) p;
!       opts_offset = sizeof (*header);
! 
!       lto_check_version (header->lto_header.major_version,
!                        header->lto_header.minor_version);
!       
!       LTO_INIT_INPUT_BLOCK (ib, p + opts_offset, 0, header->main_size);
!       input_options (&ib);
!       
!       skip = header->main_size + opts_offset;
!       l -= skip;
!       p += skip;
!     } 
!   while (l > 0);
! 
!   lto_free_section_data (file_data, LTO_section_opts, 0, data, len);
! }
  
! /* Concatenate the user options and any file options read from an LTO IL
!    file, and reissue them as if all had just been read in from the command
!    line.  As with serialization, file options precede user options.  */
  
! void
! lto_reissue_options (void)
! {
!   VEC(opt_t, heap) *opts = concatenate_options (file_options, user_options);
!   int i;
!   opt_t *o;
  
!   FOR_EACH_VEC_ELT (opt_t, opts, i, o)
!     {
!       void *flag_var = option_flag_var (o->code, &global_options);
  
!       if (flag_var)
!       set_option (&global_options, &global_options_set,
!                   o->code, o->value, o->arg,
!                   DK_UNSPECIFIED, UNKNOWN_LOCATION, global_dc);
  
!       if (o->type == CL_TARGET)
        {
!         struct cl_decoded_option decoded;
!         generate_option (o->code, o->arg, o->value, CL_TARGET, &decoded);
!         targetm_common.handle_option (&global_options, &global_options_set,
!                                       &decoded, UNKNOWN_LOCATION);
        }
-       else if (o->type == CL_COMMON)
-       gcc_assert (flag_var);
-       else
-       gcc_unreachable ();
      }
  
!   /* Flag_shlib is usually set by finish_options, but we are issuing flag_pic
!      too late.  */
!   if (flag_pic && !flag_pie)
!     flag_shlib = 1;
!   VEC_free (opt_t, heap, opts);
  }
--- 33,116 ----
  #include "common/common-target.h"
  #include "diagnostic.h"
  #include "lto-streamer.h"
! #include "toplev.h"
  
  /* Write currently held options to an LTO IL section.  */
  
  void
  lto_write_options (void)
  {
    struct lto_output_stream stream;
!   char *section_name;
!   struct obstack temporary_obstack;
!   unsigned int i, j;
!   char *args;
  
+   section_name = lto_get_section_name (LTO_section_opts, NULL, NULL);
+   lto_begin_section (section_name, false);
    memset (&stream, 0, sizeof (stream));
  
!   obstack_init (&temporary_obstack);
!   for (i = 1; i < save_decoded_options_count; ++i)
      {
!       struct cl_decoded_option *option = &save_decoded_options[i];
!       const char *q, *p;
  
!       /* Skip frontend and driver specific options here.  */
!       if (!(cl_options[option->opt_index].flags & (CL_COMMON|CL_TARGET)))
!       continue;
! 
!       /* Drop arguments created from the gcc driver that will be rejected
!        when passed on.  */
!       if (cl_options[option->opt_index].cl_reject_driver)
!       continue;
  
!       /* Skip explicitly some common options that we do not need.  */
!       switch (option->opt_index)
!       {
!       case OPT_o:
!       case OPT_dumpbase:
!       case OPT_SPECIAL_input_file:
!         continue;
  
!       default:
!         break;
!       }
  
!       if (i != 1)
!       obstack_grow (&temporary_obstack, " ", 1);
!       obstack_grow (&temporary_obstack, "'", 1);
!       q = option->canonical_option[0];
!       while ((p = strchr (q, '\'')))
!       {
!         obstack_grow (&temporary_obstack, q, p - q);
!         obstack_grow (&temporary_obstack, "'\\''", 4);
!         q = ++p;
!       }
!       obstack_grow (&temporary_obstack, q, strlen (q));
!       obstack_grow (&temporary_obstack, "'", 1);
  
!       for (j = 1; j < option->canonical_option_num_elements; ++j)
        {
!         obstack_grow (&temporary_obstack, " '", 2);
!         q = option->canonical_option[j];
!         while ((p = strchr (q, '\'')))
!           {
!             obstack_grow (&temporary_obstack, q, p - q);
!             obstack_grow (&temporary_obstack, "'\\''", 4);
!             q = ++p;
!           }
!         obstack_grow (&temporary_obstack, q, strlen (q));
!         obstack_grow (&temporary_obstack, "'", 1);
        }
      }
+   obstack_grow (&temporary_obstack, "\0", 1);
+   args = XOBFINISH (&temporary_obstack, char *);
+   lto_output_data_stream (&stream, args, strlen (args) + 1);
  
!   lto_write_stream (&stream);
!   lto_end_section ();
! 
!   obstack_free (&temporary_obstack, NULL);
!   free (section_name);
  }
Index: trunk/gcc/lto-streamer.h
===================================================================
*** trunk.orig/gcc/lto-streamer.h       2011-10-26 13:46:24.000000000 +0200
--- trunk/gcc/lto-streamer.h    2011-10-26 14:35:45.000000000 +0200
*************** extern GTY(()) VEC(tree,gc) *lto_global_
*** 882,893 ****
  
  
  /* In lto-opts.c.  */
- extern void lto_register_user_option (size_t, const char *, int, unsigned 
int);
- extern void lto_read_file_options (struct lto_file_decl_data *);
  extern void lto_write_options (void);
- extern void lto_reissue_options (void);
- void lto_clear_user_options (void);
- void lto_clear_file_options (void);
  
  
  /* In lto-wpa-fixup.c  */
--- 882,888 ----
Index: trunk/gcc/lto/lto-lang.c
===================================================================
*** trunk.orig/gcc/lto/lto-lang.c       2011-10-26 13:46:24.000000000 +0200
--- trunk/gcc/lto/lto-lang.c    2011-10-26 13:48:42.000000000 +0200
*************** lto_post_options (const char **pfilename
*** 692,699 ****
       support.  */
    flag_excess_precision_cmdline = EXCESS_PRECISION_FAST;
  
-   lto_read_all_file_options ();
- 
    /* Initialize the compiler back end.  */
    return false;
  }
--- 692,697 ----
Index: trunk/gcc/lto/lto.c
===================================================================
*** trunk.orig/gcc/lto/lto.c    2011-10-26 13:46:24.000000000 +0200
--- trunk/gcc/lto/lto.c 2011-10-26 13:48:42.000000000 +0200
*************** lto_fixup_decls (struct lto_file_decl_da
*** 2494,2553 ****
      }
  }
  
- /* Read the options saved from each file in the command line.  Called
-    from lang_hooks.post_options which is called by process_options
-    right before all the options are used to initialize the compiler.
-    This assumes that decode_options has already run, so the
-    num_in_fnames and in_fnames are properly set.
- 
-    Note that this assumes that all the files had been compiled with
-    the same options, which is not a good assumption.  In general,
-    options ought to be read from all the files in the set and merged.
-    However, it is still unclear what the merge rules should be.  */
- 
- void
- lto_read_all_file_options (void)
- {
-   size_t i;
- 
-   /* Clear any file options currently saved.  */
-   lto_clear_file_options ();
- 
-   /* Set the hooks to read ELF sections.  */
-   lto_set_in_hooks (NULL, get_section_data, free_section_data);
-   if (!quiet_flag)
-     fprintf (stderr, "Reading command line options:");
- 
-   for (i = 0; i < num_in_fnames; i++)
-     {
-       struct lto_file_decl_data *file_data;
-       lto_file *file = lto_obj_file_open (in_fnames[i], false);
-       if (!file)
-       break;
-       if (!quiet_flag)
-       {
-         fprintf (stderr, " %s", in_fnames[i]);
-         fflush (stderr);
-       }
- 
-       file_data = XCNEW (struct lto_file_decl_data);
-       file_data->file_name = file->filename;
-       file_data->section_hash_table = lto_obj_build_section_table (file, 
NULL);
- 
-       lto_read_file_options (file_data);
- 
-       lto_obj_file_close (file);
-       htab_delete (file_data->section_hash_table);
-       free (file_data);
-     }
- 
-   if (!quiet_flag)
-     fprintf (stderr, "\n");
- 
-   /* Apply globally the options read from all the files.  */
-   lto_reissue_options ();
- }
- 
  static GTY((length ("lto_stats.num_input_files + 1"))) struct 
lto_file_decl_data **all_file_decl_data;
  
  /* Turn file datas for sub files into a single array, so that they look
--- 2494,2499 ----
*************** lto_init (void)
*** 2921,2926 ****
--- 2867,2873 ----
    lto_process_name ();
    lto_streamer_hooks_init ();
    lto_reader_init ();
+   lto_set_in_hooks (NULL, get_section_data, free_section_data);
    memset (&lto_stats, 0, sizeof (lto_stats));
    bitmap_obstack_initialize (NULL);
    gimple_register_cfg_hooks ();
Index: trunk/gcc/opts-global.c
===================================================================
*** trunk.orig/gcc/opts-global.c        2011-10-26 13:46:24.000000000 +0200
--- trunk/gcc/opts-global.c     2011-10-26 13:48:42.000000000 +0200
*************** static void
*** 167,176 ****
  post_handling_callback (const struct cl_decoded_option *decoded 
ATTRIBUTE_UNUSED,
                        unsigned int mask ATTRIBUTE_UNUSED)
  {
- #ifdef ENABLE_LTO
-   lto_register_user_option (decoded->opt_index, decoded->arg,
-                           decoded->value, mask);
- #endif
  }
  
  /* Handle a front-end option; arguments and return value as for
--- 167,172 ----
*************** decode_options (struct gcc_options *opts
*** 314,324 ****
                                decoded_options, decoded_options_count,
                                loc, lang_mask, &handlers, dc);
  
- #ifdef ENABLE_LTO
-   /* Clear any options currently held for LTO.  */
-   lto_clear_user_options ();
- #endif
- 
    read_cmdline_options (opts, opts_set,
                        decoded_options, decoded_options_count,
                        loc, lang_mask,
--- 310,315 ----
Index: trunk/gcc/lto-wrapper.c
===================================================================
*** trunk.orig/gcc/lto-wrapper.c        2011-10-26 13:48:17.000000000 +0200
--- trunk/gcc/lto-wrapper.c     2011-10-26 16:43:04.000000000 +0200
*************** along with GCC; see the file COPYING3.
*** 45,50 ****
--- 45,58 ----
  #include "obstack.h"
  #include "opts.h"
  #include "options.h"
+ #include "simple-object.h"
+ 
+ /* From lto-streamer.h which we cannot include with -fkeep-inline-functions.
+    ???  Split out a lto-streamer-core.h.  */
+ 
+ #define LTO_SECTION_NAME_PREFIX         ".gnu.lto_"
+ 
+ /* End of lto-streamer.h copy.  */
  
  int debug;                            /* true if -save-temps.  */
  int verbose;                          /* true if -v.  */
*************** get_options_from_collect_gcc_options (co
*** 327,332 ****
--- 335,383 ----
    free (argv);
  }
  
+ /* 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)
+ {
+   unsigned int i;
+ 
+   /* ???  Merge options from files.  Most cases can be
+      handled by either unioning or intersecting
+      (for example -fwrapv is a case for unioning,
+      -ffast-math is for intersection).  Most complaints
+      about real conflicts between different options can
+      be deferred to the compiler proper.  Options that
+      we can neither safely handle by intersection nor
+      unioning would need to be complained about here.
+      Ideally we'd have a flag in the opt files that
+      tells whether to union or intersect or reject.
+      In absence of that it's unclear what a good default is.
+      It's also difficult to get positional handling correct.  */
+   /* ???  For now the easiest thing would be to warn about
+      mismatches.  */
+ 
+   if (*decoded_options_count != fdecoded_options_count)
+     {
+       /* ???  Warn?  */
+       return;
+     }
+   for (i = 0; i < *decoded_options_count; ++i)
+     {
+       struct cl_decoded_option *option = &(*decoded_options)[i];
+       struct cl_decoded_option *foption = &fdecoded_options[i];
+       if (strcmp (option->orig_option_with_args_text,
+                 foption->orig_option_with_args_text) != 0)
+       {
+         /* ???  Warn?  */
+         return;
+       }
+     }
+ }
  
  /* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. 
*/
  
*************** run_gcc (unsigned argc, char *argv[])
*** 342,347 ****
--- 393,400 ----
    int parallel = 0;
    int jobserver = 0;
    bool no_partition = false;
+   struct cl_decoded_option *fdecoded_options = NULL;
+   unsigned int fdecoded_options_count = 0;
    struct cl_decoded_option *decoded_options;
    unsigned int decoded_options_count;
  
*************** run_gcc (unsigned argc, char *argv[])
*** 357,369 ****
                                        &decoded_options,
                                        &decoded_options_count);
  
    /* Initalize the common arguments for the driver.  */
!   new_argv = (const char **) xmalloc ((15 + decoded_options_count + argc)
                                      * sizeof (char *));
    argv_ptr = new_argv;
    *argv_ptr++ = collect_gcc;
    *argv_ptr++ = "-xlto";
    *argv_ptr++ = "-c";
    for (j = 1; j < decoded_options_count; ++j)
      {
        struct cl_decoded_option *option = &decoded_options[j];
--- 410,529 ----
                                        &decoded_options,
                                        &decoded_options_count);
  
+   /* Look at saved options in the IL files.  */
+   for (i = 1; i < argc; ++i)
+     {
+       char *data, *p;
+       char *fopts;
+       int fd;
+       const char *errmsg;
+       int err;
+       off_t file_offset = 0, offset, length;
+       long loffset;
+       simple_object_read *sobj;
+       int consumed;
+       struct cl_decoded_option *f2decoded_options;
+       unsigned int f2decoded_options_count;
+       char *filename = argv[i];
+       if ((p = strrchr (argv[i], '@'))
+         && p != argv[i] 
+         && sscanf (p, "@%li%n", &loffset, &consumed) >= 1
+         && strlen (p) == (unsigned int) consumed)
+       {
+         filename = XNEWVEC (char, p - argv[i] + 1);
+         memcpy (filename, argv[i], p - argv[i]);
+         filename[p - argv[i]] = '\0';
+         file_offset = (off_t) loffset;
+       }
+       fd = open (argv[i], O_RDONLY);
+       if (fd == -1)
+       continue;
+       sobj = simple_object_start_read (fd, file_offset, NULL, &errmsg, &err);
+       if (!sobj)
+       {
+         close (fd);
+         continue;
+       }
+       if (!simple_object_find_section (sobj, LTO_SECTION_NAME_PREFIX "." 
"opts",
+                                      &offset, &length, &errmsg, &err))
+       {
+         simple_object_release_read (sobj);
+         close (fd);
+         continue;
+       }
+       lseek (fd, file_offset + offset, SEEK_SET);
+       data = (char *)xmalloc (length);
+       read (fd, data, length);
+       fopts = data;
+       do
+       {
+         get_options_from_collect_gcc_options (collect_gcc,
+                                               fopts, CL_LANG_ALL,
+                                               &f2decoded_options,
+                                               &f2decoded_options_count);
+         if (!fdecoded_options)
+           {
+             fdecoded_options = f2decoded_options;
+             fdecoded_options_count = f2decoded_options_count;
+           }
+         else
+           merge_and_complain (&fdecoded_options,
+                               &fdecoded_options_count,
+                               f2decoded_options, f2decoded_options_count);
+ 
+         fopts += strlen (fopts) + 1;
+       }
+       while (fopts - data < length);
+ 
+       free (data);
+       simple_object_release_read (sobj);
+       close (fd);
+     }
+ 
    /* Initalize the common arguments for the driver.  */
!   new_argv = (const char **) xmalloc ((15
!                                      + fdecoded_options_count
!                                      + decoded_options_count + argc)
                                      * sizeof (char *));
    argv_ptr = new_argv;
    *argv_ptr++ = collect_gcc;
    *argv_ptr++ = "-xlto";
    *argv_ptr++ = "-c";
+ 
+   /* Append compiler driver arguments as far as they were merged.  */
+   for (j = 1; j < fdecoded_options_count; ++j)
+     {
+       struct cl_decoded_option *option = &fdecoded_options[j];
+ 
+       /* Do not pass on frontend or driver specific flags.  */
+       if (!(cl_options[option->opt_index].flags & (CL_COMMON|CL_TARGET)))
+       continue;
+ 
+       /* Drop arguments created from the gcc driver that will be rejected
+        when passed on.  */
+       if (cl_options[option->opt_index].cl_reject_driver)
+       continue;
+ 
+       switch (option->opt_index)
+       {
+       /* Drop arguments that we want to take from the link line.  */
+       case OPT_flto_:
+       case OPT_flto:
+       case OPT_flto_partition_none:
+       case OPT_flto_partition_1to1:
+       case OPT_flto_partition_balanced:
+         continue;
+ 
+       default:
+         break;
+       }
+ 
+       /* Pass the option on.  */
+       *argv_ptr++ = option->orig_option_with_args_text;
+     }
+ 
+   /* Append linker driver arguments.  Compiler options from the linker
+      driver arguments will override / merge with those from the compiler.  */
    for (j = 1; j < decoded_options_count; ++j)
      {
        struct cl_decoded_option *option = &decoded_options[j];

Reply via email to