Patchwork Avoid global state for -femit-struct-debug- options

login
register
mail settings
Submitter Joseph S. Myers
Date Nov. 19, 2010, 12:49 p.m.
Message ID <Pine.LNX.4.64.1011191248580.17023@digraph.polyomino.org.uk>
Download mbox | patch
Permalink /patch/72245/
State New
Headers show

Comments

Joseph S. Myers - Nov. 19, 2010, 12:49 p.m.
This patch, relative to a tree with
<http://gcc.gnu.org/ml/gcc-patches/2010-11/msg01778.html> (pending
review) and <http://gcc.gnu.org/ml/gcc-patches/2010-11/msg01858.html>
(approved) applied, eliminates use of global data for
-femit-struct-debug- options and the use of tree interfaces in opts.c.

The -femit-struct-debug- state now goes in the gcc_options structure.
The should_emit_struct_debug function that uses that state, and uses
tree interfaces so is unsuitable for the driver, is made a static
function in dwarf2out.c, since that is the only place that uses is and
the options are documented as only supported for DWARF2.

With this patch applied, opts.c no longer uses tree interfaces.  It
still uses one function declared in tree.h (vect_set_verbosity_level),
though that is easy to deal with.  While the tree.h include is
formally redundant with the expr.h include that follows, removing both
is trickier; langhooks.h depends on tree.h (which will be resolved by
moving various functions to opts-global.c), and the insn-attr.h
include for INSN_SCHEDULING depends on rtl.h having been included by
expr.h (as insn-attr.h includes insn-addr.h which needs INSN_UID).  A
subsequent patch will at least make these reasons explicit in
comments.

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

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

	* common.opt (debug_struct_ordinary, debug_struct_generic): New
	Variable entries.
	* dwarf2out.c (matches_main_base, dump_struct_debug, DUMP_GSTRUCT,
	should_emit_struct_debug): Move from opts.c.
	* flag-types.h (enum debug_struct_file): Move from opts.c.
	* flags.h (should_emit_struct_debug): Remove.
	(base_of_path): Declare.
	(set_struct_debug_option): Add gcc_options parameter.
	* optc-gen.awk, opth-gen.awk: Handle array variables.
	* opts.c (enum debug_struct_file, debug_struct_ordinary,
	debug_struct_generic): Remove.
	(set_struct_debug_option): Add gcc_options parameter.
	(base_of_path): Remove static.
	(main_input_basename, main_input_baselength, matches_main_base,
	dump_struct_debug, DUMP_GSTRUCT, should_emit_struct_debug):
	Remove.
	* toplev.c (main_input_basename, main_input_baselength): Define
	here.
	* toplev.h (main_input_basename, main_input_baselength): Declare
	here.

c-family:
2010-11-19  Joseph Myers  <joseph@codesourcery.com>

	* c-opts.c (c_common_handle_option): Update calls to
	set_struct_debug_option.
Richard Guenther - Nov. 19, 2010, 1:12 p.m.
On Fri, Nov 19, 2010 at 1:49 PM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> This patch, relative to a tree with
> <http://gcc.gnu.org/ml/gcc-patches/2010-11/msg01778.html> (pending
> review) and <http://gcc.gnu.org/ml/gcc-patches/2010-11/msg01858.html>
> (approved) applied, eliminates use of global data for
> -femit-struct-debug- options and the use of tree interfaces in opts.c.
>
> The -femit-struct-debug- state now goes in the gcc_options structure.
> The should_emit_struct_debug function that uses that state, and uses
> tree interfaces so is unsuitable for the driver, is made a static
> function in dwarf2out.c, since that is the only place that uses is and
> the options are documented as only supported for DWARF2.
>
> With this patch applied, opts.c no longer uses tree interfaces.  It
> still uses one function declared in tree.h (vect_set_verbosity_level),
> though that is easy to deal with.  While the tree.h include is
> formally redundant with the expr.h include that follows, removing both
> is trickier; langhooks.h depends on tree.h (which will be resolved by
> moving various functions to opts-global.c), and the insn-attr.h
> include for INSN_SCHEDULING depends on rtl.h having been included by
> expr.h (as insn-attr.h includes insn-addr.h which needs INSN_UID).  A
> subsequent patch will at least make these reasons explicit in
> comments.
>
> Bootstrapped with no regressions on x86_64-unknown-linux-gnu.  OK to
> commit?

Ok.

Thanks,
Richard.

