Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 16 Nov 2013 01:16:24 +0000 (UTC)
From:      "Pedro F. Giffuni" <pfg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r258206 - in head/contrib/gcc: . cp doc
Message-ID:  <201311160116.rAG1GOgR066904@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: pfg
Date: Sat Nov 16 01:16:24 2013
New Revision: 258206
URL: http://svnweb.freebsd.org/changeset/base/258206

Log:
  gcc: add femit-struct-debug support to reduce Reduce dwarf debug size
  
  Obtained from:	gcc 4.3 (rev. 123909; GPLv2)
  MFC after:	3 weeks

Modified:
  head/contrib/gcc/ChangeLog.gcc43
  head/contrib/gcc/c-opts.c
  head/contrib/gcc/c.opt
  head/contrib/gcc/cp/cp-lang.c
  head/contrib/gcc/cp/cp-tree.h
  head/contrib/gcc/cp/tree.c
  head/contrib/gcc/doc/invoke.texi
  head/contrib/gcc/dwarf2out.c
  head/contrib/gcc/flags.h
  head/contrib/gcc/langhooks-def.h
  head/contrib/gcc/langhooks.h
  head/contrib/gcc/opts.c

Modified: head/contrib/gcc/ChangeLog.gcc43
==============================================================================
--- head/contrib/gcc/ChangeLog.gcc43	Sat Nov 16 01:07:02 2013	(r258205)
+++ head/contrib/gcc/ChangeLog.gcc43	Sat Nov 16 01:16:24 2013	(r258206)
@@ -27,6 +27,57 @@
 	alignment for amdfam10 architecture. Increasing the max loop
 	alignment to 24 bytes.
 
+2007-04-16  Lawrence Crowl  <crowl@google.com>
+
+	* doc/invoke.texi (Debugging Options): Add documentation for the
+	-femit-struct-debug options -femit-struct-debug-baseonly,
+	-femit-struct-debug-reduced, and
+	-femit-struct-debug-detailed[=...].
+
+	* c-opts.c (c_common_handle_option): Add
+	OPT_femit_struct_debug_baseonly, OPT_femit_struct_debug_reduced,
+	and OPT_femit_struct_debug_detailed_.
+	* c.opt: Add specifications for
+	-femit-struct-debug-baseonly, -femit-struct-debug-reduced,
+	and -femit-struct-debug-detailed[=...].
+	* opts.c (set_struct_debug_option): Parse the
+	-femit-struct-debug-... options.
+	* opts.c (matches_main_base, main_input_basename,
+	main_input_baselength, base_of_path, matches_main_base): Add
+	variables and functions to compare header base name to compilation
+	unit base name.
+	* opts.c (should_emit_struct_debug): Add to determine to emit a
+	structure based on the option.
+	(dump_struct_debug) Also disabled function to debug this
+	function.
+	* opts.c (handle_options): Save the base name of the
+	compilation unit.
+
+	* langhooks-def.h (LANG_HOOKS_GENERIC_TYPE_P): Define.
+        (LANG_HOOKS_FOR_TYPES_INITIALIZER): Add.
+	This hook indicates if a type is generic.  Set it by default
+	to "never generic".
+	* langhooks.h (struct lang_hooks_for_types): Add a new hook
+	to determine if a struct type is generic or not.
+	* cp/cp-tree.h (class_tmpl_impl_spec_p): Declare a C++ hook.
+	* cp/tree.c (class_tmpl_impl_spec_p): Implement the C++ hook.
+	* cp/cp-lang.c (LANG_HOOKS_GENERIC_TYPE_P): Override null C hook
+	with live C++ hook.
+
+	* flags.h (enum debug_info_usage): Add an enumeration to describe
+	a program's use of a structure type.
+	* dwarf2out.c (gen_struct_or_union_type_die): Add a new parameter
+	to indicate the program's usage of the type.  Filter structs based
+	on the -femit-struct-debug-... specification.
+	(gen_type_die): Split into two routines, gen_type_die and
+	gen_type_die_with_usage.  gen_type_die is now a wrapper
+	that assumes direct usage.
+	(gen_type_die_with_usage): Replace calls to gen_type_die
+	with gen_type_die_with_usage adding the program usage of
+	the referenced type.
+	(dwarf2out_imported_module_or_decl): Suppress struct debug
+	information using should_emit_struct_debug when appropriate.
+
 2007-04-12  Richard Guenther  <rguenther@suse.de> (r123736)
 
 	PR tree-optimization/24689

