Patchwork Deferring command-line options

login
register
mail settings
Submitter Joseph S. Myers
Date Nov. 17, 2010, 9:18 a.m.
Message ID <Pine.LNX.4.64.1011170917350.27921@digraph.polyomino.org.uk>
Download mbox | patch
Permalink /patch/71532/
State New
Headers show

Comments

Joseph S. Myers - Nov. 17, 2010, 9:18 a.m.
This patch implements a general system for command-line options to be
deferred for handling after the main sequence of calls to option
handlers.

The purpose of this is to separate those parts of option
handling/initialization that are best kept out of the driver
(involving RTL, registers, etc.) from those that can be shared with
the driver.

The deferred handling goes in a new file opts-global.c.  The intended
division is: opts-common.c for general option-handling code not
involving global data or the details of individual options, opts.c for
code relating to details of individual options but not involving
global data or state not readily available in the driver,
opts-global.c for code depending on global state or state not
available in the driver in ways that are hard to remove.  There are
still plenty of cases of options in opts.c using global data that will
need addressing in one way or another; the ones moved in this patch
are the ones for which it seems clearest that moving them is the right
approach.

Right now the deferred handling of common options is called from
toplev.c immediately after decode_options.  (None of the options in
question is an optimization option so we don't need to worry about
handling them in other calls to decode_options.)  This may move
elsewhere as the option initialization in toplev.c:process_options
gets better integrated with that in opts.c:finish_options.

Deferred handling is already used by at least C-family and Fortran
front ends for some preprocessor options; this patch doesn't do
anything with that although it would probably make sense to move it to
the new mechanism.

The deferred options are stored in a VEC; where multiple sets of
deferred options are useful, different options can specify different
Var settings along with Defer in the .opt file.  However, the
gcc_options field is declared as void *.  This is because declaring
VEC types also defines inline functions, which need symbols from
vec.c, and options.h is included in tm.h which is included in target
code and miscellaneous host programs such as gcov which don't use
vec.c.  If uses of tm.h in code built for the target are eliminated,
it may then make sense to revisit this, add vec.o and ggc-none.o to
all miscellaneous host programs not using them (it seems reasonable to
consider VECs generic infrastructure it's OK to link into all
programs), and give the fields their proper VEC types.

Bootstrapped with no regressions on x86_64-unknown-linux-gnu.  OK to
commit?

2010-11-17  Joseph Myers  <joseph@codesourcery.com>

	* doc/options.texi (Var): Document effects of Defer.
	(Defer): Document.
	* opt-functions.awk (var_type, var_set): Handle deferred options.
	* opts-common.c (set_option): Handle CLVC_DEFER.
	* common.opt (fcall-saved-, fcall-used-, fdump-, ffixed-,
	fplugin=, fplugin-arg-, fstack-limit, fstack-limit-register=,
	fstack-limit-symbol=): Mark as deferred.
	* opts.c: Don't include rtl.h, ggc.h, output.h, tree-pass.h or
	plugin.h.
	(print_filtered_help): Don't report state of CLVC_DEFER options.
	(common_handle_option): Move code for OPT_fcall_used_,
	OPT_fcall_saved_, OPT_fdump_, OPT_ffixed_, OPT_fplugin_,
	OPT_fplugin_arg_, OPT_fstack_limit, OPT_fstack_limit_register_ and
	OPT_fstack_limit_symbol_ to opts-global.c.
	(option_enabled, get_option_state): Hanle CLVC_DEFER.
	* opts.h: Include vec.h.
	(enum cl_var_type): Add CLVC_DEFER.
	(cl_deferred_option): Define type and vectors.
	(handle_common_deferred_options): Declare.
	* opts-global.c: New.
	* toplev.c (toplev_main): Call handle_common_deferred_options
	* Makefile.in (OPTS_H): Include $(VEC_H).
	(OBJS-common): Include opts-global.o.
	(opts.o): Update dependencies.
	(opts-global.o): Add dependencies.
Richard Guenther - Nov. 19, 2010, 1:14 p.m.
On Wed, Nov 17, 2010 at 10:18 AM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> This patch implements a general system for command-line options to be
> deferred for handling after the main sequence of calls to option
> handlers.
>
> The purpose of this is to separate those parts of option
> handling/initialization that are best kept out of the driver
> (involving RTL, registers, etc.) from those that can be shared with
> the driver.
>
> The deferred handling goes in a new file opts-global.c.  The intended
> division is: opts-common.c for general option-handling code not
> involving global data or the details of individual options, opts.c for
> code relating to details of individual options but not involving
> global data or state not readily available in the driver,
> opts-global.c for code depending on global state or state not
> available in the driver in ways that are hard to remove.  There are
> still plenty of cases of options in opts.c using global data that will
> need addressing in one way or another; the ones moved in this patch
> are the ones for which it seems clearest that moving them is the right
> approach.
>
> Right now the deferred handling of common options is called from
> toplev.c immediately after decode_options.  (None of the options in
> question is an optimization option so we don't need to worry about
> handling them in other calls to decode_options.)  This may move
> elsewhere as the option initialization in toplev.c:process_options
> gets better integrated with that in opts.c:finish_options.
>
> Deferred handling is already used by at least C-family and Fortran
> front ends for some preprocessor options; this patch doesn't do
> anything with that although it would probably make sense to move it to
> the new mechanism.
>
> The deferred options are stored in a VEC; where multiple sets of
> deferred options are useful, different options can specify different
> Var settings along with Defer in the .opt file.  However, the
> gcc_options field is declared as void *.  This is because declaring
> VEC types also defines inline functions, which need symbols from
> vec.c, and options.h is included in tm.h which is included in target
> code and miscellaneous host programs such as gcov which don't use
> vec.c.  If uses of tm.h in code built for the target are eliminated,
> it may then make sense to revisit this, add vec.o and ggc-none.o to
> all miscellaneous host programs not using them (it seems reasonable to
> consider VECs generic infrastructure it's OK to link into all
> programs), and give the fields their proper VEC types.
>
> Bootstrapped with no regressions on x86_64-unknown-linux-gnu.  OK to
> commit?