> 2010-11-19  Joseph Myers  <joseph@codesourcery.com>
>
>        * common.opt (debug_struct_ordinary, debug_struct_generic): New
>        Variable entries.
>        * dwarf2out.c (matches_main_base, dump_struct_debug, DUMP_GSTRUCT,
>        should_emit_struct_debug): Move from opts.c.
>        * flag-types.h (enum debug_struct_file): Move from opts.c.
>        * flags.h (should_emit_struct_debug): Remove.
>        (base_of_path): Declare.
>        (set_struct_debug_option): Add gcc_options parameter.
>        * optc-gen.awk, opth-gen.awk: Handle array variables.
>        * opts.c (enum debug_struct_file, debug_struct_ordinary,
>        debug_struct_generic): Remove.
>        (set_struct_debug_option): Add gcc_options parameter.
>        (base_of_path): Remove static.
>        (main_input_basename, main_input_baselength, matches_main_base,
>        dump_struct_debug, DUMP_GSTRUCT, should_emit_struct_debug):
>        Remove.
>        * toplev.c (main_input_basename, main_input_baselength): Define
>        here.
>        * toplev.h (main_input_basename, main_input_baselength): Declare
>        here.
>
> c-family:
> 2010-11-19  Joseph Myers  <joseph@codesourcery.com>
>
>        * c-opts.c (c_common_handle_option): Update calls to
>        set_struct_debug_option.
>
> diff -rupN --exclude=.svn gcc-mainline-1/gcc/c-family/c-opts.c gcc-mainline/gcc/c-family/c-opts.c
> --- gcc-mainline-1/gcc/c-family/c-opts.c        2010-11-17 06:29:21.000000000 -0800
> +++ gcc-mainline/gcc/c-family/c-opts.c  2010-11-18 16:22:22.000000000 -0800
> @@ -654,15 +654,16 @@ c_common_handle_option (size_t scode, co
>       break;
>
>     case OPT_femit_struct_debug_baseonly:
> -      set_struct_debug_option ("base");
> +      set_struct_debug_option (&global_options, "base");
>       break;
>
>     case OPT_femit_struct_debug_reduced:
> -      set_struct_debug_option ("dir:ord:sys,dir:gen:any,ind:base");
> +      set_struct_debug_option (&global_options,
> +                              "dir:ord:sys,dir:gen:any,ind:base");
>       break;
>
>     case OPT_femit_struct_debug_detailed_:
> -      set_struct_debug_option (arg);
> +      set_struct_debug_option (&global_options, arg);
>       break;
>
>     case OPT_idirafter:
> diff -rupN --exclude=.svn gcc-mainline-1/gcc/common.opt gcc-mainline/gcc/common.opt
> --- gcc-mainline-1/gcc/common.opt       2010-11-17 12:38:37.000000000 -0800
> +++ gcc-mainline/gcc/common.opt 2010-11-18 16:17:45.000000000 -0800
> @@ -113,6 +113,19 @@ void *flag_instrument_functions_exclude_
>  Variable
>  void *flag_instrument_functions_exclude_files
>
> +; Generic structs (e.g. templates not explicitly specialized)
> +; may not have a compilation unit associated with them, and so
> +; may need to be treated differently from ordinary structs.
> +;
> +; Structs only handled by reference (indirectly), will also usually
> +; not need as much debugging information.
> +
> +Variable
> +enum debug_struct_file debug_struct_ordinary[DINFO_USAGE_NUM_ENUMS] = { DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY }
> +
> +Variable
> +enum debug_struct_file debug_struct_generic[DINFO_USAGE_NUM_ENUMS] = { DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY }
> +
>  ###
>  Driver
>
> diff -rupN --exclude=.svn gcc-mainline-1/gcc/dwarf2out.c gcc-mainline/gcc/dwarf2out.c
> --- gcc-mainline-1/gcc/dwarf2out.c      2010-11-15 17:01:15.000000000 -0800
> +++ gcc-mainline/gcc/dwarf2out.c        2010-11-18 16:33:59.000000000 -0800
> @@ -546,6 +546,89 @@ static struct dw_loc_descr_struct *mem_l
>  #define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG)
>  #endif
>
> +/* Match the base name of a file to the base name of a compilation unit. */
> +
> +static int
> +matches_main_base (const char *path)
> +{
> +  /* Cache the last query. */
> +  static const char *last_path = NULL;
> +  static int last_match = 0;
> +  if (path != last_path)
> +    {
> +      const char *base;
> +      int length = base_of_path (path, &base);
> +      last_path = path;
> +      last_match = (length == main_input_baselength
> +                    && memcmp (base, main_input_basename, length) == 0);
> +    }
> +  return last_match;
> +}
> +
> +#ifdef DEBUG_DEBUG_STRUCT
> +
> +static int
> +dump_struct_debug (tree type, enum debug_info_usage usage,
> +                  enum debug_struct_file criterion, int generic,
> +                  int matches, int result)
> +{
> +  /* Find the type name. */
> +  tree type_decl = TYPE_STUB_DECL (type);
> +  tree t = type_decl;
> +  const char *name = 0;
> +  if (TREE_CODE (t) == TYPE_DECL)
> +    t = DECL_NAME (t);
> +  if (t)
> +    name = IDENTIFIER_POINTER (t);
> +
> +  fprintf (stderr, "   struct %d %s %s %s %s %d %p %s\n",
> +          criterion,
> +           DECL_IN_SYSTEM_HEADER (type_decl) ? "sys" : "usr",
> +           matches ? "bas" : "hdr",
> +           generic ? "gen" : "ord",
> +           usage == DINFO_USAGE_DFN ? ";" :
> +             usage == DINFO_USAGE_DIR_USE ? "." : "*",
> +           result,
> +           (void*) type_decl, name);
> +  return result;
> +}
> +#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
> +  dump_struct_debug (type, usage, criterion, generic, matches, result)
> +
> +#else
> +
> +#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
> +  (result)
> +
> +#endif
> +
> +static bool
> +should_emit_struct_debug (tree type, enum debug_info_usage usage)
> +{
> +  enum debug_struct_file criterion;
> +  tree type_decl;
> +  bool generic = lang_hooks.types.generic_p (type);
> +
> +  if (generic)
> +    criterion = debug_struct_generic[usage];
> +  else
> +    criterion = debug_struct_ordinary[usage];
> +
> +  if (criterion == DINFO_STRUCT_FILE_NONE)
> +    return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
> +  if (criterion == DINFO_STRUCT_FILE_ANY)
> +    return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
> +
> +  type_decl = TYPE_STUB_DECL (type);
> +
> +  if (criterion == DINFO_STRUCT_FILE_SYS && DECL_IN_SYSTEM_HEADER (type_decl))
> +    return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
> +
> +  if (matches_main_base (DECL_SOURCE_FILE (type_decl)))
> +    return DUMP_GSTRUCT (type, usage, criterion, generic, true, true);
> +  return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
> +}
> +
>  /* Hook used by __throw.  */
>
>  rtx
> diff -rupN --exclude=.svn gcc-mainline-1/gcc/flag-types.h gcc-mainline/gcc/flag-types.h
> --- gcc-mainline-1/gcc/flag-types.h     2010-11-16 14:58:29.000000000 -0800
> +++ gcc-mainline/gcc/flag-types.h       2010-11-18 16:16:19.000000000 -0800
> @@ -58,6 +58,41 @@ enum debug_info_usage
>   DINFO_USAGE_NUM_ENUMS        /* The number of enumerators. */
>  };
>
> +/* A major contribution to object and executable size is debug
> +   information size.  A major contribution to debug information size
> +   is struct descriptions replicated in several object files. The
> +   following flags attempt to reduce this information.  The basic
> +   idea is to not emit struct debugging information in the current
> +   compilation unit when that information will be generated by
> +   another compilation unit.
> +
> +   Debug information for a struct defined in the current source
> +   file should be generated in the object file.  Likewise the
> +   debug information for a struct defined in a header should be
> +   generated in the object file of the corresponding source file.
> +   Both of these case are handled when the base name of the file of
> +   the struct definition matches the base name of the source file
> +   of the current compilation unit.  This matching emits minimal
> +   struct debugging information.
> +
> +   The base file name matching rule above will fail to emit debug
> +   information for structs defined in system headers.  So a second
> +   category of files includes system headers in addition to files
> +   with matching bases.
> +
> +   The remaining types of files are library headers and application
> +   headers.  We cannot currently distinguish these two types.  */
> +
> +enum debug_struct_file
> +{
> +  DINFO_STRUCT_FILE_NONE,   /* Debug no structs. */
> +  DINFO_STRUCT_FILE_BASE,   /* Debug structs defined in files with the
> +                               same base name as the compilation unit. */
> +  DINFO_STRUCT_FILE_SYS,    /* Also debug structs defined in system
> +                               header files.  */
> +  DINFO_STRUCT_FILE_ANY     /* Debug structs defined in all files. */
> +};
> +
>  /* Enumerate visibility settings.  This is deliberately ordered from most
>    to least visibility.  */
>  #ifndef SYMBOL_VISIBILITY_DEFINED
> diff -rupN --exclude=.svn gcc-mainline-1/gcc/flags.h gcc-mainline/gcc/flags.h
> --- gcc-mainline-1/gcc/flags.h  2010-11-17 12:42:47.000000000 -0800
> +++ gcc-mainline/gcc/flags.h    2010-11-18 16:37:32.000000000 -0800
> @@ -37,8 +37,9 @@ extern const char *const debug_type_name
>  /* Specify how much debugging info to generate.  */
>  extern enum debug_info_level debug_info_level;
>
> -extern bool should_emit_struct_debug (tree type_decl, enum debug_info_usage);
> -extern void set_struct_debug_option (const char *value);
> +extern int base_of_path (const char *path, const char **base_out);
> +extern void set_struct_debug_option (struct gcc_options *opts,
> +                                    const char *value);
>
>  /* Nonzero means use GNU-only extensions in the generated symbolic
>    debugging information.  */
> diff -rupN --exclude=.svn gcc-mainline-1/gcc/optc-gen.awk gcc-mainline/gcc/optc-gen.awk
> --- gcc-mainline-1/gcc/optc-gen.awk     2010-10-12 04:23:31.000000000 -0700
> +++ gcc-mainline/gcc/optc-gen.awk       2010-11-18 16:12:11.000000000 -0800
> @@ -91,6 +91,7 @@ for (i = 0; i < n_extra_vars; i++) {
>                sub(".*= *", "", init)
>                sub(" *=.*", "", var)
>                sub("^.*[ *]", "", var)
> +               sub("\\[.*\\]$", "", var)
>        } else {
>                init = "0"
>        }
> diff -rupN --exclude=.svn gcc-mainline-1/gcc/opth-gen.awk gcc-mainline/gcc/opth-gen.awk
> --- gcc-mainline-1/gcc/opth-gen.awk     2010-10-12 04:23:31.000000000 -0700
> +++ gcc-mainline/gcc/opth-gen.awk       2010-11-18 16:11:38.000000000 -0800
> @@ -86,13 +86,17 @@ for (i = 0; i < n_extra_vars; i++) {
>        orig_var = var
>        name = var
>        type = var
> +       type_after = var
>        sub("^.*[ *]", "", name)
> +       sub("\\[.*\\]$", "", name)
> +       sub("\\[.*\\]$", "", type)
>        sub(" *" name "$", "", type)
> +       sub("^.*" name, "", type_after)
>        var_seen[name] = 1
>        print "#ifdef GENERATOR_FILE"
>        print "extern " orig_var ";"
>        print "#else"
> -       print "  " type " x_" name ";"
> +       print "  " type " x_" name type_after ";"
>        print "#define " name " global_options.x_" name
>        print "#endif"
>  }
> diff -rupN --exclude=.svn gcc-mainline-1/gcc/opts.c gcc-mainline/gcc/opts.c
> --- gcc-mainline-1/gcc/opts.c   2010-11-17 12:44:07.000000000 -0800
> +++ gcc-mainline/gcc/opts.c     2010-11-18 16:53:19.000000000 -0800
> @@ -53,53 +53,6 @@ enum debug_info_type write_symbols = NO_
>    the definitions of the different possible levels.  */
>  enum debug_info_level debug_info_level = DINFO_LEVEL_NONE;
>
> -/* A major contribution to object and executable size is debug
> -   information size.  A major contribution to debug information size
> -   is struct descriptions replicated in several object files. The
> -   following flags attempt to reduce this information.  The basic
> -   idea is to not emit struct debugging information in the current
> -   compilation unit when that information will be generated by
> -   another compilation unit.
> -
> -   Debug information for a struct defined in the current source
> -   file should be generated in the object file.  Likewise the
> -   debug information for a struct defined in a header should be
> -   generated in the object file of the corresponding source file.
> -   Both of these case are handled when the base name of the file of
> -   the struct definition matches the base name of the source file
> -   of the current compilation unit.  This matching emits minimal
> -   struct debugging information.
> -
> -   The base file name matching rule above will fail to emit debug
> -   information for structs defined in system headers.  So a second
> -   category of files includes system headers in addition to files
> -   with matching bases.
> -
> -   The remaining types of files are library headers and application
> -   headers.  We cannot currently distinguish these two types.  */
> -
> -enum debug_struct_file
> -{
> -  DINFO_STRUCT_FILE_NONE,   /* Debug no structs. */
> -  DINFO_STRUCT_FILE_BASE,   /* Debug structs defined in files with the
> -                               same base name as the compilation unit. */
> -  DINFO_STRUCT_FILE_SYS,    /* Also debug structs defined in system
> -                               header files.  */
> -  DINFO_STRUCT_FILE_ANY     /* Debug structs defined in all files. */
> -};
> -
> -/* Generic structs (e.g. templates not explicitly specialized)
> -   may not have a compilation unit associated with them, and so
> -   may need to be treated differently from ordinary structs.
> -
> -   Structs only handled by reference (indirectly), will also usually
> -   not need as much debugging information.  */
> -
> -static enum debug_struct_file debug_struct_ordinary[DINFO_USAGE_NUM_ENUMS]
> -  = { DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY };
> -static enum debug_struct_file debug_struct_generic[DINFO_USAGE_NUM_ENUMS]
> -  = { DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY };
> -
>  /* Run the second compilation of -fcompare-debug.  Not defined using
>    Var in common.opt because this is used in Ada code and so must be
>    an actual variable not a macro.  */
> @@ -113,7 +66,7 @@ int flag_compare_debug;
>    ? ((string += sizeof prefix - 1), 1) : 0)
>
>  void
> -set_struct_debug_option (const char *spec)
> +set_struct_debug_option (struct gcc_options *opts, const char *spec)
>  {
>   /* various labels for comparison */
>   static char dfn_lbl[] = "dfn:", dir_lbl[] = "dir:", ind_lbl[] = "ind:";
> @@ -158,27 +111,27 @@ set_struct_debug_option (const char *spe
>     {
>       if (ord)
>         {
> -          debug_struct_ordinary[DINFO_USAGE_DFN] = files;
> -          debug_struct_ordinary[DINFO_USAGE_DIR_USE] = files;
> -          debug_struct_ordinary[DINFO_USAGE_IND_USE] = files;
> +          opts->x_debug_struct_ordinary[DINFO_USAGE_DFN] = files;
> +          opts->x_debug_struct_ordinary[DINFO_USAGE_DIR_USE] = files;
> +          opts->x_debug_struct_ordinary[DINFO_USAGE_IND_USE] = files;
>         }
>       if (gen)
>         {
> -          debug_struct_generic[DINFO_USAGE_DFN] = files;
> -          debug_struct_generic[DINFO_USAGE_DIR_USE] = files;
> -          debug_struct_generic[DINFO_USAGE_IND_USE] = files;
> +          opts->x_debug_struct_generic[DINFO_USAGE_DFN] = files;
> +          opts->x_debug_struct_generic[DINFO_USAGE_DIR_USE] = files;
> +          opts->x_debug_struct_generic[DINFO_USAGE_IND_USE] = files;
>         }
>     }
>   else
>     {
>       if (ord)
> -        debug_struct_ordinary[usage] = files;
> +        opts->x_debug_struct_ordinary[usage] = files;
>       if (gen)
> -        debug_struct_generic[usage] = files;
> +        opts->x_debug_struct_generic[usage] = files;
>     }
>
>   if (*spec == ',')
> -    set_struct_debug_option (spec+1);
> +    set_struct_debug_option (opts, spec+1);
>   else
>     {
>       /* No more -femit-struct-debug-detailed specifications.
> @@ -186,10 +139,10 @@ set_struct_debug_option (const char *spe
>       if (*spec != '\0')
>        error ("argument %qs to %<-femit-struct-debug-detailed%> unknown",
>                spec);
> -      if (debug_struct_ordinary[DINFO_USAGE_DIR_USE]
> -               < debug_struct_ordinary[DINFO_USAGE_IND_USE]
> -         || debug_struct_generic[DINFO_USAGE_DIR_USE]
> -               < debug_struct_generic[DINFO_USAGE_IND_USE])
> +      if (opts->x_debug_struct_ordinary[DINFO_USAGE_DIR_USE]
> +               < opts->x_debug_struct_ordinary[DINFO_USAGE_IND_USE]
> +         || opts->x_debug_struct_generic[DINFO_USAGE_DIR_USE]
> +               < opts->x_debug_struct_generic[DINFO_USAGE_IND_USE])
>        error ("%<-femit-struct-debug-detailed=dir:...%> must allow at least"
>                " as much as %<-femit-struct-debug-detailed=ind:...%>");
>     }
> @@ -197,7 +150,7 @@ set_struct_debug_option (const char *spe
>
>  /* Find the base name of a path, stripping off both directories and
>    a single final extension. */
> -static int
> +int
>  base_of_path (const char *path, const char **base_out)
>  {
>   const char *base = path;
> @@ -221,93 +174,6 @@ base_of_path (const char *path, const ch
>   return dot - base;
>  }
>
> -/* Match the base name of a file to the base name of a compilation unit. */
> -
> -static const char *main_input_basename;
> -static int main_input_baselength;
> -
> -static int
> -matches_main_base (const char *path)
> -{
> -  /* Cache the last query. */
> -  static const char *last_path = NULL;
> -  static int last_match = 0;
> -  if (path != last_path)
> -    {
> -      const char *base;
> -      int length = base_of_path (path, &base);
> -      last_path = path;
> -      last_match = (length == main_input_baselength
> -                    && memcmp (base, main_input_basename, length) == 0);
> -    }
> -  return last_match;
> -}
> -
> -#ifdef DEBUG_DEBUG_STRUCT
> -
> -static int
> -dump_struct_debug (tree type, enum debug_info_usage usage,
> -                  enum debug_struct_file criterion, int generic,
> -                  int matches, int result)
> -{
> -  /* Find the type name. */
> -  tree type_decl = TYPE_STUB_DECL (type);
> -  tree t = type_decl;
> -  const char *name = 0;
> -  if (TREE_CODE (t) == TYPE_DECL)
> -    t = DECL_NAME (t);
> -  if (t)
> -    name = IDENTIFIER_POINTER (t);
> -
> -  fprintf (stderr, "   struct %d %s %s %s %s %d %p %s\n",
> -          criterion,
> -           DECL_IN_SYSTEM_HEADER (type_decl) ? "sys" : "usr",
> -           matches ? "bas" : "hdr",
> -           generic ? "gen" : "ord",
> -           usage == DINFO_USAGE_DFN ? ";" :
> -             usage == DINFO_USAGE_DIR_USE ? "." : "*",
> -           result,
> -           (void*) type_decl, name);
> -  return result;
> -}
> -#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
> -  dump_struct_debug (type, usage, criterion, generic, matches, result)
> -
> -#else
> -
> -#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
> -  (result)
> -
> -#endif
> -
> -
> -bool
> -should_emit_struct_debug (tree type, enum debug_info_usage usage)
> -{
> -  enum debug_struct_file criterion;
> -  tree type_decl;
> -  bool generic = lang_hooks.types.generic_p (type);
> -
> -  if (generic)
> -    criterion = debug_struct_generic[usage];
> -  else
> -    criterion = debug_struct_ordinary[usage];
> -
> -  if (criterion == DINFO_STRUCT_FILE_NONE)
> -    return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
> -  if (criterion == DINFO_STRUCT_FILE_ANY)
> -    return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
> -
> -  type_decl = TYPE_STUB_DECL (type);
> -
> -  if (criterion == DINFO_STRUCT_FILE_SYS && DECL_IN_SYSTEM_HEADER (type_decl))
> -    return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
> -
> -  if (matches_main_base (DECL_SOURCE_FILE (type_decl)))
> -    return DUMP_GSTRUCT (type, usage, criterion, generic, true, true);
> -  return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
> -}
> -
>  /* Nonzero means use GNU-only extensions in the generated symbolic
>    debugging information.  Currently, this only has an effect when
>    write_symbols is set to DBX_DEBUG, XCOFF_DEBUG, or DWARF_DEBUG.  */
> diff -rupN --exclude=.svn gcc-mainline-1/gcc/toplev.c gcc-mainline/gcc/toplev.c
> --- gcc-mainline-1/gcc/toplev.c 2010-11-17 12:28:27.000000000 -0800
> +++ gcc-mainline/gcc/toplev.c   2010-11-18 16:33:14.000000000 -0800
> @@ -136,6 +136,12 @@ unsigned int save_decoded_options_count;
>
>  const char *main_input_filename;
>
> +/* Pointer to base name in main_input_filename, with directories and a
> +   single final extension removed, and the length of this base
> +   name.  */
> +const char *main_input_basename;
> +int main_input_baselength;
> +
>  /* Used to enable -fvar-tracking, -fweb and -frename-registers according
>    to optimize in process_options ().  */
>  #define AUTODETECT_VALUE 2
> diff -rupN --exclude=.svn gcc-mainline-1/gcc/toplev.h gcc-mainline/gcc/toplev.h
> --- gcc-mainline-1/gcc/toplev.h 2010-11-10 09:18:38.000000000 -0800
> +++ gcc-mainline/gcc/toplev.h   2010-11-18 16:33:25.000000000 -0800
> @@ -73,6 +73,8 @@ extern unsigned local_tick;
>
>  /* Top-level source file.  */
>  extern const char *main_input_filename;
> +extern const char *main_input_basename;
> +extern int main_input_baselength;
>
>  extern const char *profile_data_prefix;
>  extern bool exit_after_options;
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>

Patch

diff -rupN --exclude=.svn gcc-mainline-1/gcc/c-family/c-opts.c gcc-mainline/gcc/c-family/c-opts.c
--- gcc-mainline-1/gcc/c-family/c-opts.c	2010-11-17 06:29:21.000000000 -0800
+++ gcc-mainline/gcc/c-family/c-opts.c	2010-11-18 16:22:22.000000000 -0800
@@ -654,15 +654,16 @@  c_common_handle_option (size_t scode, co
       break;
 
     case OPT_femit_struct_debug_baseonly:
-      set_struct_debug_option ("base");
+      set_struct_debug_option (&global_options, "base");
       break;
 
     case OPT_femit_struct_debug_reduced:
-      set_struct_debug_option ("dir:ord:sys,dir:gen:any,ind:base");
+      set_struct_debug_option (&global_options,
+			       "dir:ord:sys,dir:gen:any,ind:base");
       break;
 
     case OPT_femit_struct_debug_detailed_:
-      set_struct_debug_option (arg);
+      set_struct_debug_option (&global_options, arg);
       break;
 
     case OPT_idirafter:
diff -rupN --exclude=.svn gcc-mainline-1/gcc/common.opt gcc-mainline/gcc/common.opt
--- gcc-mainline-1/gcc/common.opt	2010-11-17 12:38:37.000000000 -0800
+++ gcc-mainline/gcc/common.opt	2010-11-18 16:17:45.000000000 -0800
@@ -113,6 +113,19 @@  void *flag_instrument_functions_exclude_
 Variable
 void *flag_instrument_functions_exclude_files
 
+; Generic structs (e.g. templates not explicitly specialized)
+; may not have a compilation unit associated with them, and so
+; may need to be treated differently from ordinary structs.
+;
+; Structs only handled by reference (indirectly), will also usually
+; not need as much debugging information.
+
+Variable
+enum debug_struct_file debug_struct_ordinary[DINFO_USAGE_NUM_ENUMS] = { DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY }
+
+Variable
+enum debug_struct_file debug_struct_generic[DINFO_USAGE_NUM_ENUMS] = { DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY }
+
 ###
 Driver
 
diff -rupN --exclude=.svn gcc-mainline-1/gcc/dwarf2out.c gcc-mainline/gcc/dwarf2out.c
--- gcc-mainline-1/gcc/dwarf2out.c	2010-11-15 17:01:15.000000000 -0800
+++ gcc-mainline/gcc/dwarf2out.c	2010-11-18 16:33:59.000000000 -0800
@@ -546,6 +546,89 @@  static struct dw_loc_descr_struct *mem_l
 #define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG)
 #endif
 
+/* Match the base name of a file to the base name of a compilation unit. */
+
+static int
+matches_main_base (const char *path)
+{
+  /* Cache the last query. */
+  static const char *last_path = NULL;
+  static int last_match = 0;
+  if (path != last_path)
+    {
+      const char *base;
+      int length = base_of_path (path, &base);
+      last_path = path;
+      last_match = (length == main_input_baselength
+                    && memcmp (base, main_input_basename, length) == 0);
+    }
+  return last_match;
+}
+
+#ifdef DEBUG_DEBUG_STRUCT
+
+static int
+dump_struct_debug (tree type, enum debug_info_usage usage,
+		   enum debug_struct_file criterion, int generic,
+		   int matches, int result)
+{
+  /* Find the type name. */
+  tree type_decl = TYPE_STUB_DECL (type);
+  tree t = type_decl;
+  const char *name = 0;
+  if (TREE_CODE (t) == TYPE_DECL)
+    t = DECL_NAME (t);
+  if (t)
+    name = IDENTIFIER_POINTER (t);
+
+  fprintf (stderr, "	struct %d %s %s %s %s %d %p %s\n",
+	   criterion,
+           DECL_IN_SYSTEM_HEADER (type_decl) ? "sys" : "usr",
+           matches ? "bas" : "hdr",
+           generic ? "gen" : "ord",
+           usage == DINFO_USAGE_DFN ? ";" :
+             usage == DINFO_USAGE_DIR_USE ? "." : "*",
+           result,
+           (void*) type_decl, name);
+  return result;
+}
+#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
+  dump_struct_debug (type, usage, criterion, generic, matches, result)
+
+#else
+
+#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
+  (result)
+
+#endif
+
+static bool
+should_emit_struct_debug (tree type, enum debug_info_usage usage)
+{
+  enum debug_struct_file criterion;
+  tree type_decl;
+  bool generic = lang_hooks.types.generic_p (type);
+
+  if (generic)
+    criterion = debug_struct_generic[usage];
+  else
+    criterion = debug_struct_ordinary[usage];
+
+  if (criterion == DINFO_STRUCT_FILE_NONE)
+    return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
+  if (criterion == DINFO_STRUCT_FILE_ANY)
+    return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
+
+  type_decl = TYPE_STUB_DECL (type);
+
+  if (criterion == DINFO_STRUCT_FILE_SYS && DECL_IN_SYSTEM_HEADER (type_decl))
+    return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
+
+  if (matches_main_base (DECL_SOURCE_FILE (type_decl)))
+    return DUMP_GSTRUCT (type, usage, criterion, generic, true, true);
+  return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
+}
+
 /* Hook used by __throw.  */
 
 rtx
diff -rupN --exclude=.svn gcc-mainline-1/gcc/flag-types.h gcc-mainline/gcc/flag-types.h
--- gcc-mainline-1/gcc/flag-types.h	2010-11-16 14:58:29.000000000 -0800
+++ gcc-mainline/gcc/flag-types.h	2010-11-18 16:16:19.000000000 -0800
@@ -58,6 +58,41 @@  enum debug_info_usage
   DINFO_USAGE_NUM_ENUMS	/* The number of enumerators. */
 };
 
+/* A major contribution to object and executable size is debug
+   information size.  A major contribution to debug information size
+   is struct descriptions replicated in several object files. The
+   following flags attempt to reduce this information.  The basic
+   idea is to not emit struct debugging information in the current
+   compilation unit when that information will be generated by
+   another compilation unit.
+
+   Debug information for a struct defined in the current source
+   file should be generated in the object file.  Likewise the
+   debug information for a struct defined in a header should be
+   generated in the object file of the corresponding source file.
+   Both of these case are handled when the base name of the file of
+   the struct definition matches the base name of the source file
+   of the current compilation unit.  This matching emits minimal
+   struct debugging information.
+
+   The base file name matching rule above will fail to emit debug
+   information for structs defined in system headers.  So a second
+   category of files includes system headers in addition to files
+   with matching bases.
+
+   The remaining types of files are library headers and application
+   headers.  We cannot currently distinguish these two types.  */
+
+enum debug_struct_file
+{
+  DINFO_STRUCT_FILE_NONE,   /* Debug no structs. */
+  DINFO_STRUCT_FILE_BASE,   /* Debug structs defined in files with the
+                               same base name as the compilation unit. */
+  DINFO_STRUCT_FILE_SYS,    /* Also debug structs defined in system
+                               header files.  */
+  DINFO_STRUCT_FILE_ANY     /* Debug structs defined in all files. */
+};
+
 /* Enumerate visibility settings.  This is deliberately ordered from most
    to least visibility.  */
 #ifndef SYMBOL_VISIBILITY_DEFINED
diff -rupN --exclude=.svn gcc-mainline-1/gcc/flags.h gcc-mainline/gcc/flags.h
--- gcc-mainline-1/gcc/flags.h	2010-11-17 12:42:47.000000000 -0800
+++ gcc-mainline/gcc/flags.h	2010-11-18 16:37:32.000000000 -0800
@@ -37,8 +37,9 @@  extern const char *const debug_type_name
 /* Specify how much debugging info to generate.  */
 extern enum debug_info_level debug_info_level;
 
-extern bool should_emit_struct_debug (tree type_decl, enum debug_info_usage);
-extern void set_struct_debug_option (const char *value);
+extern int base_of_path (const char *path, const char **base_out);
+extern void set_struct_debug_option (struct gcc_options *opts,
+				     const char *value);
 
 /* Nonzero means use GNU-only extensions in the generated symbolic
    debugging information.  */
diff -rupN --exclude=.svn gcc-mainline-1/gcc/optc-gen.awk gcc-mainline/gcc/optc-gen.awk
--- gcc-mainline-1/gcc/optc-gen.awk	2010-10-12 04:23:31.000000000 -0700
+++ gcc-mainline/gcc/optc-gen.awk	2010-11-18 16:12:11.000000000 -0800
@@ -91,6 +91,7 @@  for (i = 0; i < n_extra_vars; i++) {
 		sub(".*= *", "", init)
 		sub(" *=.*", "", var)
 		sub("^.*[ *]", "", var)
+		sub("\\[.*\\]$", "", var)
 	} else {
 		init = "0"
 	}
diff -rupN --exclude=.svn gcc-mainline-1/gcc/opth-gen.awk gcc-mainline/gcc/opth-gen.awk
--- gcc-mainline-1/gcc/opth-gen.awk	2010-10-12 04:23:31.000000000 -0700
+++ gcc-mainline/gcc/opth-gen.awk	2010-11-18 16:11:38.000000000 -0800
@@ -86,13 +86,17 @@  for (i = 0; i < n_extra_vars; i++) {
 	orig_var = var
 	name = var
 	type = var
+	type_after = var
 	sub("^.*[ *]", "", name)
+	sub("\\[.*\\]$", "", name)
+	sub("\\[.*\\]$", "", type)
 	sub(" *" name "$", "", type)
+	sub("^.*" name, "", type_after)
 	var_seen[name] = 1
 	print "#ifdef GENERATOR_FILE"
 	print "extern " orig_var ";"
 	print "#else"
-	print "  " type " x_" name ";"
+	print "  " type " x_" name type_after ";"
 	print "#define " name " global_options.x_" name
 	print "#endif"
 }
diff -rupN --exclude=.svn gcc-mainline-1/gcc/opts.c gcc-mainline/gcc/opts.c
--- gcc-mainline-1/gcc/opts.c	2010-11-17 12:44:07.000000000 -0800
+++ gcc-mainline/gcc/opts.c	2010-11-18 16:53:19.000000000 -0800
@@ -53,53 +53,6 @@  enum debug_info_type write_symbols = NO_
    the definitions of the different possible levels.  */
 enum debug_info_level debug_info_level = DINFO_LEVEL_NONE;
 
-/* A major contribution to object and executable size is debug
-   information size.  A major contribution to debug information size
-   is struct descriptions replicated in several object files. The
-   following flags attempt to reduce this information.  The basic
-   idea is to not emit struct debugging information in the current
-   compilation unit when that information will be generated by
-   another compilation unit.
-
-   Debug information for a struct defined in the current source
-   file should be generated in the object file.  Likewise the
-   debug information for a struct defined in a header should be
-   generated in the object file of the corresponding source file.
-   Both of these case are handled when the base name of the file of
-   the struct definition matches the base name of the source file
-   of the current compilation unit.  This matching emits minimal
-   struct debugging information.
-
-   The base file name matching rule above will fail to emit debug
-   information for structs defined in system headers.  So a second
-   category of files includes system headers in addition to files
-   with matching bases.
-
-   The remaining types of files are library headers and application
-   headers.  We cannot currently distinguish these two types.  */
-
-enum debug_struct_file
-{
-  DINFO_STRUCT_FILE_NONE,   /* Debug no structs. */
-  DINFO_STRUCT_FILE_BASE,   /* Debug structs defined in files with the
-                               same base name as the compilation unit. */
-  DINFO_STRUCT_FILE_SYS,    /* Also debug structs defined in system
-                               header files.  */
-  DINFO_STRUCT_FILE_ANY     /* Debug structs defined in all files. */
-};
-
-/* Generic structs (e.g. templates not explicitly specialized)
-   may not have a compilation unit associated with them, and so
-   may need to be treated differently from ordinary structs.
-
-   Structs only handled by reference (indirectly), will also usually
-   not need as much debugging information.  */
-
-static enum debug_struct_file debug_struct_ordinary[DINFO_USAGE_NUM_ENUMS]
-  = { DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY };
-static enum debug_struct_file debug_struct_generic[DINFO_USAGE_NUM_ENUMS]
-  = { DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY };
-
 /* Run the second compilation of -fcompare-debug.  Not defined using
    Var in common.opt because this is used in Ada code and so must be
    an actual variable not a macro.  */
@@ -113,7 +66,7 @@  int flag_compare_debug;
    ? ((string += sizeof prefix - 1), 1) : 0)
 
 void
-set_struct_debug_option (const char *spec)
+set_struct_debug_option (struct gcc_options *opts, const char *spec)
 {
   /* various labels for comparison */
   static char dfn_lbl[] = "dfn:", dir_lbl[] = "dir:", ind_lbl[] = "ind:";
@@ -158,27 +111,27 @@  set_struct_debug_option (const char *spe
     {
       if (ord)
         {
-          debug_struct_ordinary[DINFO_USAGE_DFN] = files;
-          debug_struct_ordinary[DINFO_USAGE_DIR_USE] = files;
-          debug_struct_ordinary[DINFO_USAGE_IND_USE] = files;
+          opts->x_debug_struct_ordinary[DINFO_USAGE_DFN] = files;
+          opts->x_debug_struct_ordinary[DINFO_USAGE_DIR_USE] = files;
+          opts->x_debug_struct_ordinary[DINFO_USAGE_IND_USE] = files;
         }
       if (gen)
         {
-          debug_struct_generic[DINFO_USAGE_DFN] = files;
-          debug_struct_generic[DINFO_USAGE_DIR_USE] = files;
-          debug_struct_generic[DINFO_USAGE_IND_USE] = files;
+          opts->x_debug_struct_generic[DINFO_USAGE_DFN] = files;
+          opts->x_debug_struct_generic[DINFO_USAGE_DIR_USE] = files;
+          opts->x_debug_struct_generic[DINFO_USAGE_IND_USE] = files;
         }
     }
   else
     {
       if (ord)
-        debug_struct_ordinary[usage] = files;
+        opts->x_debug_struct_ordinary[usage] = files;
       if (gen)
-        debug_struct_generic[usage] = files;
+        opts->x_debug_struct_generic[usage] = files;
     }
 
   if (*spec == ',')
-    set_struct_debug_option (spec+1);
+    set_struct_debug_option (opts, spec+1);
   else
     {
       /* No more -femit-struct-debug-detailed specifications.
@@ -186,10 +139,10 @@  set_struct_debug_option (const char *spe
       if (*spec != '\0')
 	error ("argument %qs to %<-femit-struct-debug-detailed%> unknown",
                spec);
-      if (debug_struct_ordinary[DINFO_USAGE_DIR_USE]
-		< debug_struct_ordinary[DINFO_USAGE_IND_USE]
-	  || debug_struct_generic[DINFO_USAGE_DIR_USE]
-		< debug_struct_generic[DINFO_USAGE_IND_USE])
+      if (opts->x_debug_struct_ordinary[DINFO_USAGE_DIR_USE]
+		< opts->x_debug_struct_ordinary[DINFO_USAGE_IND_USE]
+	  || opts->x_debug_struct_generic[DINFO_USAGE_DIR_USE]
+		< opts->x_debug_struct_generic[DINFO_USAGE_IND_USE])
 	error ("%<-femit-struct-debug-detailed=dir:...%> must allow at least"
                " as much as %<-femit-struct-debug-detailed=ind:...%>");
     }
@@ -197,7 +150,7 @@  set_struct_debug_option (const char *spe
 
 /* Find the base name of a path, stripping off both directories and
    a single final extension. */
-static int
+int
 base_of_path (const char *path, const char **base_out)
 {
   const char *base = path;
@@ -221,93 +174,6 @@  base_of_path (const char *path, const ch
   return dot - base;
 }
 
-/* Match the base name of a file to the base name of a compilation unit. */
-
-static const char *main_input_basename;
-static int main_input_baselength;
-
-static int
-matches_main_base (const char *path)
-{
-  /* Cache the last query. */
-  static const char *last_path = NULL;
-  static int last_match = 0;
-  if (path != last_path)
-    {
-      const char *base;
-      int length = base_of_path (path, &base);
-      last_path = path;
-      last_match = (length == main_input_baselength
-                    && memcmp (base, main_input_basename, length) == 0);
-    }
-  return last_match;
-}
-
-#ifdef DEBUG_DEBUG_STRUCT
-
-static int
-dump_struct_debug (tree type, enum debug_info_usage usage,
-		   enum debug_struct_file criterion, int generic,
-		   int matches, int result)
-{
-  /* Find the type name. */
-  tree type_decl = TYPE_STUB_DECL (type);
-  tree t = type_decl;
-  const char *name = 0;
-  if (TREE_CODE (t) == TYPE_DECL)
-    t = DECL_NAME (t);
-  if (t)
-    name = IDENTIFIER_POINTER (t);
-
-  fprintf (stderr, "	struct %d %s %s %s %s %d %p %s\n",
-	   criterion,
-           DECL_IN_SYSTEM_HEADER (type_decl) ? "sys" : "usr",
-           matches ? "bas" : "hdr",
-           generic ? "gen" : "ord",
-           usage == DINFO_USAGE_DFN ? ";" :
-             usage == DINFO_USAGE_DIR_USE ? "." : "*",
-           result,
-           (void*) type_decl, name);
-  return result;
-}
-#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
-  dump_struct_debug (type, usage, criterion, generic, matches, result)
-
-#else
-
-#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
-  (result)
-
-#endif
-
-
-bool
-should_emit_struct_debug (tree type, enum debug_info_usage usage)
-{
-  enum debug_struct_file criterion;
-  tree type_decl;
-  bool generic = lang_hooks.types.generic_p (type);
-
-  if (generic)
-    criterion = debug_struct_generic[usage];
-  else
-    criterion = debug_struct_ordinary[usage];
-
-  if (criterion == DINFO_STRUCT_FILE_NONE)
-    return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
-  if (criterion == DINFO_STRUCT_FILE_ANY)
-    return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
-
-  type_decl = TYPE_STUB_DECL (type);
-
-  if (criterion == DINFO_STRUCT_FILE_SYS && DECL_IN_SYSTEM_HEADER (type_decl))
-    return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
-
-  if (matches_main_base (DECL_SOURCE_FILE (type_decl)))
-    return DUMP_GSTRUCT (type, usage, criterion, generic, true, true);
-  return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
-}
-
 /* Nonzero means use GNU-only extensions in the generated symbolic
    debugging information.  Currently, this only has an effect when
    write_symbols is set to DBX_DEBUG, XCOFF_DEBUG, or DWARF_DEBUG.  */
diff -rupN --exclude=.svn gcc-mainline-1/gcc/toplev.c gcc-mainline/gcc/toplev.c
--- gcc-mainline-1/gcc/toplev.c	2010-11-17 12:28:27.000000000 -0800
+++ gcc-mainline/gcc/toplev.c	2010-11-18 16:33:14.000000000 -0800
@@ -136,6 +136,12 @@  unsigned int save_decoded_options_count;
 
 const char *main_input_filename;
 
+/* Pointer to base name in main_input_filename, with directories and a
+   single final extension removed, and the length of this base
+   name.  */
+const char *main_input_basename;
+int main_input_baselength;
+
 /* Used to enable -fvar-tracking, -fweb and -frename-registers according
    to optimize in process_options ().  */
 #define AUTODETECT_VALUE 2
diff -rupN --exclude=.svn gcc-mainline-1/gcc/toplev.h gcc-mainline/gcc/toplev.h
--- gcc-mainline-1/gcc/toplev.h	2010-11-10 09:18:38.000000000 -0800
+++ gcc-mainline/gcc/toplev.h	2010-11-18 16:33:25.000000000 -0800
@@ -73,6 +73,8 @@  extern unsigned local_tick;
 
 /* Top-level source file.  */
 extern const char *main_input_filename;
+extern const char *main_input_basename;
+extern int main_input_baselength;
 
 extern const char *profile_data_prefix;
 extern bool exit_after_options;