Modified: head/contrib/gcc/c-opts.c
==============================================================================
--- head/contrib/gcc/c-opts.c	Sat Nov 16 01:07:02 2013	(r258205)
+++ head/contrib/gcc/c-opts.c	Sat Nov 16 01:16:24 2013	(r258206)
@@ -818,6 +818,18 @@ c_common_handle_option (size_t scode, co
       flag_gen_declaration = 1;
       break;
 
+    case OPT_femit_struct_debug_baseonly:
+      set_struct_debug_option ("base");
+      break;
+
+    case OPT_femit_struct_debug_reduced:
+      set_struct_debug_option ("dir:ord:sys,dir:gen:any,ind:base");
+      break;
+
+    case OPT_femit_struct_debug_detailed_:
+      set_struct_debug_option (arg);
+      break;
+
     case OPT_idirafter:
       add_path (xstrdup (arg), AFTER, 0, true);
       break;

Modified: head/contrib/gcc/c.opt
==============================================================================
--- head/contrib/gcc/c.opt	Sat Nov 16 01:07:02 2013	(r258205)
+++ head/contrib/gcc/c.opt	Sat Nov 16 01:16:24 2013	(r258206)
@@ -765,6 +765,18 @@ gen-decls
 ObjC ObjC++
 Dump declarations to a .decl file
 
+femit-struct-debug-baseonly
+C ObjC C++ ObjC++
+-femit-struct-debug-baseonly	Aggressive reduced debug info for structs
+
+femit-struct-debug-reduced
+C ObjC C++ ObjC++
+-femit-struct-debug-reduced	Conservative reduced debug info for structs
+
+femit-struct-debug-detailed=
+C ObjC C++ ObjC++ Joined
+-femit-struct-debug-detailed=<spec-list>	Detailed reduced debug info for structs
+
 idirafter
 C ObjC C++ ObjC++ Joined Separate
 -idirafter <dir>	Add <dir> to the end of the system include path

Modified: head/contrib/gcc/cp/cp-lang.c
==============================================================================
--- head/contrib/gcc/cp/cp-lang.c	Sat Nov 16 01:07:02 2013	(r258205)
+++ head/contrib/gcc/cp/cp-lang.c	Sat Nov 16 01:16:24 2013	(r258206)
@@ -44,6 +44,8 @@ static void cp_init_ts (void);
 #define LANG_HOOKS_NAME "GNU C++"
 #undef LANG_HOOKS_INIT
 #define LANG_HOOKS_INIT cxx_init
+#undef LANG_HOOKS_GENERIC_TYPE_P
+#define LANG_HOOKS_GENERIC_TYPE_P class_tmpl_impl_spec_p
 #undef LANG_HOOKS_DECL_PRINTABLE_NAME
 #define LANG_HOOKS_DECL_PRINTABLE_NAME	cxx_printable_name
 #undef LANG_HOOKS_FOLD_OBJ_TYPE_REF

Modified: head/contrib/gcc/cp/cp-tree.h
==============================================================================
--- head/contrib/gcc/cp/cp-tree.h	Sat Nov 16 01:07:02 2013	(r258205)
+++ head/contrib/gcc/cp/cp-tree.h	Sat Nov 16 01:16:24 2013	(r258206)
@@ -4373,6 +4373,7 @@ extern tree add_stmt_to_compound		(tree,
 extern tree cxx_maybe_build_cleanup		(tree);
 extern void init_tree				(void);
 extern int pod_type_p				(tree);
+extern bool class_tmpl_impl_spec_p		(tree);
 extern int zero_init_p				(tree);
 extern tree canonical_type_variant		(tree);
 extern tree copy_binfo				(tree, tree, tree,

Modified: head/contrib/gcc/cp/tree.c
==============================================================================
--- head/contrib/gcc/cp/tree.c	Sat Nov 16 01:07:02 2013	(r258205)
+++ head/contrib/gcc/cp/tree.c	Sat Nov 16 01:16:24 2013	(r258206)
@@ -1762,6 +1762,14 @@ pod_type_p (tree t)
   return 1;
 }
 
+/* Nonzero iff type T is a class template implicit specialization.  */
+
+bool
+class_tmpl_impl_spec_p (tree t)
+{
+  return CLASS_TYPE_P (t) && CLASSTYPE_TEMPLATE_INSTANTIATION (t);
+}
+
 /* Returns 1 iff zero initialization of type T means actually storing
    zeros in it.  */
 

Modified: head/contrib/gcc/doc/invoke.texi
==============================================================================
--- head/contrib/gcc/doc/invoke.texi	Sat Nov 16 01:07:02 2013	(r258205)
+++ head/contrib/gcc/doc/invoke.texi	Sat Nov 16 01:16:24 2013	(r258206)
@@ -275,6 +275,8 @@ in the following sections.
 -ftest-coverage  -ftime-report -fvar-tracking @gol
 -g  -g@var{level}  -gcoff -gdwarf-2 @gol
 -ggdb  -gstabs  -gstabs+  -gvms  -gxcoff  -gxcoff+ @gol
+-femit-struct-debug-baseonly -femit-struct-debug-reduced @gol
+-femit-struct-debug-detailed@r{[}=@var{spec-list}@r{]} @gol
 -p  -pg  -print-file-name=@var{library}  -print-libgcc-file-name @gol
 -print-multi-directory  -print-multi-lib @gol
 -print-prog-name=@var{program}  -print-search-dirs  -Q @gol
@@ -3411,6 +3413,78 @@ Compress DWARF2 debugging information by
 information about each symbol.  This option only makes sense when
 generating DWARF2 debugging information with @option{-gdwarf-2}.
 
+@item -femit-struct-debug-baseonly
+Emit debug information for struct-like types
+only when the base name of the compilation source file
+matches the base name of file in which the struct was defined.
+
+This option substantially reduces the size of debugging information,
+but at significant potential loss in type information to the debugger.
+See @option{-femit-struct-debug-reduced} for a less aggressive option.
+See @option{-femit-struct-debug-detailed} for more detailed control.
+
+This option works only with DWARF 2.
+
+@item -femit-struct-debug-reduced
+Emit debug information for struct-like types
+only when the base name of the compilation source file
+matches the base name of file in which the type was defined,
+unless the struct is a template or defined in a system header.
+
+This option significantly reduces the size of debugging information,
+with some potential loss in type information to the debugger.
+See @option{-femit-struct-debug-baseonly} for a more aggressive option.
+See @option{-femit-struct-debug-detailed} for more detailed control.
+
+This option works only with DWARF 2.
+
+@item -femit-struct-debug-detailed@r{[}=@var{spec-list}@r{]}
+Specify the struct-like types
+for which the compiler will generate debug information.
+The intent is to reduce duplicate struct debug information
+between different object files within the same program.
+
+This option is a detailed version of
+@option{-femit-struct-debug-reduced} and @option{-femit-struct-debug-baseonly},
+which will serve for most needs.
+
+A specification has the syntax
+[@samp{dir:}|@samp{ind:}][@samp{ord:}|@samp{gen:}](@samp{any}|@samp{sys}|@samp{base}|@samp{none})
+
+The optional first word limits the specification to
+structs that are used directly (@samp{dir:}) or used indirectly (@samp{ind:}).
+A struct type is used directly when it is the type of a variable, member.
+Indirect uses arise through pointers to structs.
+That is, when use of an incomplete struct would be legal, the use is indirect.
+An example is
+@samp{struct one direct; struct two * indirect;}.
+
+The optional second word limits the specification to
+ordinary structs (@samp{ord:}) or generic structs (@samp{gen:}).
+Generic structs are a bit complicated to explain.
+For C++, these are non-explicit specializations of template classes,
+or non-template classes within the above.
+Other programming languages have generics,
+but @samp{-femit-struct-debug-detailed} does not yet implement them.
+
+The third word specifies the source files for those
+structs for which the compiler will emit debug information.
+The values @samp{none} and @samp{any} have the normal meaning.
+The value @samp{base} means that
+the base of name of the file in which the type declaration appears
+must match the base of the name of the main compilation file.
+In practice, this means that
+types declared in @file{foo.c} and @file{foo.h} will have debug information,
+but types declared in other header will not.
+The value @samp{sys} means those types satisfying @samp{base}
+or declared in system or compiler headers.
+
+You may need to experiment to determine the best settings for your application.
+
+The default is @samp{-femit-struct-debug-detailed=all}.
+
+This option works only with DWARF 2.
+
 @cindex @command{prof}
 @item -p
 @opindex p

Modified: head/contrib/gcc/dwarf2out.c
==============================================================================
--- head/contrib/gcc/dwarf2out.c	Sat Nov 16 01:07:02 2013	(r258205)
+++ head/contrib/gcc/dwarf2out.c	Sat Nov 16 01:16:24 2013	(r258206)
@@ -4215,7 +4215,8 @@ static void gen_ptr_to_mbr_type_die (tre
 static dw_die_ref gen_compile_unit_die (const char *);
 static void gen_inheritance_die (tree, tree, dw_die_ref);
 static void gen_member_die (tree, dw_die_ref);
-static void gen_struct_or_union_type_die (tree, dw_die_ref);
+static void gen_struct_or_union_type_die (tree, dw_die_ref,
+						enum debug_info_usage);
 static void gen_subroutine_type_die (tree, dw_die_ref);
 static void gen_typedef_die (tree, dw_die_ref);
 static void gen_type_die (tree, dw_die_ref);
@@ -12473,7 +12474,8 @@ gen_member_die (tree type, dw_die_ref co
    member DIEs needed by later specification DIEs.  */
 
 static void
-gen_struct_or_union_type_die (tree type, dw_die_ref context_die)
+gen_struct_or_union_type_die (tree type, dw_die_ref context_die,
+				enum debug_info_usage usage)
 {
   dw_die_ref type_die = lookup_type_die (type);
   dw_die_ref scope_die = 0;
@@ -12482,6 +12484,7 @@ gen_struct_or_union_type_die (tree type,
 		  && (! TYPE_STUB_DECL (type)
 		      || ! TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))));
   int ns_decl = (context_die && context_die->die_tag == DW_TAG_namespace);
+  complete = complete && should_emit_struct_debug (type, usage);
 
   if (type_die && ! complete)
     return;
@@ -12609,7 +12612,8 @@ gen_typedef_die (tree decl, dw_die_ref c
 /* Generate a type description DIE.  */
 
 static void
-gen_type_die (tree type, dw_die_ref context_die)
+gen_type_die_with_usage (tree type, dw_die_ref context_die,
+				enum debug_info_usage usage)
 {
   int need_pop;
 
@@ -12657,16 +12661,19 @@ gen_type_die (tree type, dw_die_ref cont
 
       /* For these types, all that is required is that we output a DIE (or a
 	 set of DIEs) to represent the "basis" type.  */
-      gen_type_die (TREE_TYPE (type), context_die);
+      gen_type_die_with_usage (TREE_TYPE (type), context_die,
+				DINFO_USAGE_IND_USE);
       break;
 
     case OFFSET_TYPE:
       /* This code is used for C++ pointer-to-data-member types.
 	 Output a description of the relevant class type.  */
-      gen_type_die (TYPE_OFFSET_BASETYPE (type), context_die);
+      gen_type_die_with_usage (TYPE_OFFSET_BASETYPE (type), context_die,
+					DINFO_USAGE_IND_USE);
 
       /* Output a description of the type of the object pointed to.  */
-      gen_type_die (TREE_TYPE (type), context_die);
+      gen_type_die_with_usage (TREE_TYPE (type), context_die,
+					DINFO_USAGE_IND_USE);
 
       /* Now output a DIE to represent this pointer-to-data-member type
 	 itself.  */
@@ -12675,13 +12682,15 @@ gen_type_die (tree type, dw_die_ref cont
 
     case FUNCTION_TYPE:
       /* Force out return type (in case it wasn't forced out already).  */
-      gen_type_die (TREE_TYPE (type), context_die);
+      gen_type_die_with_usage (TREE_TYPE (type), context_die,
+					DINFO_USAGE_DIR_USE);
       gen_subroutine_type_die (type, context_die);
       break;
 
     case METHOD_TYPE:
       /* Force out return type (in case it wasn't forced out already).  */
-      gen_type_die (TREE_TYPE (type), context_die);
+      gen_type_die_with_usage (TREE_TYPE (type), context_die,
+					DINFO_USAGE_DIR_USE);
       gen_subroutine_type_die (type, context_die);
       break;
 
@@ -12707,7 +12716,7 @@ gen_type_die (tree type, dw_die_ref cont
 	  && AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
 	  && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
 	{
-	  gen_type_die (TYPE_CONTEXT (type), context_die);
+	  gen_type_die_with_usage (TYPE_CONTEXT (type), context_die, usage);
 
 	  if (TREE_ASM_WRITTEN (type))
 	    return;
@@ -12731,7 +12740,7 @@ gen_type_die (tree type, dw_die_ref cont
 	    gen_enumeration_type_die (type, context_die);
 	}
       else
-	gen_struct_or_union_type_die (type, context_die);
+	gen_struct_or_union_type_die (type, context_die, usage);
 
       if (need_pop)
 	pop_decl_scope ();
@@ -12760,6 +12769,12 @@ gen_type_die (tree type, dw_die_ref cont
   TREE_ASM_WRITTEN (type) = 1;
 }
 
+static void
+gen_type_die (tree type, dw_die_ref context_die)
+{
+  gen_type_die_with_usage (type, context_die, DINFO_USAGE_DIR_USE);
+}
+
 /* Generate a DIE for a tagged type instantiation.  */
 
 static void
@@ -13357,7 +13372,11 @@ dwarf2out_imported_module_or_decl (tree 
   if (!context)
     scope_die = comp_unit_die;
   else if (TYPE_P (context))
+    {
+      if (!should_emit_struct_debug (context, DINFO_USAGE_DIR_USE))
+	return;
     scope_die = force_type_die (context);
+    }
   else
     scope_die = force_decl_die (context);
 
@@ -13383,7 +13402,12 @@ dwarf2out_imported_module_or_decl (tree 
 
 	      if (TYPE_CONTEXT (type))
 		if (TYPE_P (TYPE_CONTEXT (type)))
+		  {
+		    if (!should_emit_struct_debug (TYPE_CONTEXT (type),
+						   DINFO_USAGE_DIR_USE))
+		      return;
 		  type_context_die = force_type_die (TYPE_CONTEXT (type));
+		  }
 	      else
 		type_context_die = force_decl_die (TYPE_CONTEXT (type));
 	      else

Modified: head/contrib/gcc/flags.h
==============================================================================
--- head/contrib/gcc/flags.h	Sat Nov 16 01:07:02 2013	(r258205)
+++ head/contrib/gcc/flags.h	Sat Nov 16 01:16:24 2013	(r258206)
@@ -23,6 +23,7 @@ Software Foundation, 51 Franklin Street,
 #ifndef GCC_FLAGS_H
 #define GCC_FLAGS_H
 
+#include "coretypes.h"
 #include "options.h"
 
 enum debug_info_type
@@ -54,6 +55,25 @@ enum debug_info_level
 /* Specify how much debugging info to generate.  */
 extern enum debug_info_level debug_info_level;
 
+/* 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 function determines whether or not debug information
+   should be generated for a given struct.  The indirect parameter
+   indicates that the struct is being handled indirectly, via
+   a pointer.  See opts.c for the implementation. */
+
+enum debug_info_usage
+{
+  DINFO_USAGE_DFN,	/* A struct definition. */
+  DINFO_USAGE_DIR_USE,	/* A direct use, such as the type of a variable. */
+  DINFO_USAGE_IND_USE,	/* An indirect use, such as through a pointer. */
+  DINFO_USAGE_NUM_ENUMS	/* The number of enumerators. */
+};
+
+extern bool should_emit_struct_debug (tree type_decl, enum debug_info_usage);
+extern void set_struct_debug_option (const char *value);
+
 /* Nonzero means use GNU-only extensions in the generated symbolic
    debugging information.  */
 extern bool use_gnu_debug_info_extensions;

Modified: head/contrib/gcc/langhooks-def.h
==============================================================================
--- head/contrib/gcc/langhooks-def.h	Sat Nov 16 01:07:02 2013	(r258205)
+++ head/contrib/gcc/langhooks-def.h	Sat Nov 16 01:16:24 2013	(r258206)
@@ -217,6 +217,7 @@ extern tree lhd_make_node (enum tree_cod
    so we create a compile-time error instead.  */
 #define LANG_HOOKS_MAKE_TYPE lhd_make_node
 #define LANG_HOOKS_INCOMPLETE_TYPE_ERROR lhd_incomplete_type_error
+#define LANG_HOOKS_GENERIC_TYPE_P	hook_bool_tree_false
 #define LANG_HOOKS_TYPE_PROMOTES_TO lhd_type_promotes_to
 #define LANG_HOOKS_REGISTER_BUILTIN_TYPE lhd_register_builtin_type
 #define LANG_HOOKS_TYPE_MAX_SIZE	lhd_return_null_tree
@@ -231,6 +232,7 @@ extern tree lhd_make_node (enum tree_cod
   LANG_HOOKS_UNSIGNED_TYPE, \
   LANG_HOOKS_SIGNED_TYPE, \
   LANG_HOOKS_SIGNED_OR_UNSIGNED_TYPE, \
+  LANG_HOOKS_GENERIC_TYPE_P, \
   LANG_HOOKS_TYPE_PROMOTES_TO, \
   LANG_HOOKS_REGISTER_BUILTIN_TYPE, \
   LANG_HOOKS_INCOMPLETE_TYPE_ERROR, \

Modified: head/contrib/gcc/langhooks.h
==============================================================================
--- head/contrib/gcc/langhooks.h	Sat Nov 16 01:07:02 2013	(r258205)
+++ head/contrib/gcc/langhooks.h	Sat Nov 16 01:16:24 2013	(r258206)
@@ -119,6 +119,10 @@ struct lang_hooks_for_types
      according to UNSIGNEDP.  */
   tree (*signed_or_unsigned_type) (int, tree);
 
+  /* True if the type is an instantiation of a generic type,
+     e.g. C++ template implicit specializations.  */
+  bool (*generic_p) (tree);
+
   /* Given a type, apply default promotions to unnamed function
      arguments and return the new type.  Return the same type if no
      change.  Required by any language that supports variadic

Modified: head/contrib/gcc/opts.c
==============================================================================
--- head/contrib/gcc/opts.c	Sat Nov 16 01:07:02 2013	(r258205)
+++ head/contrib/gcc/opts.c	Sat Nov 16 01:16:24 2013	(r258206)
@@ -79,6 +79,256 @@ 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 thet 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 };
+
+/* Parse the -femit-struct-debug-detailed option value
+   and set the flag variables. */
+
+#define MATCH( prefix, string ) \
+  ((strncmp (prefix, string, sizeof prefix - 1) == 0) \
+   ? ((string += sizeof prefix - 1), 1) : 0)
+
+void
+set_struct_debug_option (const char *spec)
+{
+  /* various labels for comparison */
+  static char dfn_lbl[] = "dfn:", dir_lbl[] = "dir:", ind_lbl[] = "ind:";
+  static char ord_lbl[] = "ord:", gen_lbl[] = "gen:";
+  static char none_lbl[] = "none", any_lbl[] = "any";
+  static char base_lbl[] = "base", sys_lbl[] = "sys";
+
+  enum debug_struct_file files = DINFO_STRUCT_FILE_ANY;
+  /* Default is to apply to as much as possible. */
+  enum debug_info_usage usage = DINFO_USAGE_NUM_ENUMS;
+  int ord = 1, gen = 1;
+
+  /* What usage? */
+  if (MATCH (dfn_lbl, spec))
+    usage = DINFO_USAGE_DFN;
+  else if (MATCH (dir_lbl, spec))
+    usage = DINFO_USAGE_DIR_USE;
+  else if (MATCH (ind_lbl, spec))
+    usage = DINFO_USAGE_IND_USE;
+
+  /* Generics or not? */
+  if (MATCH (ord_lbl, spec))
+    gen = 0;
+  else if (MATCH (gen_lbl, spec))
+    ord = 0;
+
+  /* What allowable environment? */
+  if (MATCH (none_lbl, spec))
+    files = DINFO_STRUCT_FILE_NONE;
+  else if (MATCH (any_lbl, spec))
+    files = DINFO_STRUCT_FILE_ANY;
+  else if (MATCH (sys_lbl, spec))
+    files = DINFO_STRUCT_FILE_SYS;
+  else if (MATCH (base_lbl, spec))
+    files = DINFO_STRUCT_FILE_BASE;
+  else
+    error ("argument %qs to %<-femit-struct-debug-detailed%> not recognized",
+           spec);
+
+  /* Effect the specification. */
+  if (usage == DINFO_USAGE_NUM_ENUMS)
+    {
+      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;
+        }
+      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;
+        }
+    }
+  else
+    {
+      if (ord)
+        debug_struct_ordinary[usage] = files;
+      if (gen)
+        debug_struct_generic[usage] = files;
+    }
+
+  if (*spec == ',')
+    set_struct_debug_option (spec+1);
+  else
+    {
+      /* No more -femit-struct-debug-detailed specifications.
+         Do final checks. */
+      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])
+	error ("%<-femit-struct-debug-detailed=dir:...%> must allow at least"
+               " as much as %<-femit-struct-debug-detailed=ind:...%>");
+    }
+}
+
+/* Find the base name of a path, stripping off both directories and
+   a single final extension. */
+static int
+base_of_path (const char *path, const char **base_out)
+{
+  const char *base = path;
+  const char *dot = 0;
+  const char *p = path;
+  char c = *p;
+  while (c)
+    {
+      if (IS_DIR_SEPARATOR(c))
+        {
+          base = p + 1;
+          dot = 0;
+        }
+      else if (c == '.')
+        dot = p;
+      c = *++p;
+    }
+  if (!dot)
+    dot = p;
+  *base_out = base;
+  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.  */
@@ -370,7 +620,11 @@ handle_options (unsigned int argc, const
       if (opt[0] != '-' || opt[1] == '\0')
 	{
 	  if (main_input_filename == NULL)
+	    {
 	    main_input_filename = opt;
+	      main_input_baselength
+		= base_of_path (main_input_filename, &main_input_basename);
+	    }
 	  add_input_filename (opt);
 	  n = 1;
 	  continue;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201311160116.rAG1GOgR066904>