Ok.

Thanks,
Richard.

> 2010-11-17  Joseph Myers  <joseph@codesourcery.com>
>
>        * doc/options.texi (Var): Document effects of Defer.
>        (Defer): Document.
>        * opt-functions.awk (var_type, var_set): Handle deferred options.
>        * opts-common.c (set_option): Handle CLVC_DEFER.
>        * common.opt (fcall-saved-, fcall-used-, fdump-, ffixed-,
>        fplugin=, fplugin-arg-, fstack-limit, fstack-limit-register=,
>        fstack-limit-symbol=): Mark as deferred.
>        * opts.c: Don't include rtl.h, ggc.h, output.h, tree-pass.h or
>        plugin.h.
>        (print_filtered_help): Don't report state of CLVC_DEFER options.
>        (common_handle_option): Move code for OPT_fcall_used_,
>        OPT_fcall_saved_, OPT_fdump_, OPT_ffixed_, OPT_fplugin_,
>        OPT_fplugin_arg_, OPT_fstack_limit, OPT_fstack_limit_register_ and
>        OPT_fstack_limit_symbol_ to opts-global.c.
>        (option_enabled, get_option_state): Hanle CLVC_DEFER.
>        * opts.h: Include vec.h.
>        (enum cl_var_type): Add CLVC_DEFER.
>        (cl_deferred_option): Define type and vectors.
>        (handle_common_deferred_options): Declare.
>        * opts-global.c: New.
>        * toplev.c (toplev_main): Call handle_common_deferred_options
>        * Makefile.in (OPTS_H): Include $(VEC_H).
>        (OBJS-common): Include opts-global.o.
>        (opts.o): Update dependencies.
>        (opts-global.o): Add dependencies.
>
> Index: gcc/doc/options.texi
> ===================================================================
> --- gcc/doc/options.texi        (revision 166795)
> +++ gcc/doc/options.texi        (working copy)
> @@ -201,6 +201,12 @@ If the option takes an argument and has
>  @var{var} is an integer variable that stores the value of the argument.
>
>  @item
> +If the option has the @code{Defer} property, @var{var} is a pointer to
> +a @code{VEC(cl_deferred_option,heap)} that stores the option for later
> +processing.  (@var{var} is declared with type @code{void *} and needs
> +to be cast to @code{VEC(cl_deferred_option,heap)} before use.)
> +
> +@item
>  Otherwise, if the option takes an argument, @var{var} is a pointer to
>  the argument string.  The pointer will be null if the argument is optional
>  and wasn't given.
> @@ -255,6 +261,10 @@ The main purpose of this property is to
>  The first option should use @samp{Mask(@var{name})} and the others
>  should use @samp{Mask(@var{name}) MaskExists}.
>
> +@item Defer
> +The option should be stored in a vector, specified with @code{Var},
> +for later processing.
> +
>  @item Alias(@var{opt})
>  @itemx Alias(@var{opt}, @var{arg})
>  @itemx Alias(@var{opt}, @var{posarg}, @var{negarg})
> Index: gcc/opts-common.c
> ===================================================================
> --- gcc/opts-common.c   (revision 166795)
> +++ gcc/opts-common.c   (working copy)
> @@ -958,6 +958,22 @@ set_option (struct gcc_options *opts, st
>        if (set_flag_var)
>          *(const char **) set_flag_var = "";
>        break;
> +
> +    case CLVC_DEFER:
> +       {
> +         VEC(cl_deferred_option,heap) *vec
> +           = (VEC(cl_deferred_option,heap) *) *(void **) flag_var;
> +         cl_deferred_option *p;
> +
> +         p = VEC_safe_push (cl_deferred_option, heap, vec, NULL);
> +         p->opt_index = opt_index;
> +         p->arg = arg;
> +         p->value = value;
> +         *(void **) flag_var = vec;
> +         if (set_flag_var)
> +           *(void **) set_flag_var = vec;
> +       }
> +       break;
>     }
>
>   if ((diagnostic_t) kind != DK_UNSPECIFIED
> Index: gcc/toplev.c
> ===================================================================
> --- gcc/toplev.c        (revision 166795)
> +++ gcc/toplev.c        (working copy)
> @@ -2365,6 +2365,8 @@ toplev_main (int argc, char **argv)
>                  save_decoded_options, save_decoded_options_count,
>                  UNKNOWN_LOCATION, global_dc);
>
> +  handle_common_deferred_options ();
> +
>   init_local_tick ();
>
>   initialize_plugins ();
> Index: gcc/opts.c
> ===================================================================
> --- gcc/opts.c  (revision 166795)
> +++ gcc/opts.c  (working copy)
> @@ -25,10 +25,7 @@ along with GCC; see the file COPYING3.
>  #include "coretypes.h"
>  #include "tm.h"
>  #include "tree.h"
> -#include "rtl.h"
>  #include "expr.h"
> -#include "ggc.h"
> -#include "output.h"
>  #include "langhooks.h"
>  #include "opts.h"
>  #include "options.h"
> @@ -39,10 +36,8 @@ along with GCC; see the file COPYING3.
>  #include "opts-diagnostic.h"
>  #include "insn-attr.h"         /* For INSN_SCHEDULING.  */
>  #include "target.h"
> -#include "tree-pass.h"
>  #include "dbgcnt.h"
>  #include "debug.h"
> -#include "plugin.h"
>  #include "except.h"
>  #include "lto-streamer.h"
>
> @@ -1440,7 +1435,8 @@ print_filtered_help (unsigned int includ
>          else
>            strcpy (new_help, "\t");
>
> -         if (flag_var != NULL)
> +         if (flag_var != NULL
> +             && option->var_type != CLVC_DEFER)
>            {
>              if (option->flags & CL_JOINED)
>                {
> @@ -1839,11 +1835,8 @@ common_handle_option (struct gcc_options
>       break;
>
>     case OPT_fcall_used_:
> -      fix_register (arg, 0, 1);
> -      break;
> -
>     case OPT_fcall_saved_:
> -      fix_register (arg, 0, 0);
> +      /* Deferred.  */
>       break;
>
>     case OPT_fcompare_debug_second:
> @@ -1877,8 +1870,7 @@ common_handle_option (struct gcc_options
>       break;
>
>     case OPT_fdump_:
> -      if (!dump_switch_p (arg))
> -       return false;
> +      /* Deferred.  */
>       break;
>
>     case OPT_ffp_contract_:
> @@ -1911,7 +1903,7 @@ common_handle_option (struct gcc_options
>       break;
>
>     case OPT_ffixed_:
> -      fix_register (arg, 1, 1);
> +      /* Deferred.  */
>       break;
>
>     case OPT_finline_limit_:
> @@ -1946,19 +1938,8 @@ common_handle_option (struct gcc_options
>       break;
>
>     case OPT_fplugin_:
> -#ifdef ENABLE_PLUGIN
> -      add_new_plugin (arg);
> -#else
> -      error ("plugin support is disabled; configure with --enable-plugin");
> -#endif
> -      break;
> -
>     case OPT_fplugin_arg_:
> -#ifdef ENABLE_PLUGIN
> -      parse_plugin_arg_opt (arg);
> -#else
> -      error ("plugin support is disabled; configure with --enable-plugin");
> -#endif
> +      /* Deferred.  */
>       break;
>
>     case OPT_fprofile_dir_:
> @@ -2084,21 +2065,12 @@ common_handle_option (struct gcc_options
>       /* The real switch is -fno-stack-limit.  */
>       if (value)
>        return false;
> -      stack_limit_rtx = NULL_RTX;
> +      /* Deferred.  */
>       break;
>
>     case OPT_fstack_limit_register_:
> -      {
> -       int reg = decode_reg_name (arg);
> -       if (reg < 0)
> -         error ("unrecognized register name \"%s\"", arg);
> -       else
> -         stack_limit_rtx = gen_rtx_REG (Pmode, reg);
> -      }
> -      break;
> -
>     case OPT_fstack_limit_symbol_:
> -      stack_limit_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (arg));
> +      /* Deferred.  */
>       break;
>
>     case OPT_ftree_vectorizer_verbose_:
> @@ -2380,6 +2352,7 @@ option_enabled (int opt_idx, void *opts)
>        return (*(int *) flag_var & option->var_value) != 0;
>
>       case CLVC_STRING:
> +      case CLVC_DEFER:
>        break;
>       }
>   return -1;
> @@ -2418,6 +2391,9 @@ get_option_state (struct gcc_options *op
>        state->data = "";
>       state->size = strlen ((const char *) state->data) + 1;
>       break;
> +
> +    case CLVC_DEFER:
> +      return false;
>     }
>   return true;
>  }
> Index: gcc/opts.h
> ===================================================================
> --- gcc/opts.h  (revision 166795)
> +++ gcc/opts.h  (working copy)
> @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.
>  #define GCC_OPTS_H
>
>  #include "input.h"
> +#include "vec.h"
>
>  /* Specifies how a switch's VAR_VALUE relates to its FLAG_VAR.  */
>  enum cl_var_type {
> @@ -39,7 +40,11 @@ enum cl_var_type {
>
>   /* The switch takes a string argument and FLAG_VAR points to that
>      argument.  */
> -  CLVC_STRING
> +  CLVC_STRING,
> +
> +  /* The switch should be stored in the VEC pointed to by FLAG_VAR for
> +     later processing.  */
> +  CLVC_DEFER
>  };
>
>  struct cl_option
> @@ -158,6 +163,20 @@ struct cl_decoded_option
>   int errors;
>  };
>
> +/* Structure describing an option deferred for handling after the main
> +   option handlers.  */
> +
> +typedef struct
> +{
> +  /* Elements from struct cl_decoded_option used for deferred
> +     options.  */
> +  size_t opt_index;
> +  const char *arg;
> +  int value;
> +} cl_deferred_option;
> +DEF_VEC_O(cl_deferred_option);
> +DEF_VEC_ALLOC_O(cl_deferred_option,heap);
> +
>  /* Structure describing a single option-handling callback.  */
>
>  struct cl_option_handler_func
> @@ -264,4 +283,5 @@ extern void control_warning_option (unsi
>                                    struct gcc_options *opts_set,
>                                    diagnostic_context *dc);
>  extern void print_ignored_options (void);
> +extern void handle_common_deferred_options (void);
>  #endif
> Index: gcc/common.opt
> ===================================================================
> --- gcc/common.opt      (revision 166795)
> +++ gcc/common.opt      (working copy)
> @@ -710,11 +710,11 @@ Common Report Var(flag_btr_bb_exclusive)
>  Restrict target load migration not to re-use registers in any basic block
>
>  fcall-saved-
> -Common Joined RejectNegative
> +Common Joined RejectNegative Var(common_deferred_options) Defer
>  -fcall-saved-<register>        Mark <register> as being preserved across functions
>
>  fcall-used-
> -Common Joined RejectNegative
> +Common Joined RejectNegative Var(common_deferred_options) Defer
>  -fcall-used-<register> Mark <register> as being corrupted by function calls
>
>  ; Nonzero for -fcaller-saves: allocate values in regs that need to
> @@ -815,7 +815,7 @@ Common Var(flag_diagnostics_show_option)
>  Amend appropriate diagnostic messages with the command line option that controls them
>
>  fdump-
> -Common Joined RejectNegative
> +Common Joined RejectNegative Var(common_deferred_options) Defer
>  -fdump-<type>  Dump various compiler internals to a file
>
>  fdump-final-insns
> @@ -893,7 +893,7 @@ Common Report Var(flag_finite_math_only)
>  Assume no NaNs or infinities are generated
>
>  ffixed-
> -Common Joined RejectNegative
> +Common Joined RejectNegative Var(common_deferred_options) Defer
>  -ffixed-<register>     Mark <register> as being unavailable to the compiler
>
>  ffloat-store
> @@ -1306,11 +1306,11 @@ Common Report Var(flag_pie,1)
>  Generate position-independent code for executables if possible (small mode)
>
>  fplugin=
> -Common Joined RejectNegative
> +Common Joined RejectNegative Var(common_deferred_options) Defer
>  Specify a plugin to load
>
>  fplugin-arg-
> -Common Joined RejectNegative
> +Common Joined RejectNegative Var(common_deferred_options) Defer
>  -fplugin-arg-<name>-<key>[=<value>]    Specify argument <key>=<value> for plugin <name>
>
>  fpredictive-commoning
> @@ -1573,14 +1573,14 @@ Common Alias(fstack-check=, specific, no
>  Insert stack checking code into the program.  Same as -fstack-check=specific
>
>  fstack-limit
> -Common
> +Common Var(common_deferred_options) Defer
>
>  fstack-limit-register=
> -Common RejectNegative Joined
> +Common RejectNegative Joined Var(common_deferred_options) Defer
>  -fstack-limit-register=<register>      Trap if the stack goes past <register>
>
>  fstack-limit-symbol=
> -Common RejectNegative Joined
> +Common RejectNegative Joined Var(common_deferred_options) Defer
>  -fstack-limit-symbol=<name>    Trap if the stack goes past symbol <name>
>
>  fstack-protector
> Index: gcc/opt-functions.awk
> ===================================================================
> --- gcc/opt-functions.awk       (revision 166795)
> +++ gcc/opt-functions.awk       (working copy)
> @@ -148,7 +148,9 @@ function static_var(name, flags)
>  # Return the type of variable that should be associated with the given flags.
>  function var_type(flags)
>  {
> -       if (!flag_set_p("Joined.*", flags) && !flag_set_p("Separate", flags))
> +       if (flag_set_p("Defer", flags))
> +               return "void *"
> +       else if (!flag_set_p("Joined.*", flags) && !flag_set_p("Separate", flags))
>                return "int "
>        else if (flag_set_p("UInteger", flags))
>                return "int "
> @@ -177,6 +179,8 @@ function var_type_struct(flags)
>  # "var_cond" and "var_value" fields of its cl_options[] entry.
>  function var_set(flags)
>  {
> +       if (flag_set_p("Defer", flags))
> +               return "CLVC_DEFER, 0"
>        s = nth_arg(1, opt_args("Var", flags))
>        if (s != "")
>                return "CLVC_EQUAL, " s
> Index: gcc/opts-global.c
> ===================================================================
> --- gcc/opts-global.c   (revision 0)
> +++ gcc/opts-global.c   (revision 0)
> @@ -0,0 +1,105 @@
> +/* Command line option handling.  Code involving global state that
> +   should not be shared with the driver.
> +   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
> +   Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "diagnostic-core.h"
> +#include "opts.h"
> +#include "flags.h"
> +#include "ggc.h"
> +#include "tm.h" /* Required by rtl.h.  */
> +#include "rtl.h"
> +#include "output.h"
> +#include "plugin.h"
> +#include "tree-pass.h"
> +
> +void
> +handle_common_deferred_options (void)
> +{
> +  unsigned int i;
> +  cl_deferred_option *opt;
> +  VEC(cl_deferred_option,heap) *vec
> +    = (VEC(cl_deferred_option,heap) *) common_deferred_options;
> +
> +  FOR_EACH_VEC_ELT (cl_deferred_option, vec, i, opt)
> +    {
> +      switch (opt->opt_index)
> +       {
> +       case OPT_fcall_used_:
> +         fix_register (opt->arg, 0, 1);
> +         break;
> +
> +       case OPT_fcall_saved_:
> +         fix_register (opt->arg, 0, 0);
> +         break;
> +
> +       case OPT_fdump_:
> +         if (!dump_switch_p (opt->arg))
> +           error ("unrecognized command line option %<-fdump-%s%>", opt->arg);
> +         break;
> +
> +       case OPT_ffixed_:
> +         /* Deferred.  */
> +         fix_register (opt->arg, 1, 1);
> +         break;
> +
> +       case OPT_fplugin_:
> +#ifdef ENABLE_PLUGIN
> +         add_new_plugin (opt->arg);
> +#else
> +         error ("plugin support is disabled; configure with --enable-plugin");
> +#endif
> +         break;
> +
> +       case OPT_fplugin_arg_:
> +#ifdef ENABLE_PLUGIN
> +         parse_plugin_arg_opt (opt->arg);
> +#else
> +         error ("plugin support is disabled; configure with --enable-plugin");
> +#endif
> +         break;
> +
> +       case OPT_fstack_limit:
> +         /* The real switch is -fno-stack-limit.  */
> +         gcc_assert (!opt->value);
> +         stack_limit_rtx = NULL_RTX;
> +         break;
> +
> +       case OPT_fstack_limit_register_:
> +         {
> +           int reg = decode_reg_name (opt->arg);
> +           if (reg < 0)
> +             error ("unrecognized register name %qs", opt->arg);
> +           else
> +             stack_limit_rtx = gen_rtx_REG (Pmode, reg);
> +         }
> +         break;
> +
> +       case OPT_fstack_limit_symbol_:
> +         stack_limit_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (opt->arg));
> +         break;
> +
> +       default:
> +         gcc_unreachable ();
> +       }
> +    }
> +}
> Index: gcc/Makefile.in
> ===================================================================
> --- gcc/Makefile.in     (revision 166795)
> +++ gcc/Makefile.in     (working copy)
> @@ -932,7 +932,7 @@ PREDICT_H = predict.h predict.def
>  CPPLIB_H = $(srcdir)/../libcpp/include/line-map.h \
>        $(srcdir)/../libcpp/include/cpplib.h
>  INPUT_H = $(srcdir)/../libcpp/include/line-map.h input.h
> -OPTS_H = $(INPUT_H) opts.h
> +OPTS_H = $(INPUT_H) $(VEC_H) opts.h
>  DECNUM_H = $(DECNUM)/decContext.h $(DECNUM)/decDPD.h $(DECNUM)/decNumber.h \
>        $(DECNUMFMT)/decimal32.h $(DECNUMFMT)/decimal64.h \
>        $(DECNUMFMT)/decimal128.h $(DECNUMFMT)/decimal128Local.h
> @@ -1295,6 +1295,7 @@ OBJS-common = \
>        optabs.o \
>        options.o \
>        opts-common.o \
> +       opts-global.o \
>        opts.o \
>        params.o \
>        passes.o \
> @@ -2810,10 +2811,13 @@ fold-const.o : fold-const.c $(CONFIG_H)
>  diagnostic.o : diagnostic.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
>    version.h $(INPUT_H) intl.h $(DIAGNOSTIC_H) diagnostic.def
>  opts.o : opts.c $(OPTS_H) $(OPTIONS_H) $(TOPLEV_H) $(DIAGNOSTIC_CORE_H) $(CONFIG_H) $(SYSTEM_H) \
> -   coretypes.h $(TREE_H) $(TM_H) langhooks.h $(GGC_H) $(EXPR_H) $(RTL_H) \
> -   output.h $(DIAGNOSTIC_H) $(TM_P_H) $(INSN_ATTR_H) intl.h $(TARGET_H) \
> -   $(FLAGS_H) $(PARAMS_H) $(TREE_PASS_H) $(DBGCNT_H) debug.h \
> -   $(PLUGIN_H) $(EXCEPT_H) $(LTO_STREAMER_H) opts-diagnostic.h
> +   coretypes.h $(TREE_H) $(TM_H) langhooks.h $(EXPR_H) \
> +   $(DIAGNOSTIC_H) $(TM_P_H) $(INSN_ATTR_H) intl.h $(TARGET_H) \
> +   $(FLAGS_H) $(PARAMS_H) $(DBGCNT_H) debug.h \
> +   $(EXCEPT_H) $(LTO_STREAMER_H) opts-diagnostic.h
> +opts-global.o : opts-global.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
> +   $(DIAGNOSTIC_CORE_H) $(OPTS_H) $(FLAGS_H) $(GGC_H) $(TM_H) $(RTL_H) \
> +   output.h $(PLUGIN_H) $(TREE_PASS_H)
>  opts-common.o : opts-common.c $(OPTS_H) $(FLAGS_H) $(CONFIG_H) $(SYSTEM_H) \
>    coretypes.h intl.h $(DIAGNOSTIC_H) $(TM_H)
>  targhooks.o : targhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>

Patch

Index: gcc/doc/options.texi
===================================================================
--- gcc/doc/options.texi	(revision 166795)
+++ gcc/doc/options.texi	(working copy)
@@ -201,6 +201,12 @@  If the option takes an argument and has 
 @var{var} is an integer variable that stores the value of the argument.
 
 @item
+If the option has the @code{Defer} property, @var{var} is a pointer to
+a @code{VEC(cl_deferred_option,heap)} that stores the option for later
+processing.  (@var{var} is declared with type @code{void *} and needs
+to be cast to @code{VEC(cl_deferred_option,heap)} before use.)
+
+@item
 Otherwise, if the option takes an argument, @var{var} is a pointer to
 the argument string.  The pointer will be null if the argument is optional
 and wasn't given.
@@ -255,6 +261,10 @@  The main purpose of this property is to 
 The first option should use @samp{Mask(@var{name})} and the others
 should use @samp{Mask(@var{name}) MaskExists}.
 
+@item Defer
+The option should be stored in a vector, specified with @code{Var},
+for later processing.
+
 @item Alias(@var{opt})
 @itemx Alias(@var{opt}, @var{arg})
 @itemx Alias(@var{opt}, @var{posarg}, @var{negarg})
Index: gcc/opts-common.c
===================================================================
--- gcc/opts-common.c	(revision 166795)
+++ gcc/opts-common.c	(working copy)
@@ -958,6 +958,22 @@  set_option (struct gcc_options *opts, st
 	if (set_flag_var)
 	  *(const char **) set_flag_var = "";
 	break;
+
+    case CLVC_DEFER:
+	{
+	  VEC(cl_deferred_option,heap) *vec
+	    = (VEC(cl_deferred_option,heap) *) *(void **) flag_var;
+	  cl_deferred_option *p;
+
+	  p = VEC_safe_push (cl_deferred_option, heap, vec, NULL);
+	  p->opt_index = opt_index;
+	  p->arg = arg;
+	  p->value = value;
+	  *(void **) flag_var = vec;
+	  if (set_flag_var)
+	    *(void **) set_flag_var = vec;
+	}
+	break;
     }
 
   if ((diagnostic_t) kind != DK_UNSPECIFIED
Index: gcc/toplev.c
===================================================================
--- gcc/toplev.c	(revision 166795)
+++ gcc/toplev.c	(working copy)
@@ -2365,6 +2365,8 @@  toplev_main (int argc, char **argv)
 		  save_decoded_options, save_decoded_options_count,
 		  UNKNOWN_LOCATION, global_dc);
 
+  handle_common_deferred_options ();
+
   init_local_tick ();
 
   initialize_plugins ();
Index: gcc/opts.c
===================================================================
--- gcc/opts.c	(revision 166795)
+++ gcc/opts.c	(working copy)
@@ -25,10 +25,7 @@  along with GCC; see the file COPYING3.  
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
-#include "rtl.h"
 #include "expr.h"
-#include "ggc.h"
-#include "output.h"
 #include "langhooks.h"
 #include "opts.h"
 #include "options.h"
@@ -39,10 +36,8 @@  along with GCC; see the file COPYING3.  
 #include "opts-diagnostic.h"
 #include "insn-attr.h"		/* For INSN_SCHEDULING.  */
 #include "target.h"
-#include "tree-pass.h"
 #include "dbgcnt.h"
 #include "debug.h"
-#include "plugin.h"
 #include "except.h"
 #include "lto-streamer.h"
 
@@ -1440,7 +1435,8 @@  print_filtered_help (unsigned int includ
 	  else
 	    strcpy (new_help, "\t");
 
-	  if (flag_var != NULL)
+	  if (flag_var != NULL
+	      && option->var_type != CLVC_DEFER)
 	    {
 	      if (option->flags & CL_JOINED)
 		{
@@ -1839,11 +1835,8 @@  common_handle_option (struct gcc_options
       break;
 
     case OPT_fcall_used_:
-      fix_register (arg, 0, 1);
-      break;
-
     case OPT_fcall_saved_:
-      fix_register (arg, 0, 0);
+      /* Deferred.  */
       break;
 
     case OPT_fcompare_debug_second:
@@ -1877,8 +1870,7 @@  common_handle_option (struct gcc_options
       break;
 
     case OPT_fdump_:
-      if (!dump_switch_p (arg))
-	return false;
+      /* Deferred.  */
       break;
 
     case OPT_ffp_contract_:
@@ -1911,7 +1903,7 @@  common_handle_option (struct gcc_options
       break;
 
     case OPT_ffixed_:
-      fix_register (arg, 1, 1);
+      /* Deferred.  */
       break;
 
     case OPT_finline_limit_:
@@ -1946,19 +1938,8 @@  common_handle_option (struct gcc_options
       break;
 
     case OPT_fplugin_:
-#ifdef ENABLE_PLUGIN
-      add_new_plugin (arg);
-#else
-      error ("plugin support is disabled; configure with --enable-plugin");
-#endif
-      break;
-
     case OPT_fplugin_arg_:
-#ifdef ENABLE_PLUGIN
-      parse_plugin_arg_opt (arg);
-#else
-      error ("plugin support is disabled; configure with --enable-plugin");
-#endif
+      /* Deferred.  */
       break;
 
     case OPT_fprofile_dir_:
@@ -2084,21 +2065,12 @@  common_handle_option (struct gcc_options
       /* The real switch is -fno-stack-limit.  */
       if (value)
 	return false;
-      stack_limit_rtx = NULL_RTX;
+      /* Deferred.  */
       break;
 
     case OPT_fstack_limit_register_:
-      {
-	int reg = decode_reg_name (arg);
-	if (reg < 0)
-	  error ("unrecognized register name \"%s\"", arg);
-	else
-	  stack_limit_rtx = gen_rtx_REG (Pmode, reg);
-      }
-      break;
-
     case OPT_fstack_limit_symbol_:
-      stack_limit_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (arg));
+      /* Deferred.  */
       break;
 
     case OPT_ftree_vectorizer_verbose_:
@@ -2380,6 +2352,7 @@  option_enabled (int opt_idx, void *opts)
 	return (*(int *) flag_var & option->var_value) != 0;
 
       case CLVC_STRING:
+      case CLVC_DEFER:
 	break;
       }
   return -1;
@@ -2418,6 +2391,9 @@  get_option_state (struct gcc_options *op
 	state->data = "";
       state->size = strlen ((const char *) state->data) + 1;
       break;
+
+    case CLVC_DEFER:
+      return false;
     }
   return true;
 }
Index: gcc/opts.h
===================================================================
--- gcc/opts.h	(revision 166795)
+++ gcc/opts.h	(working copy)
@@ -22,6 +22,7 @@  along with GCC; see the file COPYING3.  
 #define GCC_OPTS_H
 
 #include "input.h"
+#include "vec.h"
 
 /* Specifies how a switch's VAR_VALUE relates to its FLAG_VAR.  */
 enum cl_var_type {
@@ -39,7 +40,11 @@  enum cl_var_type {
 
   /* The switch takes a string argument and FLAG_VAR points to that
      argument.  */
-  CLVC_STRING
+  CLVC_STRING,
+
+  /* The switch should be stored in the VEC pointed to by FLAG_VAR for
+     later processing.  */
+  CLVC_DEFER
 };
 
 struct cl_option
@@ -158,6 +163,20 @@  struct cl_decoded_option
   int errors;
 };
 
+/* Structure describing an option deferred for handling after the main
+   option handlers.  */
+
+typedef struct
+{
+  /* Elements from struct cl_decoded_option used for deferred
+     options.  */
+  size_t opt_index;
+  const char *arg;
+  int value;
+} cl_deferred_option;
+DEF_VEC_O(cl_deferred_option);
+DEF_VEC_ALLOC_O(cl_deferred_option,heap);
+
 /* Structure describing a single option-handling callback.  */
 
 struct cl_option_handler_func
@@ -264,4 +283,5 @@  extern void control_warning_option (unsi
 				    struct gcc_options *opts_set,
 				    diagnostic_context *dc);
 extern void print_ignored_options (void);
+extern void handle_common_deferred_options (void);
 #endif
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 166795)
+++ gcc/common.opt	(working copy)
@@ -710,11 +710,11 @@  Common Report Var(flag_btr_bb_exclusive)
 Restrict target load migration not to re-use registers in any basic block
 
 fcall-saved-
-Common Joined RejectNegative
+Common Joined RejectNegative Var(common_deferred_options) Defer
 -fcall-saved-<register>	Mark <register> as being preserved across functions
 
 fcall-used-
-Common Joined RejectNegative
+Common Joined RejectNegative Var(common_deferred_options) Defer
 -fcall-used-<register>	Mark <register> as being corrupted by function calls
 
 ; Nonzero for -fcaller-saves: allocate values in regs that need to
@@ -815,7 +815,7 @@  Common Var(flag_diagnostics_show_option)
 Amend appropriate diagnostic messages with the command line option that controls them
 
 fdump-
-Common Joined RejectNegative
+Common Joined RejectNegative Var(common_deferred_options) Defer
 -fdump-<type>	Dump various compiler internals to a file
 
 fdump-final-insns
@@ -893,7 +893,7 @@  Common Report Var(flag_finite_math_only)
 Assume no NaNs or infinities are generated
 
 ffixed-
-Common Joined RejectNegative
+Common Joined RejectNegative Var(common_deferred_options) Defer
 -ffixed-<register>	Mark <register> as being unavailable to the compiler
 
 ffloat-store
@@ -1306,11 +1306,11 @@  Common Report Var(flag_pie,1)
 Generate position-independent code for executables if possible (small mode)
 
 fplugin=
-Common Joined RejectNegative
+Common Joined RejectNegative Var(common_deferred_options) Defer
 Specify a plugin to load
 
 fplugin-arg-
-Common Joined RejectNegative
+Common Joined RejectNegative Var(common_deferred_options) Defer
 -fplugin-arg-<name>-<key>[=<value>]	Specify argument <key>=<value> for plugin <name>
 
 fpredictive-commoning
@@ -1573,14 +1573,14 @@  Common Alias(fstack-check=, specific, no
 Insert stack checking code into the program.  Same as -fstack-check=specific
 
 fstack-limit
-Common
+Common Var(common_deferred_options) Defer
 
 fstack-limit-register=
-Common RejectNegative Joined
+Common RejectNegative Joined Var(common_deferred_options) Defer
 -fstack-limit-register=<register>	Trap if the stack goes past <register>
 
 fstack-limit-symbol=
-Common RejectNegative Joined
+Common RejectNegative Joined Var(common_deferred_options) Defer
 -fstack-limit-symbol=<name>	Trap if the stack goes past symbol <name>
 
 fstack-protector
Index: gcc/opt-functions.awk
===================================================================
--- gcc/opt-functions.awk	(revision 166795)
+++ gcc/opt-functions.awk	(working copy)
@@ -148,7 +148,9 @@  function static_var(name, flags)
 # Return the type of variable that should be associated with the given flags.
 function var_type(flags)
 {
-	if (!flag_set_p("Joined.*", flags) && !flag_set_p("Separate", flags))
+	if (flag_set_p("Defer", flags))
+		return "void *"
+	else if (!flag_set_p("Joined.*", flags) && !flag_set_p("Separate", flags))
 		return "int "
 	else if (flag_set_p("UInteger", flags))
 		return "int "
@@ -177,6 +179,8 @@  function var_type_struct(flags)
 # "var_cond" and "var_value" fields of its cl_options[] entry.
 function var_set(flags)
 {
+	if (flag_set_p("Defer", flags))
+		return "CLVC_DEFER, 0"
 	s = nth_arg(1, opt_args("Var", flags))
 	if (s != "")
 		return "CLVC_EQUAL, " s
Index: gcc/opts-global.c
===================================================================
--- gcc/opts-global.c	(revision 0)
+++ gcc/opts-global.c	(revision 0)
@@ -0,0 +1,105 @@ 
+/* Command line option handling.  Code involving global state that
+   should not be shared with the driver.
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostic-core.h"
+#include "opts.h"
+#include "flags.h"
+#include "ggc.h"
+#include "tm.h" /* Required by rtl.h.  */
+#include "rtl.h"
+#include "output.h"
+#include "plugin.h"
+#include "tree-pass.h"
+
+void
+handle_common_deferred_options (void)
+{
+  unsigned int i;
+  cl_deferred_option *opt;
+  VEC(cl_deferred_option,heap) *vec
+    = (VEC(cl_deferred_option,heap) *) common_deferred_options;
+
+  FOR_EACH_VEC_ELT (cl_deferred_option, vec, i, opt)
+    {
+      switch (opt->opt_index)
+	{
+	case OPT_fcall_used_:
+	  fix_register (opt->arg, 0, 1);
+	  break;
+
+	case OPT_fcall_saved_:
+	  fix_register (opt->arg, 0, 0);
+	  break;
+
+	case OPT_fdump_:
+	  if (!dump_switch_p (opt->arg))
+	    error ("unrecognized command line option %<-fdump-%s%>", opt->arg);
+	  break;
+
+	case OPT_ffixed_:
+	  /* Deferred.  */
+	  fix_register (opt->arg, 1, 1);
+	  break;
+
+	case OPT_fplugin_:
+#ifdef ENABLE_PLUGIN
+	  add_new_plugin (opt->arg);
+#else
+	  error ("plugin support is disabled; configure with --enable-plugin");
+#endif
+	  break;
+
+	case OPT_fplugin_arg_:
+#ifdef ENABLE_PLUGIN
+	  parse_plugin_arg_opt (opt->arg);
+#else
+	  error ("plugin support is disabled; configure with --enable-plugin");
+#endif
+	  break;
+
+	case OPT_fstack_limit:
+	  /* The real switch is -fno-stack-limit.  */
+	  gcc_assert (!opt->value);
+	  stack_limit_rtx = NULL_RTX;
+	  break;
+
+	case OPT_fstack_limit_register_:
+	  {
+	    int reg = decode_reg_name (opt->arg);
+	    if (reg < 0)
+	      error ("unrecognized register name %qs", opt->arg);
+	    else
+	      stack_limit_rtx = gen_rtx_REG (Pmode, reg);
+	  }
+	  break;
+
+	case OPT_fstack_limit_symbol_:
+	  stack_limit_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (opt->arg));
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	}
+    }
+}
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 166795)
+++ gcc/Makefile.in	(working copy)
@@ -932,7 +932,7 @@  PREDICT_H = predict.h predict.def
 CPPLIB_H = $(srcdir)/../libcpp/include/line-map.h \
 	$(srcdir)/../libcpp/include/cpplib.h
 INPUT_H = $(srcdir)/../libcpp/include/line-map.h input.h
-OPTS_H = $(INPUT_H) opts.h
+OPTS_H = $(INPUT_H) $(VEC_H) opts.h
 DECNUM_H = $(DECNUM)/decContext.h $(DECNUM)/decDPD.h $(DECNUM)/decNumber.h \
 	$(DECNUMFMT)/decimal32.h $(DECNUMFMT)/decimal64.h \
 	$(DECNUMFMT)/decimal128.h $(DECNUMFMT)/decimal128Local.h
@@ -1295,6 +1295,7 @@  OBJS-common = \
 	optabs.o \
 	options.o \
 	opts-common.o \
+	opts-global.o \
 	opts.o \
 	params.o \
 	passes.o \
@@ -2810,10 +2811,13 @@  fold-const.o : fold-const.c $(CONFIG_H) 
 diagnostic.o : diagnostic.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    version.h $(INPUT_H) intl.h $(DIAGNOSTIC_H) diagnostic.def
 opts.o : opts.c $(OPTS_H) $(OPTIONS_H) $(TOPLEV_H) $(DIAGNOSTIC_CORE_H) $(CONFIG_H) $(SYSTEM_H) \
-   coretypes.h $(TREE_H) $(TM_H) langhooks.h $(GGC_H) $(EXPR_H) $(RTL_H) \
-   output.h $(DIAGNOSTIC_H) $(TM_P_H) $(INSN_ATTR_H) intl.h $(TARGET_H) \
-   $(FLAGS_H) $(PARAMS_H) $(TREE_PASS_H) $(DBGCNT_H) debug.h \
-   $(PLUGIN_H) $(EXCEPT_H) $(LTO_STREAMER_H) opts-diagnostic.h
+   coretypes.h $(TREE_H) $(TM_H) langhooks.h $(EXPR_H) \
+   $(DIAGNOSTIC_H) $(TM_P_H) $(INSN_ATTR_H) intl.h $(TARGET_H) \
+   $(FLAGS_H) $(PARAMS_H) $(DBGCNT_H) debug.h \
+   $(EXCEPT_H) $(LTO_STREAMER_H) opts-diagnostic.h
+opts-global.o : opts-global.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+   $(DIAGNOSTIC_CORE_H) $(OPTS_H) $(FLAGS_H) $(GGC_H) $(TM_H) $(RTL_H) \
+   output.h $(PLUGIN_H) $(TREE_PASS_H)
 opts-common.o : opts-common.c $(OPTS_H) $(FLAGS_H) $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h intl.h $(DIAGNOSTIC_H) $(TM_H)
 targhooks.o : targhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \