public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [patch 10/10] debug-early merge: compiler proper
@ 2015-05-08  0:41 Aldy Hernandez
  2015-05-18 11:06 ` Richard Biener
  0 siblings, 1 reply; 34+ messages in thread
From: Aldy Hernandez @ 2015-05-08  0:41 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 15 bytes --]

As seen on TV.

[-- Attachment #2: dearly-rest.patch --]
[-- Type: text/x-patch, Size: 96866 bytes --]

gcc/

	* dwarf2out.c: Remove deferred_locations*.
	(dwarf2_debug_hooks): Add early_finish hook.
	Remove global_decl hook.
	Add early_global_decl and late_global_decl hook.
	Add dumped_early bit to die_struct.
	New global early_dwarf_dumping.
	(struct limbo_die_struct): Document created_for field.
	Remove file_table_last_lookup.
	(remove_AT): Return TRUE if successful.
	(remove_child_TAG): Clear die_parent.
	(reparent_child): New function abstracted from...
	(splice_child_die): ...here.
	(new_die): Set dumped_early field if appropriate.
	ICE if a DIE ends up in limbo too late.
	(print_die): Display "(DUMPED EARLY)" if appropriate.
	(check_die): New.
	(defer_location): Remove.
	(add_subscript_info): Reuse DW_TAG_subrange_type if available.
	(fill_variable_array_bounds): New.
	(decl_start_label): Call fill_variable_array_bounds.
	(gen_formal_parameter_die): Rewrite to reuse previously generated
	DIEs.
	(gen_subprogram_die): Same.
	(gen_variable_die): Same.
	(gen_const_die): Same.
	(gen_label_die): Same.
	(gen_lexical_block_die): Same.
	(decl_will_get_specification_p): New.
	(local_function_static): New.
	(gen_struct_or_union_type_die): Fill in variable-length fields.
	(gen_typedef_die): Fill in variable-length typedefs.
	(gen_tagged_type_die): Gracefully return on error_mark_node.
	Handle re-entrancy.
	(gen_type_die_with_usage): Handle variable-length types.
	Remove duplicate code for ARRAY_TYPE case.
	(process_scope_var): Only process imported modules during early
	dwarf.
	(dwarf2out_early_global_decl): New.
	(dwarf2out_late_global_decl): Rename from dwarf2out_global_decl.
	(dwarf2out_type_decl): Set early_dwarf_dumping while calling
	dwarf2out_decl.
	(dwarf2out_decl): Verify that we did not recreate a previously
	generated DIE.
	Do not return on DECL_EXTERNALs in VAR_DECLs.
	Abstract some code to local_function_static.
	(lookup_filename): Remove use of file_table_last_lookup.
	Gracefully exit on missing file_name.
	(dwarf2out_finish): Verify limbo list.
	Remove deferred_locations_list use.
	Move deferred_asm_name and limbo flushing to...
	(dwarf2out_early_finish): ...here.  New.
	(dwarf2out_c_finalize): Remove set of deferred_location_list,
	deferred_asm_name, and file_table_last_lookup.
	* cgraph.h (referred_to_p): Add default argument.
	* cgraphunit.c (referred_to_p): Add and handle include_self
	argument.
	(analyze_functions): Add first_time argument.
	Call check_global_declaration for all symbols.
	Call late_global_decl for nodes for moribund nodes.
	(finalize_compilation_unit): Add new argument to
	analyze_functions.
	Call early_global_decl for functions.
	Call early_finish debug hook.
	* dbxout.c (dbxout_early_global_decl): New.
	(dbxout_late_global_decl): New.  Adapted from dbxout_global_decl.
	(dbx_debug_hooks): Add new hooks.
	(xcoff_debug_hooks): Same.
	* debug.c (do_nothing_debug_hooks): Add early_finish field.
	Add early and late debug hooks.
	Remove global_decl hook.
	* debug.h (struct gcc_debug_hooks): Add early_finish,
	early_global_decl, and late_global_decl fields.
	Remove global_decl field.
	Document gcc_debug_hooks.
	* gengtype.c (output_typename): Mark function as unused.
	* godump.c (go_early_global_decl): New.
	(go_late_global_decl): New.
	(go_global_decl): Remove.
	(dump_go_spec_init): Remove global_decl.  Add
	{early,late}_global_decl.
	* langhooks-def.h (LANG_HOOKS_WRITE_GLOBALS): Remove.
	(LANG_HOOKS_POST_COMPILATION_PARSING_CLEANUPS): New.
	* langhooks.c (lhd_warn_unused_global_decl): Adjust comment.
	(write_global_declarations): Remove.
	(global_decl_processing): New.
	* langhooks.h (struct lang_hooks_for_decls): Remove
	final_write_globals field.
	Add post_compilation_parsing_cleanups field.
	* passes.c (rest_of_decl_compilation): Call early_global_decl.
	* sdbout.c: Add early and late_global_decl hooks.  Remove
	sdbout_global_decl hook.
	Add early_finish field for sdb_debug_hooks.
	(sdbout_global_decl): Remove.
	(sdbout_early_global_decl): New.
	(sdbout_late_global_decl): New.
	* timevar.def (TV_PHASE_LATE_PARSING_CLEANUPS): New.
	* toplev.c (check_global_declaration): Rename from
	check_global_declaration_1.
	Adapt to use symtab infrastructure.
	(check_global_declarations): Remove.
	(emit_debug_global_declarations): Rename global_decl to
	late_global_decl.
	(compile_file): Remove call to final_write_globals langhook.
	Run the actual compilation process.
	Perform any post compilation parser cleanups.
	Generate late debug info.
	* toplev.h (check_global_declaration): New.
	(check_global_declaration_1): Remove.
	(check_global_declarations): Remove.
	(write_global_declarations): Remove.
	(global_decl_processing): New.
	* tree-core.h (struct tree_block): Add DIE field.
	* tree.h (BLOCK_DIE): New.
	* vmsdbgout.c (vmsdbgout_global_decl): Remove function and its use
	throughout.
	(vmsdbgout_early_global_decl): New.
	(vmsdbgout_late_global_decl): New.
	Add early_finish debug hook field to vmsdbg_debug_hooks.
	Remove vmsdbgout_decl to vmsdbgout_function_decl.
	Add early and late_global_decl debug hooks.

diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 108cc80..55864a2 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -314,7 +314,7 @@ public:
   bool needed_p (void);
 
   /* Return true when there are references to the node.  */
-  bool referred_to_p (void);
+  bool referred_to_p (bool include_self = true);
 
   /* Return true if NODE can be discarded by linker from the binary.  */
   inline bool
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 0a50f61..faa953a 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -406,10 +406,11 @@ cgraph_node::reset (void)
   remove_all_references ();
 }
 
-/* Return true when there are references to the node.  */
+/* Return true when there are references to the node.  INCLUDE_SELF is
+   true if a self reference counts as a reference.  */
 
 bool
-symtab_node::referred_to_p (void)
+symtab_node::referred_to_p (bool include_self)
 {
   ipa_ref *ref = NULL;
 
@@ -419,7 +420,13 @@ symtab_node::referred_to_p (void)
   /* For functions check also calls.  */
   cgraph_node *cn = dyn_cast <cgraph_node *> (this);
   if (cn && cn->callers)
-    return true;
+    {
+      if (include_self)
+	return true;
+      for (cgraph_edge *e = cn->callers; e; e = e->next_caller)
+	if (e->caller != this)
+	  return true;
+    }
   return false;
 }
 
@@ -928,8 +935,12 @@ walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
 static cgraph_node *first_analyzed;
 static varpool_node *first_analyzed_var;
 
+/* FIRST_TIME is set to TRUE for the first time we are called for a
+   translation unit from finalize_compilation_unit() or false
+   otherwise.  */
+
 static void
-analyze_functions (void)
+analyze_functions (bool first_time)
 {
   /* Keep track of already processed nodes when called multiple times for
      intermodule optimization.  */
@@ -1101,6 +1112,13 @@ analyze_functions (void)
       symtab_node::dump_table (symtab->dump_file);
     }
 
+  if (first_time)
+    {
+      symtab_node *snode;
+      FOR_EACH_SYMBOL (snode)
+	check_global_declaration (snode->decl);
+    }
+
   if (symtab->dump_file)
     fprintf (symtab->dump_file, "\nRemoving unused symbols:");
 
@@ -1113,6 +1131,19 @@ analyze_functions (void)
 	{
 	  if (symtab->dump_file)
 	    fprintf (symtab->dump_file, " %s", node->name ());
+
+	  /* See if the debugger can use anything before the DECL
+	     passes away.  Perhaps it can notice a DECL that is now a
+	     constant and can tag the early DIE with an appropriate
+	     attribute.
+
+	     Otherwise, this is the last chance the debug_hooks have
+	     at looking at optimized away DECLs, since
+	     late_global_decl will subsequently be called from the
+	     contents of the now pruned symbol table.  */
+	  if (!decl_function_context (node->decl))
+	    (*debug_hooks->late_global_decl) (node->decl);
+
 	  node->remove ();
 	  continue;
 	}
@@ -2449,13 +2480,24 @@ symbol_table::finalize_compilation_unit (void)
 
   /* Gimplify and lower all functions, compute reachability and
      remove unreachable nodes.  */
-  analyze_functions ();
+  analyze_functions (/*first_time=*/true);
 
   /* Mark alias targets necessary and emit diagnostics.  */
   handle_alias_pairs ();
 
   /* Gimplify and lower thunks.  */
-  analyze_functions ();
+  analyze_functions (/*first_time=*/false);
+
+  /* Emit early debug for reachable functions, and by consequence,
+     locally scoped symbols.  */
+  struct cgraph_node *cnode;
+  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cnode)
+    if (!decl_function_context (cnode->decl))
+      (*debug_hooks->early_global_decl) (cnode->decl);
+
+  /* Clean up anything that needs cleaning up after initial debug
+     generation.  */
+  (*debug_hooks->early_finish) ();
 
   /* Finally drive the pass manager.  */
   compile ();
diff --git a/gcc/dbxout.c b/gcc/dbxout.c
index 758c1c4..0c9a327 100644
--- a/gcc/dbxout.c
+++ b/gcc/dbxout.c
@@ -350,7 +350,8 @@ static int dbxout_symbol_location (tree, tree, const char *, rtx);
 static void dbxout_symbol_name (tree, const char *, int);
 static void dbxout_common_name (tree, const char *, stab_code_type);
 static const char *dbxout_common_check (tree, int *);
-static void dbxout_global_decl (tree);
+static void dbxout_early_global_decl (tree);
+static void dbxout_late_global_decl (tree);
 static void dbxout_type_decl (tree, int);
 static void dbxout_handle_pch (unsigned);
 static void debug_free_queue (void);
@@ -372,6 +373,7 @@ const struct gcc_debug_hooks dbx_debug_hooks =
   dbxout_init,
   dbxout_finish,
   debug_nothing_void,
+  debug_nothing_void,
   debug_nothing_int_charstar,
   debug_nothing_int_charstar,
   dbxout_start_source_file,
@@ -391,7 +393,8 @@ const struct gcc_debug_hooks dbx_debug_hooks =
 #endif
   debug_nothing_int,		         /* end_function */
   dbxout_function_decl,
-  dbxout_global_decl,		         /* global_decl */
+  dbxout_early_global_decl,		 /* early_global_decl */
+  dbxout_late_global_decl,		 /* late_global_decl */
   dbxout_type_decl,			 /* type_decl */
   debug_nothing_tree_tree_tree_bool,	 /* imported_module_or_decl */
   debug_nothing_tree,		         /* deferred_inline_function */
@@ -412,6 +415,7 @@ const struct gcc_debug_hooks xcoff_debug_hooks =
   dbxout_init,
   dbxout_finish,
   debug_nothing_void,
+  debug_nothing_void,
   debug_nothing_int_charstar,
   debug_nothing_int_charstar,
   dbxout_start_source_file,
@@ -427,7 +431,8 @@ const struct gcc_debug_hooks xcoff_debug_hooks =
   debug_nothing_tree,		         /* begin_function */
   xcoffout_end_function,
   debug_nothing_tree,		         /* function_decl */
-  dbxout_global_decl,		         /* global_decl */
+  dbxout_early_global_decl,		 /* early_global_decl */
+  dbxout_late_global_decl,		 /* late_global_decl */
   dbxout_type_decl,			 /* type_decl */
   debug_nothing_tree_tree_tree_bool,	 /* imported_module_or_decl */
   debug_nothing_tree,		         /* deferred_inline_function */
@@ -1341,10 +1346,16 @@ dbxout_function_decl (tree decl)
 
 #endif /* DBX_DEBUGGING_INFO  */
 
+static void
+dbxout_early_global_decl (tree decl ATTRIBUTE_UNUSED)
+{
+  /* NYI for non-dwarf.  */
+}
+
 /* Debug information for a global DECL.  Called from toplev.c after
    compilation proper has finished.  */
 static void
-dbxout_global_decl (tree decl)
+dbxout_late_global_decl (tree decl)
 {
   if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
     {
diff --git a/gcc/debug.c b/gcc/debug.c
index 7d18c0a..a1d154e 100644
--- a/gcc/debug.c
+++ b/gcc/debug.c
@@ -36,6 +36,7 @@ const struct gcc_debug_hooks do_nothing_debug_hooks =
 {
   debug_nothing_charstar,
   debug_nothing_charstar,
+  debug_nothing_void,			/* early_finish */
   debug_nothing_void,
   debug_nothing_int_charstar,
   debug_nothing_int_charstar,
@@ -52,7 +53,8 @@ const struct gcc_debug_hooks do_nothing_debug_hooks =
   debug_nothing_tree,		         /* begin_function */
   debug_nothing_int,		         /* end_function */
   debug_nothing_tree,		         /* function_decl */
-  debug_nothing_tree,		         /* global_decl */
+  debug_nothing_tree,	         	 /* early_global_decl */
+  debug_nothing_tree,	         	 /* late_global_decl */
   debug_nothing_tree_int,		 /* type_decl */
   debug_nothing_tree_tree_tree_bool,	 /* imported_module_or_decl */
   debug_nothing_tree,		         /* deferred_inline_function */
diff --git a/gcc/debug.h b/gcc/debug.h
index 276c887..e7e1334 100644
--- a/gcc/debug.h
+++ b/gcc/debug.h
@@ -30,6 +30,9 @@ struct gcc_debug_hooks
   /* Output debug symbols.  */
   void (* finish) (const char *main_filename);
 
+  /* Run cleanups necessary after early debug generation.  */
+  void (* early_finish) (void);
+
   /* Called from cgraph_optimize before starting to assemble
      functions/variables/toplevel asms.  */
   void (* assembly_start) (void);
@@ -89,12 +92,43 @@ struct gcc_debug_hooks
   /* Debug information for a function DECL.  This might include the
      function name (a symbol), its parameters, and the block that
      makes up the function's body, and the local variables of the
-     function.  */
+     function.
+
+     This is only called for FUNCTION_DECLs.  It is part of the late
+     debug pass and is called from rest_of_handle_final.
+
+     Location information is available at this point.
+
+     See the documentation for early_global_decl and late_global_decl
+     for other entry points into the debugging back-ends for DECLs.  */
   void (* function_decl) (tree decl);
 
-  /* Debug information for a global DECL.  Called from toplev.c after
-     compilation proper has finished.  */
-  void (* global_decl) (tree decl);
+  /* Debug information for a global DECL.  Called from the parser
+     after the parsing process has finished.
+
+     This gets called for both variables and functions.
+
+     Location information is not available at this point, but it is a
+     good probe point to get access to symbols before they get
+     optimized away.
+
+     This hook may be called on VAR_DECLs or FUNCTION_DECLs.  It is up
+     to the hook to use what it needs.  */
+  void (* early_global_decl) (tree decl);
+
+  /* Augment debug information generated by early_global_decl with
+     more complete debug info (if applicable).  Called from toplev.c
+     after the compilation proper has finished and cgraph information
+     is available.
+
+     This gets called for both variables and functions.
+
+     Location information is usually available at this point, unless
+     the hook is being called for a decl that has been optimized away.
+
+     This hook may be called on VAR_DECLs or FUNCTION_DECLs.  It is up
+     to the hook to use what it needs.  */
+  void (* late_global_decl) (tree decl);
 
   /* Debug information for a type DECL.  Called from toplev.c after
      compilation proper, also from various language front ends to
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 8d5c062..79afb97 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -1268,16 +1268,6 @@ struct GTY((for_user)) dwarf_file_data {
   int emitted_number;
 };
 
-typedef struct GTY(()) deferred_locations_struct
-{
-  tree variable;
-  dw_die_ref die;
-} deferred_locations;
-
-
-static GTY(()) vec<deferred_locations, va_gc> *deferred_locations_list;
-
-
 /* Describe an entry into the .debug_addr section.  */
 
 enum ate_kind {
@@ -2448,6 +2438,7 @@ build_cfa_aligned_loc (dw_cfa_location *cfa,
 
 static void dwarf2out_init (const char *);
 static void dwarf2out_finish (const char *);
+static void dwarf2out_early_finish (void);
 static void dwarf2out_assembly_start (void);
 static void dwarf2out_define (unsigned int, const char *);
 static void dwarf2out_undef (unsigned int, const char *);
@@ -2457,7 +2448,8 @@ static void dwarf2out_function_decl (tree);
 static void dwarf2out_begin_block (unsigned, unsigned);
 static void dwarf2out_end_block (unsigned, unsigned);
 static bool dwarf2out_ignore_block (const_tree);
-static void dwarf2out_global_decl (tree);
+static void dwarf2out_early_global_decl (tree);
+static void dwarf2out_late_global_decl (tree);
 static void dwarf2out_type_decl (tree, int);
 static void dwarf2out_imported_module_or_decl (tree, tree, tree, bool);
 static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree,
@@ -2474,6 +2466,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
 {
   dwarf2out_init,
   dwarf2out_finish,
+  dwarf2out_early_finish,
   dwarf2out_assembly_start,
   dwarf2out_define,
   dwarf2out_undef,
@@ -2495,7 +2488,8 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   dwarf2out_begin_function,
   dwarf2out_end_function,	/* end_function */
   dwarf2out_function_decl,	/* function_decl */
-  dwarf2out_global_decl,
+  dwarf2out_early_global_decl,
+  dwarf2out_late_global_decl,
   dwarf2out_type_decl,		/* type_decl */
   dwarf2out_imported_module_or_decl,
   debug_nothing_tree,		/* deferred_inline_function */
@@ -2636,10 +2630,15 @@ typedef struct GTY((chain_circular ("%h.die_sib"), for_user)) die_struct {
   /* Die is used and must not be pruned as unused.  */
   BOOL_BITFIELD die_perennial_p : 1;
   BOOL_BITFIELD comdat_type_p : 1; /* DIE has a type signature */
+  /* Die was generated early via dwarf2out_early_global_decl.  */
+  BOOL_BITFIELD dumped_early : 1;
   /* Lots of spare bits.  */
 }
 die_node;
 
+/* Set to TRUE while dwarf2out_early_global_decl is running.  */
+static bool early_dwarf_dumping;
+
 /* Evaluate 'expr' while 'c' is set to each child of DIE in order.  */
 #define FOR_EACH_CHILD(die, c, expr) do {	\
   c = die->die_child;				\
@@ -2690,9 +2689,13 @@ typedef struct GTY(()) comdat_type_struct
 }
 comdat_type_node;
 
-/* The limbo die list structure.  */
+/* A list of DIEs for which we can't determine ancestry (parent_die
+   field) just yet.  Later in dwarf2out_finish we will fill in the
+   missing bits.  */
 typedef struct GTY(()) limbo_die_struct {
   dw_die_ref die;
+  /* The tree for which this DIE was created for.  We use this to
+     determine anscestry later.  */
   tree created_for;
   struct limbo_die_struct *next;
 }
@@ -2943,7 +2946,7 @@ static GTY((length ("abbrev_die_table_allocated")))
 /* Number of elements currently allocated for abbrev_die_table.  */
 static GTY(()) unsigned abbrev_die_table_allocated;
 
-/* Number of elements in type_die_table currently in use.  */
+/* Number of elements in abbrev_die_table currently in use.  */
 static GTY(()) unsigned abbrev_die_table_in_use;
 
 /* Size (in elements) of increments by which we may expand the
@@ -3025,9 +3028,6 @@ static GTY(()) struct dwarf_file_data * last_emitted_file;
 /* Number of internal labels generated by gen_internal_sym().  */
 static GTY(()) int label_num;
 
-/* Cached result of previous call to lookup_filename.  */
-static GTY(()) struct dwarf_file_data * file_table_last_lookup;
-
 static GTY(()) vec<die_arg_entry, va_gc> *tmpl_value_parm_die_table;
 
 /* Instances of generic types for which we need to generate debug
@@ -3112,7 +3112,7 @@ static inline dw_die_ref get_AT_ref (dw_die_ref, enum dwarf_attribute);
 static bool is_cxx (void);
 static bool is_fortran (void);
 static bool is_ada (void);
-static void remove_AT (dw_die_ref, enum dwarf_attribute);
+static bool remove_AT (dw_die_ref, enum dwarf_attribute);
 static void remove_child_TAG (dw_die_ref, enum dwarf_tag);
 static void add_child_die (dw_die_ref, dw_die_ref);
 static dw_die_ref new_die (enum dwarf_tag, dw_die_ref, tree);
@@ -4752,16 +4752,17 @@ is_ada (void)
   return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83;
 }
 
-/* Remove the specified attribute if present.  */
+/* Remove the specified attribute if present.  Return TRUE if removal
+   was successful.  */
 
-static void
+static bool
 remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
 {
   dw_attr_ref a;
   unsigned ix;
 
   if (! die)
-    return;
+    return false;
 
   FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
     if (a->dw_attr == attr_kind)
@@ -4773,8 +4774,9 @@ remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
 	/* vec::ordered_remove should help reduce the number of abbrevs
 	   that are needed.  */
 	die->die_attr->ordered_remove (ix);
-	return;
+	return true;
       }
+  return false;
 }
 
 /* Remove CHILD from its parent.  PREV must have the property that
@@ -4848,6 +4850,7 @@ remove_child_TAG (dw_die_ref die, enum dwarf_tag tag)
     while (c->die_tag == tag)
       {
 	remove_child_with_prev (c, prev);
+	c->die_parent = NULL;
 	/* Might have removed every child.  */
 	if (c == c->die_sib)
 	  return;
@@ -4877,6 +4880,21 @@ add_child_die (dw_die_ref die, dw_die_ref child_die)
   die->die_child = child_die;
 }
 
+/* Unassociate CHILD from its parent, and make its parent be
+   NEW_PARENT.  */
+
+static void
+reparent_child (dw_die_ref child, dw_die_ref new_parent)
+{
+  for (dw_die_ref p = child->die_parent->die_child; ; p = p->die_sib)
+    if (p->die_sib == child)
+      {
+	remove_child_with_prev (child, p);
+	break;
+      }
+  add_child_die (new_parent, child);
+}
+
 /* Move CHILD, which must be a child of PARENT or the DIE for which PARENT
    is the specification, to the end of PARENT's list of children.
    This is done by removing and re-adding it.  */
@@ -4884,8 +4902,6 @@ add_child_die (dw_die_ref die, dw_die_ref child_die)
 static void
 splice_child_die (dw_die_ref parent, dw_die_ref child)
 {
-  dw_die_ref p;
-
   /* We want the declaration DIE from inside the class, not the
      specification DIE at toplevel.  */
   if (child->die_parent != parent)
@@ -4900,17 +4916,13 @@ splice_child_die (dw_die_ref parent, dw_die_ref child)
 	      || (child->die_parent
 		  == get_AT_ref (parent, DW_AT_specification)));
 
-  for (p = child->die_parent->die_child; ; p = p->die_sib)
-    if (p->die_sib == child)
-      {
-	remove_child_with_prev (child, p);
-	break;
-      }
-
-  add_child_die (parent, child);
+  reparent_child (child, parent);
 }
 
-/* Return a pointer to a newly created DIE node.  */
+/* Create and return a new die with a parent of PARENT_DIE.  If
+   PARENT_DIE is NULL, the new DIE is placed in limbo and an
+   associated tree T must be supplied to determine parenthood
+   later.  */
 
 static inline dw_die_ref
 new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
@@ -4919,12 +4931,36 @@ new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
 
   die->die_tag = tag_value;
 
+  if (early_dwarf_dumping)
+    die->dumped_early = true;
+
   if (parent_die != NULL)
     add_child_die (parent_die, die);
   else
     {
       limbo_die_node *limbo_node;
 
+      /* No DIEs created after early dwarf should end up in limbo,
+	 because the limbo list should not persist past LTO
+	 streaming.  */
+      if (tag_value != DW_TAG_compile_unit
+	  && tag_value != DW_TAG_type_unit
+	  && !early_dwarf_dumping
+	  /* Allow nested functions to live in limbo because they will
+	     only temporarily live there, as decls_for_scope will fix
+	     them up.  */
+	  && (TREE_CODE (t) != FUNCTION_DECL
+	      || !decl_function_context (t))
+	  /* FIXME debug-early: Allow late limbo DIE creation for LTO,
+	     especially in the ltrans stage, but once we implement LTO
+	     dwarf streaming, we should remove this exception.  */
+	  && !in_lto_p)
+	{
+	  fprintf (stderr, "symbol ended up in limbo too late:");
+	  debug_generic_stmt (t);
+	  gcc_unreachable ();
+	}
+
       limbo_node = ggc_cleared_alloc<limbo_die_node> ();
       limbo_node->die = die;
       limbo_node->created_for = t;
@@ -5580,9 +5616,18 @@ print_die (dw_die_ref die, FILE *outfile)
   unsigned ix;
 
   print_spaces (outfile);
-  fprintf (outfile, "DIE %4ld: %s (%p)\n",
+  fprintf (outfile, "DIE %4ld: %s (%p)",
 	   die->die_offset, dwarf_tag_name (die->die_tag),
 	   (void*) die);
+  if (die->dumped_early)
+    {
+      fprintf (outfile, " (DUMPED EARLY");
+      const char *name = get_AT_string (die, DW_AT_name);
+      if (name)
+	fprintf (outfile, ": %s", name);
+      fputc (')', outfile);
+    }
+  fputc ('\n', outfile);
   print_spaces (outfile);
   fprintf (outfile, "  abbrev id: %lu", die->die_abbrev);
   fprintf (outfile, " offset: %ld", die->die_offset);
@@ -5656,6 +5701,34 @@ debug_dwarf (void)
   print_indent = 0;
   print_die (comp_unit_die (), stderr);
 }
+
+/* Sanity checks on DIEs.  */
+
+static void
+check_die (dw_die_ref die)
+{
+  /* A debugging information entry that is a member of an abstract
+     instance tree [that has DW_AT_inline] should not contain any
+     attributes which describe aspects of the subroutine which vary
+     between distinct inlined expansions or distinct out-of-line
+     expansions.  */
+  unsigned ix;
+  dw_attr_ref a;
+  bool inline_found = false;
+  FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+    if (a->dw_attr == DW_AT_inline && a->dw_attr_val.v.val_unsigned)
+      inline_found = true;
+  if (inline_found)
+    {
+      /* Catch the most common mistakes.  */
+      FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+	gcc_assert (a->dw_attr != DW_AT_low_pc
+		    && a->dw_attr != DW_AT_high_pc
+		    && a->dw_attr != DW_AT_location
+		    && a->dw_attr != DW_AT_frame_base
+		    && a->dw_attr != DW_AT_GNU_all_call_sites);
+    }
+}
 \f
 /* Start a new compilation unit DIE for an include file.  OLD_UNIT is the CU
    for the enclosing include file, if any.  BINCL_DIE is the DW_TAG_GNU_BINCL
@@ -16110,17 +16183,6 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, bool cache_p,
   return tree_add_const_value_attribute_for_decl (die, decl);
 }
 
-/* Add VARIABLE and DIE into deferred locations list.  */
-
-static void
-defer_location (tree variable, dw_die_ref die)
-{
-  deferred_locations entry;
-  entry.variable = variable;
-  entry.die = die;
-  vec_safe_push (deferred_locations_list, entry);
-}
-
 /* Helper function for tree_add_const_value_attribute.  Natively encode
    initializer INIT into an array.  Return true if successful.  */
 
@@ -16802,14 +16864,17 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr,
 /* Add subscript info to TYPE_DIE, describing an array TYPE, collapsing
    possibly nested array subscripts in a flat sequence if COLLAPSE_P is true.
    Note that the block of subscript information for an array type also
-   includes information about the element type of the given array type.  */
+   includes information about the element type of the given array type.
+
+   This function reuses previously set type and bound information if
+   available.  */
 
 static void
 add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
 {
   unsigned dimension_number;
   tree lower, upper;
-  dw_die_ref subrange_die;
+  dw_die_ref child = type_die->die_child;
 
   for (dimension_number = 0;
        TREE_CODE (type) == ARRAY_TYPE && (dimension_number == 0 || collapse_p);
@@ -16823,7 +16888,37 @@ add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
       /* Arrays come in three flavors: Unspecified bounds, fixed bounds,
 	 and (in GNU C only) variable bounds.  Handle all three forms
 	 here.  */
-      subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
+
+      /* Find and reuse a previously generated DW_TAG_subrange_type if
+	 available.
+
+         For multi-dimensional arrays, as we iterate through the
+         various dimensions in the enclosing for loop above, we also
+         iterate through the DIE children and pick at each
+         DW_TAG_subrange_type previously generated (if available).
+         Each child DW_TAG_subrange_type DIE describes the range of
+         the current dimension.  At this point we should have as many
+         DW_TAG_subrange_type's as we have dimensions in the
+         array.  */
+      dw_die_ref subrange_die = NULL;
+      if (child)
+	while (1)
+	  {
+	    child = child->die_sib;
+	    if (child->die_tag == DW_TAG_subrange_type)
+	      subrange_die = child;
+	    if (child == type_die->die_child)
+	      {
+		/* If we wrapped around, stop looking next time.  */
+		child = NULL;
+		break;
+	      }
+	    if (child->die_tag == DW_TAG_subrange_type)
+	      break;
+	  }
+      if (!subrange_die)
+	subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
+
       if (domain)
 	{
 	  /* We have an array type with specified bounds.  */
@@ -16831,7 +16926,8 @@ add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
 	  upper = TYPE_MAX_VALUE (domain);
 
 	  /* Define the index type.  */
-	  if (TREE_TYPE (domain))
+	  if (TREE_TYPE (domain)
+	      && !get_AT (subrange_die, DW_AT_type))
 	    {
 	      /* ??? This is probably an Ada unnamed subrange type.  Ignore the
 		 TREE_TYPE field.  We can't emit debug info for this
@@ -16853,8 +16949,9 @@ add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
 	     to produce useful results, go ahead and output the lower
 	     bound solo, and hope the debugger can cope.  */
 
-	  add_bound_info (subrange_die, DW_AT_lower_bound, lower, NULL);
-	  if (upper)
+	  if (!get_AT (subrange_die, DW_AT_lower_bound))
+	    add_bound_info (subrange_die, DW_AT_lower_bound, lower, NULL);
+	  if (upper && !get_AT (subrange_die, DW_AT_upper_bound))
 	    add_bound_info (subrange_die, DW_AT_upper_bound, upper, NULL);
 	}
 
@@ -17481,6 +17578,26 @@ decl_start_label (tree decl)
 }
 #endif
 \f
+/* For variable-length arrays that have been previously generated, but
+   may be incomplete due to missing subscript info, fill the subscript
+   info.  Return TRUE if this is one of those cases.  */
+static bool
+fill_variable_array_bounds (tree type)
+{
+  if (TREE_ASM_WRITTEN (type)
+      && TREE_CODE (type) == ARRAY_TYPE
+      && TYPE_SIZE (type)
+      && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+    {
+      dw_die_ref array_die = lookup_type_die (type);
+      if (!array_die)
+	return false;
+      add_subscript_info (array_die, type, !is_ada ());
+      return true;
+    }
+  return false;
+}
+
 /* These routines generate the internal representation of the DIE's for
    the compilation unit.  Debugging information is collected by walking
    the declaration trees passed in from dwarf2out_decl().  */
@@ -17488,7 +17605,6 @@ decl_start_label (tree decl)
 static void
 gen_array_type_die (tree type, dw_die_ref context_die)
 {
-  dw_die_ref scope_die = scope_die_for (type, context_die);
   dw_die_ref array_die;
 
   /* GNU compilers represent multidimensional array types as sequences of one
@@ -17502,6 +17618,11 @@ gen_array_type_die (tree type, dw_die_ref context_die)
      flexibilty wrt arrays of variable size.  */
 
   bool collapse_nested_arrays = !is_ada ();
+
+  if (fill_variable_array_bounds (type))
+    return;
+
+  dw_die_ref scope_die = scope_die_for (type, context_die);
   tree element_type;
 
   /* Emit DW_TAG_string_type for Fortran character types (with kind 1 only, as
@@ -17857,8 +17978,64 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
 {
   tree node_or_origin = node ? node : origin;
   tree ultimate_origin;
-  dw_die_ref parm_die
-    = new_die (DW_TAG_formal_parameter, context_die, node);
+  dw_die_ref parm_die = NULL;
+  
+  if (TREE_CODE_CLASS (TREE_CODE (node_or_origin)) == tcc_declaration)
+    {
+      parm_die = lookup_decl_die (node);
+
+      /* If the contexts differ, we may not be talking about the same
+	 thing.  */
+      if (parm_die && parm_die->die_parent != context_die)
+	{
+	  if (!DECL_ABSTRACT_P (node))
+	    {
+	      /* This can happen when creating an inlined instance, in
+		 which case we need to create a new DIE that will get
+		 annotated with DW_AT_abstract_origin.  */
+	      parm_die = NULL;
+	    }
+	  else
+	    {
+	      /* Reuse DIE even with a differing context.
+
+		 This happens when called through
+		 dwarf2out_abstract_function for formal parameter
+		 packs.  */
+	      gcc_assert (parm_die->die_parent->die_tag
+			  == DW_TAG_GNU_formal_parameter_pack);
+	    }
+	}
+
+      if (parm_die && parm_die->die_parent == NULL)
+	{
+	  /* Check that parm_die already has the right attributes that
+	     we would have added below.  If any attributes are
+	     missing, fall through to add them.  */
+	  if (! DECL_ABSTRACT_P (node_or_origin)
+	      && !get_AT (parm_die, DW_AT_location)
+	      && !get_AT (parm_die, DW_AT_const_value))
+	    /* We are missing  location info, and are about to add it.  */
+	    ;
+	  else
+	    {
+	      add_child_die (context_die, parm_die);
+	      return parm_die;
+	    }
+	}
+    }
+
+  /* If we have a previously generated DIE, use it, unless this is an
+     concrete instance (origin != NULL), in which case we need a new
+     DIE with a corresponding DW_AT_abstract_origin.  */
+  bool reusing_die;
+  if (parm_die && origin == NULL)
+    reusing_die = true;
+  else
+    {
+      parm_die = new_die (DW_TAG_formal_parameter, context_die, node);
+      reusing_die = false;
+    }
 
   switch (TREE_CODE_CLASS (TREE_CODE (node_or_origin)))
     {
@@ -17866,6 +18043,10 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
       ultimate_origin = decl_ultimate_origin (node_or_origin);
       if (node || ultimate_origin)
 	origin = ultimate_origin;
+
+      if (reusing_die)
+	goto add_location;
+
       if (origin != NULL)
 	add_abstract_origin_attribute (parm_die, origin);
       else if (emit_name_p)
@@ -17885,6 +18066,7 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
 				decl_quals (node_or_origin),
 				context_die);
 	}
+    add_location:
       if (origin == NULL && DECL_ARTIFICIAL (node))
 	add_AT_flag (parm_die, DW_AT_artificial, 1);
 
@@ -18399,26 +18581,94 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 {
   tree origin = decl_ultimate_origin (decl);
   dw_die_ref subr_die;
-  tree outer_scope;
   dw_die_ref old_die = lookup_decl_die (decl);
+
+  /* This function gets called multiple times for different stages of
+     the debug process.  For example, for func() in this code:
+
+	namespace S
+	{
+	  void func() { ... }
+	}
+
+     ...we get called 4 times.  Twice in early debug and twice in
+     late debug:
+
+     Early debug
+     -----------
+
+       1. Once while generating func() within the namespace.  This is
+          the declaration.  The declaration bit below is set, as the
+          context is the namespace.
+
+	  A new DIE will be generated with DW_AT_declaration set.
+
+       2. Once for func() itself.  This is the specification.  The
+          declaration bit below is clear as the context is the CU.
+
+	  We will use the cached DIE from (1) to create a new DIE with
+	  DW_AT_specification pointing to the declaration in (1).
+
+     Late debug via rest_of_handle_final()
+     -------------------------------------
+
+       3. Once generating func() within the namespace.  This is also the
+          declaration, as in (1), but this time we will early exit below
+          as we have a cached DIE and a declaration needs no additional
+          annotations (no locations), as the source declaration line
+          info is enough.
+
+       4. Once for func() itself.  As in (2), this is the specification,
+          but this time we will re-use the cached DIE, and just annotate
+          it with the location information that should now be available.
+
+     For something without namespaces, but with abstract instances, we
+     are also called a multiple times:
+
+        class Base
+	{
+	public:
+	  Base ();	  // constructor declaration (1)
+	};
+
+	Base::Base () { } // constructor specification (2)
+
+    Early debug
+    -----------
+
+       1. Once for the Base() constructor by virtue of it being a
+          member of the Base class.  This is done via
+          rest_of_type_compilation.
+
+	  This is a declaration, so a new DIE will be created with
+	  DW_AT_declaration.
+
+       2. Once for the Base() constructor definition, but this time
+          while generating the abstract instance of the base
+          constructor (__base_ctor) which is being generated via early
+          debug of reachable functions.
+
+	  Even though we have a cached version of the declaration (1),
+	  we will create a DW_AT_specification of the declaration DIE
+	  in (1).
+
+       3. Once for the __base_ctor itself, but this time, we generate
+          an DW_AT_abstract_origin version of the DW_AT_specification in
+	  (2).
+
+    Late debug via rest_of_handle_final
+    -----------------------------------
+
+       4. One final time for the __base_ctor (which will have a cached
+          DIE with DW_AT_abstract_origin created in (3).  This time,
+          we will just annotate the location information now
+          available.
+  */
   int declaration = (current_function_decl != decl
 		     || class_or_namespace_scope_p (context_die));
 
   premark_used_types (DECL_STRUCT_FUNCTION (decl));
 
-  /* It is possible to have both DECL_ABSTRACT_P and DECLARATION be true if we
-     started to generate the abstract instance of an inline, decided to output
-     its containing class, and proceeded to emit the declaration of the inline
-     from the member list for the class.  If so, DECLARATION takes priority;
-     we'll get back to the abstract instance when done with the class.  */
-
-  /* The class-scope declaration DIE must be the primary DIE.  */
-  if (origin && declaration && class_or_namespace_scope_p (context_die))
-    {
-      origin = NULL;
-      gcc_assert (!old_die);
-    }
-
   /* Now that the C++ front end lazily declares artificial member fns, we
      might need to retrofit the declaration into its class.  */
   if (!declaration && !origin && !old_die
@@ -18427,6 +18677,8 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       && debug_info_level > DINFO_LEVEL_TERSE)
     old_die = force_decl_die (decl);
 
+  bool dumped_early = false;
+  /* An inlined instance, tag a new DIE with DW_AT_abstract_origin.  */
   if (origin != NULL)
     {
       gcc_assert (!declaration || local_scope_p (context_die));
@@ -18436,19 +18688,34 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       if (old_die && old_die->die_parent == NULL)
 	add_child_die (context_die, old_die);
 
-      subr_die = new_die (DW_TAG_subprogram, context_die, decl);
-      add_abstract_origin_attribute (subr_die, origin);
-      /*  This is where the actual code for a cloned function is.
-	  Let's emit linkage name attribute for it.  This helps
-	  debuggers to e.g, set breakpoints into
-	  constructors/destructors when the user asks "break
-	  K::K".  */
-      add_linkage_name (subr_die, decl);
+      if (old_die && get_AT_ref (old_die, DW_AT_abstract_origin))
+	{
+	  /* If we have a DW_AT_abstract_origin we have a working
+	     cached version.  */
+	  subr_die = old_die;
+	}
+      else
+	{
+	  subr_die = new_die (DW_TAG_subprogram, context_die, decl);
+	  add_abstract_origin_attribute (subr_die, origin);
+	  /*  This is where the actual code for a cloned function is.
+	      Let's emit linkage name attribute for it.  This helps
+	      debuggers to e.g, set breakpoints into
+	      constructors/destructors when the user asks "break
+	      K::K".  */
+	  add_linkage_name (subr_die, decl);
+	}
     }
+  /* A cached copy, possibly from early dwarf generation.  Reuse as
+     much as possible.  */
   else if (old_die)
     {
-      expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
-      struct dwarf_file_data * file_index = lookup_filename (s.file);
+      /* A declaration that has been previously dumped needs no
+	 additional information.  */
+      if (declaration)
+	return;
+
+      dumped_early = old_die->dumped_early;
 
       if (!get_AT_flag (old_die, DW_AT_declaration)
 	  /* We can have a normal definition following an inline one in the
@@ -18458,7 +18725,13 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	{
 	  /* Detect and ignore this case, where we are trying to output
 	     something we have already output.  */
-	  return;
+	  if (get_AT (old_die, DW_AT_low_pc)
+	      || get_AT (old_die, DW_AT_ranges))
+	    return;
+
+	  /* If we have no location information, this must be a
+	     partially generated DIE from early dwarf generation.
+	     Fall through and generate it.  */
 	}
 
       /* If the definition comes from the same place as the declaration,
@@ -18468,23 +18741,44 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	 instances of inlines, since the spec requires the out-of-line copy
 	 to have the same parent.  For local class methods, this doesn't
 	 apply; we just use the old DIE.  */
-      if ((is_cu_die (old_die->die_parent) || context_die == NULL)
-	  && (DECL_ARTIFICIAL (decl)
-	      || (get_AT_file (old_die, DW_AT_decl_file) == file_index
-		  && (get_AT_unsigned (old_die, DW_AT_decl_line)
-		      == (unsigned) s.line))))
+      expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
+      struct dwarf_file_data * file_index = lookup_filename (s.file);
+      if ((is_cu_die (old_die->die_parent)
+	   /* FIXME: Jason doesn't like this condition, but it fixes
+	      the inconsistency/ICE with the following Fortran test:
+
+		 module some_m
+		 contains
+		    logical function funky (FLAG)
+		      funky = .true.
+		   end function
+		 end module
+
+	      Another alternative is !is_cu_die (context_die).
+	   */
+	   || old_die->die_parent->die_tag == DW_TAG_module
+	   || context_die == NULL)
+	   && (DECL_ARTIFICIAL (decl)
+	       || (get_AT_file (old_die, DW_AT_decl_file) == file_index
+		   && (get_AT_unsigned (old_die, DW_AT_decl_line)
+		       == (unsigned) s.line))))
 	{
 	  subr_die = old_die;
 
-	  /* Clear out the declaration attribute and the formal parameters.
-	     Do not remove all children, because it is possible that this
-	     declaration die was forced using force_decl_die(). In such
-	     cases die that forced declaration die (e.g. TAG_imported_module)
-	     is one of the children that we do not want to remove.  */
-	  remove_AT (subr_die, DW_AT_declaration);
-	  remove_AT (subr_die, DW_AT_object_pointer);
-	  remove_child_TAG (subr_die, DW_TAG_formal_parameter);
+	  /* Clear out the declaration attribute, but leave the
+	     parameters so they can be augmented with location
+	     information later.  Unless this was a declaration, in
+	     which case, wipe out the nameless parameters and recreate
+	     them further down.  */
+	  if (remove_AT (subr_die, DW_AT_declaration))
+	    {
+
+	      remove_AT (subr_die, DW_AT_object_pointer);
+	      remove_child_TAG (subr_die, DW_TAG_formal_parameter);
+	    }
 	}
+      /* Make a specification pointing to the previously built
+	 declaration.  */
       else
 	{
 	  subr_die = new_die (DW_TAG_subprogram, context_die, decl);
@@ -18506,6 +18800,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	    }
 	}
     }
+  /* Create a fresh DIE for anything else.  */
   else
     {
       subr_die = new_die (DW_TAG_subprogram, context_die, decl);
@@ -18532,6 +18827,11 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       add_accessibility_attribute (subr_die, decl);
     }
 
+  /* Unless we have an existing non-declaration DIE, equate the new
+     DIE.  */
+  if (!old_die || is_declaration_die (old_die))
+    equate_decl_number_to_die (decl, subr_die);
+
   if (declaration)
     {
       if (!old_die || !get_AT (old_die, DW_AT_inline))
@@ -18549,17 +18849,9 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	  if (lang_hooks.decls.function_decl_deleted_p (decl)
 	      && (! dwarf_strict))
 	    add_AT_flag (subr_die, DW_AT_GNU_deleted, 1);
-
-	  /* The first time we see a member function, it is in the context of
-	     the class to which it belongs.  We make sure of this by emitting
-	     the class first.  The next time is the definition, which is
-	     handled above.  The two may come from the same source text.
-
-	     Note that force_decl_die() forces function declaration die. It is
-	     later reused to represent definition.  */
-	  equate_decl_number_to_die (decl, subr_die);
 	}
     }
+  /* Tag abstract instances with DW_AT_inline.  */
   else if (DECL_ABSTRACT_P (decl))
     {
       if (DECL_DECLARED_INLINE_P (decl))
@@ -18580,18 +18872,21 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       if (DECL_DECLARED_INLINE_P (decl)
 	  && lookup_attribute ("artificial", DECL_ATTRIBUTES (decl)))
 	add_AT_flag (subr_die, DW_AT_artificial, 1);
-
-      equate_decl_number_to_die (decl, subr_die);
     }
+  /* For non DECL_EXTERNALs, if range information is available, fill
+     the DIE with it.  */
   else if (!DECL_EXTERNAL (decl))
     {
       HOST_WIDE_INT cfa_fb_offset;
+
       struct function *fun = DECL_STRUCT_FUNCTION (decl);
 
-      if (!old_die || !get_AT (old_die, DW_AT_inline))
-	equate_decl_number_to_die (decl, subr_die);
+      /* If we have no fun->fde, we have no range information.
+	 Skip over and fill in range information in the second
+	 dwarf pass.  */
+      if (!fun->fde)
+	goto no_fde_continue;
 
-      gcc_checking_assert (fun);
       if (!flag_reorder_blocks_and_partition)
 	{
 	  dw_fde_ref fde = fun->fde;
@@ -18745,12 +19040,16 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       compute_frame_pointer_to_fb_displacement (cfa_fb_offset);
 
       if (fun->static_chain_decl)
-	add_AT_location_description (subr_die, DW_AT_static_link,
-		 loc_list_from_tree (fun->static_chain_decl, 2, NULL));
+	add_AT_location_description
+	  (subr_die, DW_AT_static_link,
+	   loc_list_from_tree (fun->static_chain_decl, 2, NULL));
+    no_fde_continue:
+      ;
     }
 
   /* Generate child dies for template paramaters.  */
-  if (debug_info_level > DINFO_LEVEL_TERSE)
+  if (debug_info_level > DINFO_LEVEL_TERSE
+      && early_dwarf_dumping)
     gen_generic_params_dies (decl);
 
   /* Now output descriptions of the arguments for this function. This gets
@@ -18769,7 +19068,11 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
   if (debug_info_level <= DINFO_LEVEL_TERSE)
     ;
   else if (declaration)
-    gen_formal_types_die (decl, subr_die);
+    {
+      /* Only generate a prototype's parameters once.  */
+      if (!dumped_early)
+	gen_formal_types_die (decl, subr_die);
+    }
   else
     {
       /* Generate DIEs to represent all known formal parameters.  */
@@ -18801,9 +19104,14 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	{
 	  if (generic_decl_parm
 	      && lang_hooks.function_parameter_pack_p (generic_decl_parm))
-	    gen_formal_parameter_pack_die (generic_decl_parm,
-					   parm, subr_die,
-					   &parm);
+	    {
+	      if (early_dwarf_dumping)
+		gen_formal_parameter_pack_die (generic_decl_parm,
+					       parm, subr_die,
+					       &parm);
+	      else if (parm)
+		parm = DECL_CHAIN (parm);
+	    }
 	  else if (parm && !POINTER_BOUNDS_P (parm))
 	    {
 	      dw_die_ref parm_die = gen_decl_die (parm, NULL, subr_die);
@@ -18839,11 +19147,14 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	gen_unspecified_parameters_die (decl, subr_die);
     }
 
+  if (subr_die != old_die)
+    /* Add the calling convention attribute if requested.  */
+    add_calling_convention_attribute (subr_die, decl);
+
   /* Output Dwarf info for all of the stuff within the body of the function
-     (if it has one - it may be just a declaration).  */
-  outer_scope = DECL_INITIAL (decl);
+     (if it has one - it may be just a declaration).
 
-  /* OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent
+     OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent
      a function.  This BLOCK actually represents the outermost binding contour
      for the function, i.e. the contour in which the function's formal
      parameters and labels get declared. Curiously, it appears that the front
@@ -18857,6 +19168,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
      a BLOCK node representing the function's outermost pair of curly braces,
      and any blocks used for the base and member initializers of a C++
      constructor function.  */
+  tree outer_scope = DECL_INITIAL (decl);
   if (! declaration && outer_scope && TREE_CODE (outer_scope) != ERROR_MARK)
     {
       int call_site_note_count = 0;
@@ -18866,6 +19178,9 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       if (DECL_NAME (DECL_RESULT (decl)))
 	gen_decl_die (DECL_RESULT (decl), NULL, subr_die);
 
+      /* The first time through decls_for_scope we will generate the
+	 DIEs for the locals.  The second time, we fill in the
+	 location info.  */
       decls_for_scope (outer_scope, subr_die);
 
       if (call_arg_locations && !dwarf_strict)
@@ -19017,10 +19332,6 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       call_site_count = -1;
       tail_call_site_count = -1;
     }
-
-  if (subr_die != old_die)
-    /* Add the calling convention attribute if requested.  */
-    add_calling_convention_attribute (subr_die, decl);
 }
 
 /* Returns a hash value for X (which really is a die_struct).  */
@@ -19040,6 +19351,33 @@ block_die_hasher::equal (die_struct *x, die_struct *y)
   return x->decl_id == y->decl_id && x->die_parent == y->die_parent;
 }
 
+/* Return TRUE if DECL, which may have been previously generated as
+   OLD_DIE, is a candidate for a DW_AT_specification.  DECLARATION is
+   true if decl (or its origin) is either an extern declaration or a
+   class/namespace scoped declaration.
+
+   The declare_in_namespace support causes us to get two DIEs for one
+   variable, both of which are declarations.  We want to avoid
+   considering one to be a specification, so we must test for
+   DECLARATION and DW_AT_declaration.  */
+static inline bool
+decl_will_get_specification_p (dw_die_ref old_die, tree decl, bool declaration)
+{
+  return (old_die && TREE_STATIC (decl) && !declaration
+	  && get_AT_flag (old_die, DW_AT_declaration) == 1);
+}
+
+/* Return true if DECL is a local static.  */
+
+static inline bool
+local_function_static (tree decl)
+{
+  gcc_assert (TREE_CODE (decl) == VAR_DECL);
+  return TREE_STATIC (decl)
+    && DECL_CONTEXT (decl)
+    && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL;
+}
+
 /* Generate a DIE to represent a declared data object.
    Either DECL or ORIGIN must be non-null.  */
 
@@ -19052,7 +19390,6 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
   tree ultimate_origin;
   dw_die_ref var_die;
   dw_die_ref old_die = decl ? lookup_decl_die (decl) : NULL;
-  dw_die_ref origin_die;
   bool declaration = (DECL_EXTERNAL (decl_or_origin)
 		      || class_or_namespace_scope_p (context_die));
   bool specialization_p = false;
@@ -19167,11 +19504,74 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
       return;
     }
 
+  dw_die_ref origin_die = NULL;
+
+  if (old_die && old_die->dumped_early)
+    {
+      if (decl_will_get_specification_p (old_die, decl, declaration))
+	{
+	  /* If we already have a DW_AT_specification, all we need is
+	     location info.  */
+	  if (get_AT (old_die, DW_AT_specification))
+	    {
+	      var_die = old_die;
+	      goto gen_variable_die_location;
+	    }
+	  /* Otherwise fall-thru so we can make a new variable die
+	     along with a DW_AT_specification.  */
+	}
+      else if (declaration)
+	{
+	  /* A declaration that has been previously dumped, needs no
+	     further annotations, since it doesn't need location on
+	     the second pass.  */
+	  return;
+	}
+      else if (old_die->die_parent != context_die)
+	{
+	  /* If the contexts differ, it means we _MAY_ not be talking
+	     about the same thing.  */
+	  if (origin)
+	    {
+	      /* If we will be creating an inlined instance, we need a
+		 new DIE that will get annotated with
+		 DW_AT_abstract_origin.  Clear things so we can get a
+		 new DIE.  */
+	      gcc_assert (!DECL_ABSTRACT_P (decl));
+	      old_die = NULL;
+	    }
+	  else
+	    {
+	      /* In some cases we end up with different contexts because
+		 the context_die is set to the context of the containing
+		 function, whereas the cached die is correctly set to the
+		 (possible) enclosing lexical scope (DW_TAG_lexical_block).
+		 In which case, special case it (hack).
+
+		 See dwarf2out_decl and its use of
+		 local_function_static to see how this can happened.
+		 In java, it can happen with non local statics, hence
+		 we do not check for TREE_STATIC here.  */
+	      gcc_assert (!DECL_CONTEXT (decl)
+			  || TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL);
+	      var_die = old_die;
+	      goto gen_variable_die_location;
+	    }
+	}
+      else
+	{
+	  /* If a DIE was dumped early, it still needs location info.
+	     Skip to where we fill the location bits.  */
+	  var_die = old_die;
+	  goto gen_variable_die_location;
+	}
+    }
+
   /* If the compiler emitted a definition for the DECL declaration
-     and if we already emitted a DIE for it, don't emit a second
+     and we already emitted a DIE for it, don't emit a second
      DIE for it again. Allow re-declarations of DECLs that are
      inside functions, though.  */
-  if (old_die && declaration && !local_scope_p (context_die))
+  else if (old_die && !declaration && !local_scope_p (context_die))
     return;
 
   /* For static data members, the declaration in the class is supposed
@@ -19182,7 +19582,6 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
   else
     var_die = new_die (DW_TAG_variable, context_die, decl);
 
-  origin_die = NULL;
   if (origin != NULL)
     origin_die = add_abstract_origin_attribute (var_die, origin);
 
@@ -19193,14 +19592,8 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
      copy decls and set the DECL_ABSTRACT_P flag on them instead of
      sharing them.
 
-     ??? Duplicated blocks have been rewritten to use .debug_ranges.
-
-     ??? The declare_in_namespace support causes us to get two DIEs for one
-     variable, both of which are declarations.  We want to avoid considering
-     one to be a specification, so we must test that this DIE is not a
-     declaration.  */
-  else if (old_die && TREE_STATIC (decl) && ! declaration
-	   && get_AT_flag (old_die, DW_AT_declaration) == 1)
+     ??? Duplicated blocks have been rewritten to use .debug_ranges.  */
+  else if (decl_will_get_specification_p (old_die, decl, declaration))
     {
       /* This is a definition of a C++ class level static.  */
       add_AT_specification (var_die, old_die);
@@ -19254,9 +19647,15 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
   if (declaration)
     add_AT_flag (var_die, DW_AT_declaration, 1);
 
-  if (decl && (DECL_ABSTRACT_P (decl) || declaration || old_die == NULL))
+  if (decl && (DECL_ABSTRACT_P (decl) || declaration || old_die == NULL
+	       /* If we make it to a specialization, we have already
+		  handled the declaration by virtue of early dwarf.
+		  If so, make a new assocation if available, so late
+		  dwarf can find it.  */
+	       || (specialization_p && early_dwarf_dumping)))
     equate_decl_number_to_die (decl, var_die);
 
+ gen_variable_die_location:
   if (! declaration
       && (! DECL_ABSTRACT_P (decl_or_origin)
 	  /* Local static vars are shared between all clones/inlines,
@@ -19269,13 +19668,11 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
 	 to add it again.  */
       && (origin_die == NULL || get_AT (origin_die, DW_AT_location) == NULL))
     {
-      if (TREE_CODE (decl_or_origin) == VAR_DECL && TREE_STATIC (decl_or_origin)
-          && !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl_or_origin)))
-	defer_location (decl_or_origin, var_die);
+      if (early_dwarf_dumping)
+	add_pubname (decl_or_origin, var_die);
       else
-        add_location_or_const_value_attribute (var_die, decl_or_origin,
+	add_location_or_const_value_attribute (var_die, decl_or_origin,
 					       decl == NULL, DW_AT_location);
-      add_pubname (decl_or_origin, var_die);
     }
   else
     tree_add_const_value_attribute_for_decl (var_die, decl_or_origin);
@@ -19289,7 +19686,12 @@ gen_const_die (tree decl, dw_die_ref context_die)
   dw_die_ref const_die;
   tree type = TREE_TYPE (decl);
 
+  const_die = lookup_decl_die (decl);
+  if (const_die)
+    return;
+
   const_die = new_die (DW_TAG_constant, context_die, decl);
+  equate_decl_number_to_die (decl, const_die);
   add_name_and_src_coords_attributes (const_die, decl);
   add_type_attribute (const_die, type, TYPE_QUAL_CONST, context_die);
   if (TREE_PUBLIC (decl))
@@ -19305,14 +19707,20 @@ static void
 gen_label_die (tree decl, dw_die_ref context_die)
 {
   tree origin = decl_ultimate_origin (decl);
-  dw_die_ref lbl_die = new_die (DW_TAG_label, context_die, decl);
+  dw_die_ref lbl_die = lookup_decl_die (decl);
   rtx insn;
   char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
-  if (origin != NULL)
-    add_abstract_origin_attribute (lbl_die, origin);
-  else
-    add_name_and_src_coords_attributes (lbl_die, decl);
+  if (!lbl_die)
+    {
+      lbl_die = new_die (DW_TAG_label, context_die, decl);
+      equate_decl_number_to_die (decl, lbl_die);
+
+      if (origin != NULL)
+	add_abstract_origin_attribute (lbl_die, origin);
+      else
+	add_name_and_src_coords_attributes (lbl_die, decl);
+    }
 
   if (DECL_ABSTRACT_P (decl))
     equate_decl_number_to_die (decl, lbl_die);
@@ -19466,17 +19874,68 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
 static void
 gen_lexical_block_die (tree stmt, dw_die_ref context_die)
 {
-  dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+  dw_die_ref stmt_die = BLOCK_DIE (stmt);
 
-  if (call_arg_locations)
+  if (BLOCK_ABSTRACT (stmt))
+    {
+      if (stmt_die)
+	{
+	  /* Do nothing.  This must have been early dumped and it
+	     won't even need location information since it's a
+	     DW_AT_inline function.  */
+	  for (dw_die_ref c = context_die; c; c = c->die_parent)
+	    if (c->die_tag == DW_TAG_inlined_subroutine
+		|| c->die_tag == DW_TAG_subprogram)
+	      {
+		gcc_assert (get_AT (c, DW_AT_inline));
+		break;
+	      }
+	  return;
+	}
+      else
+	{
+	  /* Do the new DIE dance.  */
+	  stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+	  BLOCK_DIE (stmt) = stmt_die;
+	}
+    }
+  else if (BLOCK_ABSTRACT_ORIGIN (stmt))
+    {
+      /* If this is an inlined instance, create a new lexical die for
+	 anything below to attach DW_AT_abstract_origin to.  */
+      stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+    }
+  else
     {
-      if (block_map.length () <= BLOCK_NUMBER (stmt))
-	block_map.safe_grow_cleared (BLOCK_NUMBER (stmt) + 1);
-      block_map[BLOCK_NUMBER (stmt)] = stmt_die;
+      if (!stmt_die)
+	{
+	  /* This is the first time we are creating something for this
+	     block.  */
+	  stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+	  BLOCK_DIE (stmt) = stmt_die;
+	}
+      else
+	{
+	  /* Otherwise we are being called from late dwarf dumping to
+	     fill in some (location) details.  */
+	}
     }
 
-  if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
-    add_high_low_attributes (stmt, stmt_die);
+  if (!early_dwarf_dumping)
+    {
+      if (call_arg_locations)
+	{
+	  if (block_map.length () <= BLOCK_NUMBER (stmt))
+	    block_map.safe_grow_cleared (BLOCK_NUMBER (stmt) + 1);
+	  block_map[BLOCK_NUMBER (stmt)] = stmt_die;
+	}
+
+      /* A non abstract block whose blocks have already been reordered
+	 should have the instruction range for this block.  If so, set the
+	 high/low attributes.  */
+      if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
+	add_high_low_attributes (stmt, stmt_die);
+    }
 
   decls_for_scope (stmt, stmt_die);
 }
@@ -19968,6 +20427,16 @@ static void
 gen_struct_or_union_type_die (tree type, dw_die_ref context_die,
 				enum debug_info_usage usage)
 {
+  /* Fill in the size of variable-length fields in late dwarf.  */
+  if (TREE_ASM_WRITTEN (type)
+      && !early_dwarf_dumping)
+    {
+      tree member;
+      for (member = TYPE_FIELDS (type); member; member = DECL_CHAIN (member))
+	fill_variable_array_bounds (TREE_TYPE (member));
+      return;
+    }
+
   dw_die_ref type_die = lookup_type_die (type);
   dw_die_ref scope_die = 0;
   int nested = 0;
@@ -20087,7 +20556,11 @@ gen_typedef_die (tree decl, dw_die_ref context_die)
   tree origin;
 
   if (TREE_ASM_WRITTEN (decl))
-    return;
+    {
+      if (DECL_ORIGINAL_TYPE (decl))
+	fill_variable_array_bounds (DECL_ORIGINAL_TYPE (decl));
+      return;
+    }
 
   TREE_ASM_WRITTEN (decl) = 1;
   type_die = new_die (DW_TAG_typedef, context_die, decl);
@@ -20103,6 +20576,9 @@ gen_typedef_die (tree decl, dw_die_ref context_die)
 	{
 	  type = DECL_ORIGINAL_TYPE (decl);
 
+	  if (type == error_mark_node)
+	    return;
+
 	  gcc_assert (type != TREE_TYPE (decl));
 	  equate_type_number_to_die (TREE_TYPE (decl), type_die);
 	}
@@ -20110,6 +20586,9 @@ gen_typedef_die (tree decl, dw_die_ref context_die)
 	{
 	  type = TREE_TYPE (decl);
 
+	  if (type == error_mark_node)
+	    return;
+
 	  if (is_naming_typedef_decl (TYPE_NAME (type)))
 	    {
 	      /* Here, we are in the case of decl being a typedef naming
@@ -20170,13 +20649,15 @@ gen_tagged_type_die (tree type,
       || !is_tagged_type (type))
     return;
 
+  if (TREE_ASM_WRITTEN (type))
+    need_pop = 0;
   /* If this is a nested type whose containing class hasn't been written
      out yet, writing it out will cover this one, too.  This does not apply
      to instantiations of member class templates; they need to be added to
      the containing class as they are generated.  FIXME: This hurts the
      idea of combining type decls from multiple TUs, since we can't predict
      what set of template instantiations we'll get.  */
-  if (TYPE_CONTEXT (type)
+  else if (TYPE_CONTEXT (type)
       && AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
       && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
     {
@@ -20308,7 +20789,19 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
     }
 
   if (TREE_ASM_WRITTEN (type))
-    return;
+    {
+      /* Variable-length types may be incomplete even if
+	 TREE_ASM_WRITTEN.  For such types, fall through to
+	 gen_array_type_die() and possibly fill in
+	 DW_AT_{upper,lower}_bound attributes.  */
+      if ((TREE_CODE (type) != ARRAY_TYPE
+	   && TREE_CODE (type) != RECORD_TYPE
+	   && TREE_CODE (type) != UNION_TYPE
+	   && TREE_CODE (type) != QUAL_UNION_TYPE)
+	  || (TYPE_SIZE (type)
+	      && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST))
+	return;
+    }
 
   switch (TREE_CODE (type))
     {
@@ -20360,9 +20853,6 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
       break;
 
     case ARRAY_TYPE:
-      gen_array_type_die (type, context_die);
-      break;
-
     case VECTOR_TYPE:
       gen_array_type_die (type, context_die);
       break;
@@ -20533,8 +21023,11 @@ process_scope_var (tree stmt, tree decl, tree origin, dw_die_ref context_die)
   if (die != NULL && die->die_parent == NULL)
     add_child_die (context_die, die);
   else if (TREE_CODE (decl_or_origin) == IMPORTED_DECL)
-    dwarf2out_imported_module_or_decl_1 (decl_or_origin, DECL_NAME (decl_or_origin),
-					 stmt, context_die);
+    {
+      if (early_dwarf_dumping)
+	dwarf2out_imported_module_or_decl_1 (decl_or_origin, DECL_NAME (decl_or_origin),
+					     stmt, context_die);
+    }
   else
     gen_decl_die (decl, origin, context_die);
 }
@@ -20748,7 +21241,9 @@ setup_namespace_context (tree thing, dw_die_ref context_die)
    type) within its namespace, if appropriate.
 
    For compatibility with older debuggers, namespace DIEs only contain
-   declarations; all definitions are emitted at CU scope.  */
+   declarations; all definitions are emitted at CU scope, with
+   DW_AT_specification pointing to the declaration (like with class
+   members).  */
 
 static dw_die_ref
 declare_in_namespace (tree thing, dw_die_ref context_die)
@@ -21065,16 +21560,68 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
   return NULL;
 }
 \f
-/* Output debug information for global decl DECL.  Called from toplev.c after
-   compilation proper has finished.  */
+/* Output initial debug information for global DECL.  Called at the
+   end of the parsing process.
+
+   This is the initial debug generation process.  As such, the DIEs
+   generated may be incomplete.  A later debug generation pass
+   (dwarf2out_late_global_decl) will augment the information generated
+   in this pass (e.g., with complete location info).  */
+
+static void
+dwarf2out_early_global_decl (tree decl)
+{
+  bool prev_early_dwarf_dumping = early_dwarf_dumping;
+  early_dwarf_dumping = true;
+
+  /* gen_decl_die() will set DECL_ABSTRACT because
+     cgraph_function_possibly_inlined_p() returns true.  This is in
+     turn will cause DW_AT_inline attributes to be set.
+
+     This happens because at early dwarf generation, there is no
+     cgraph information, causing cgraph_function_possibly_inlined_p()
+     to return true.  Trick cgraph_function_possibly_inlined_p()
+     while we generate dwarf early.  */
+  bool save = symtab->global_info_ready;
+  symtab->global_info_ready = true;
+
+  /* We don't handle TYPE_DECLs.  If required, they'll be reached via
+     other DECLs and they can point to template types or other things
+     that dwarf2out can't handle when done via dwarf2out_decl.  */
+  if (TREE_CODE (decl) != TYPE_DECL
+      && TREE_CODE (decl) != PARM_DECL)
+    {
+      tree save_fndecl = current_function_decl;
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+	{
+	  /* No cfun means the symbol has no body, so there's nothing
+	     to emit.  */
+	  if (!DECL_STRUCT_FUNCTION (decl))
+	    goto early_decl_exit;
+
+	  current_function_decl = decl;
+	}
+      dwarf2out_decl (decl);
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+	current_function_decl = save_fndecl;
+    }
+ early_decl_exit:
+  symtab->global_info_ready = save;
+  early_dwarf_dumping = prev_early_dwarf_dumping;
+  return;
+}
+
+/* Output debug information for global decl DECL.  Called from
+   toplev.c after compilation proper has finished.  */
 
 static void
-dwarf2out_global_decl (tree decl)
+dwarf2out_late_global_decl (tree decl)
 {
-  /* Output DWARF2 information for file-scope tentative data object
-     declarations, file-scope (extern) function declarations (which
-     had no corresponding body) and file-scope tagged type declarations
-     and definitions which have not yet been forced out.  */
+  /* Output any global decls we missed or fill-in any location
+     information we were unable to determine on the first pass.
+
+     Skip over functions because they were handled by the
+     debug_hooks->function_decl() call in rest_of_handle_final.  */
   if ((TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl))
       && !POINTER_BOUNDS_P (decl))
     dwarf2out_decl (decl);
@@ -21086,7 +21633,12 @@ static void
 dwarf2out_type_decl (tree decl, int local)
 {
   if (!local)
-    dwarf2out_decl (decl);
+    {
+      bool t = early_dwarf_dumping;
+      early_dwarf_dumping = true;
+      dwarf2out_decl (decl);
+      early_dwarf_dumping = t;
+    }
 }
 
 /* Output debug information for imported module or decl DECL.
@@ -21260,13 +21812,22 @@ gen_namelist_decl (tree name, dw_die_ref scope_die, tree item_decls)
 }
 
 
-/* Write the debugging output for DECL.  */
+/* Write the debugging output for DECL and return the DIE.  */
 
 static void
 dwarf2out_decl (tree decl)
 {
   dw_die_ref context_die = comp_unit_die ();
 
+#ifdef ENABLE_CHECKING
+  /* Save some info so we can later determine if we erroneously
+     created a DIE for something we had already created a DIE for.
+     We should always be reusing DIEs created early.  */
+  dw_die_ref early_die = NULL;
+  if (decl_die_table)
+    early_die = lookup_decl_die (decl);
+#endif
+
   switch (TREE_CODE (decl))
     {
     case ERROR_MARK:
@@ -21319,21 +21880,8 @@ dwarf2out_decl (tree decl)
       break;
 
     case VAR_DECL:
-      /* Ignore this VAR_DECL if it refers to a file-scope extern data object
-	 declaration and if the declaration was never even referenced from
-	 within this entire compilation unit.  We suppress these DIEs in
-	 order to save space in the .debug section (by eliminating entries
-	 which are probably useless).  Note that we must not suppress
-	 block-local extern declarations (whether used or not) because that
-	 would screw-up the debugger's name lookup mechanism and cause it to
-	 miss things which really ought to be in scope at a given point.  */
-      if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
-	return;
-
       /* For local statics lookup proper context die.  */
-      if (TREE_STATIC (decl)
-	  && DECL_CONTEXT (decl)
-	  && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
+      if (local_function_static (decl))
 	context_die = lookup_decl_die (DECL_CONTEXT (decl));
 
       /* If we are in terse mode, don't generate any DIEs to represent any
@@ -21388,6 +21936,19 @@ dwarf2out_decl (tree decl)
     }
 
   gen_decl_die (decl, NULL, context_die);
+
+  dw_die_ref die = lookup_decl_die (decl);
+  if (die)
+    check_die (die);
+#ifdef ENABLE_CHECKING
+  /* If we early created a DIE, make sure it didn't get re-created by
+     mistake.  */
+  if (early_die && early_die->dumped_early)
+    gcc_assert (early_die == die
+		/* We can have a differing DIE if and only if, the
+		   new one is a specification of the old one.  */
+		|| get_AT_ref (die, DW_AT_specification) == early_die);
+#endif
 }
 
 /* Write the debugging output for DECL.  */
@@ -21475,23 +22036,16 @@ dwarf_file_hasher::hash (dwarf_file_data *p)
    section) and references to those files numbers (in the .debug_srcinfo
    and.debug_macinfo sections).  If the filename given as an argument is not
    found in our current list, add it to the list and assign it the next
-   available unique index number.  In order to speed up searches, we remember
-   the index of the filename was looked up last.  This handles the majority of
-   all searches.  */
+   available unique index number.  */
 
 static struct dwarf_file_data *
 lookup_filename (const char *file_name)
 {
   struct dwarf_file_data * created;
 
-  /* Check to see if the file name that was searched on the previous
-     call matches this file name.  If so, return the index.  */
-  if (file_table_last_lookup
-      && (file_name == file_table_last_lookup->filename
-	  || filename_cmp (file_table_last_lookup->filename, file_name) == 0))
-    return file_table_last_lookup;
+  if (!file_name)
+    return NULL;
 
-  /* Didn't match the previous lookup, search the table.  */
   dwarf_file_data **slot
     = file_table->find_slot_with_hash (file_name, htab_hash_string (file_name),
 				       INSERT);
@@ -24530,11 +25084,20 @@ optimize_location_lists (dw_die_ref die)
 static void
 dwarf2out_finish (const char *filename)
 {
-  limbo_die_node *node, *next_node;
   comdat_type_node *ctnode;
-  unsigned int i;
   dw_die_ref main_comp_unit_die;
 
+  /* If the limbo list has anything, it should be things that were
+     created after the compilation proper.  Anything from the early
+     dwarf pass, should have parents and should never be in the limbo
+     list this late.  */
+  for (limbo_die_node *node = limbo_die_list; node; node = node->next)
+    gcc_assert (node->die->die_tag == DW_TAG_compile_unit
+		|| !node->die->dumped_early);
+
+  /* Flush out any latecomers to the limbo party.  */
+  dwarf2out_early_finish ();
+
   /* PCH might result in DW_AT_producer string being restored from the
      header compilation, so always fill it with empty string initially
      and overwrite only here.  */
@@ -24564,65 +25127,6 @@ dwarf2out_finish (const char *filename)
 	add_comp_dir_attribute (comp_unit_die ());
     }
 
-  if (deferred_locations_list)
-    for (i = 0; i < deferred_locations_list->length (); i++)
-      {
-	add_location_or_const_value_attribute (
-	    (*deferred_locations_list)[i].die,
-	    (*deferred_locations_list)[i].variable,
-	    false,
-	    DW_AT_location);
-      }
-
-  /* Traverse the limbo die list, and add parent/child links.  The only
-     dies without parents that should be here are concrete instances of
-     inline functions, and the comp_unit_die.  We can ignore the comp_unit_die.
-     For concrete instances, we can get the parent die from the abstract
-     instance.  */
-  for (node = limbo_die_list; node; node = next_node)
-    {
-      dw_die_ref die = node->die;
-      next_node = node->next;
-
-      if (die->die_parent == NULL)
-	{
-	  dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
-
-	  if (origin && origin->die_parent)
-	    add_child_die (origin->die_parent, die);
-	  else if (is_cu_die (die))
-	    ;
-	  else if (seen_error ())
-	    /* It's OK to be confused by errors in the input.  */
-	    add_child_die (comp_unit_die (), die);
-	  else
-	    {
-	      /* In certain situations, the lexical block containing a
-		 nested function can be optimized away, which results
-		 in the nested function die being orphaned.  Likewise
-		 with the return type of that nested function.  Force
-		 this to be a child of the containing function.
-
-		 It may happen that even the containing function got fully
-		 inlined and optimized out.  In that case we are lost and
-		 assign the empty child.  This should not be big issue as
-		 the function is likely unreachable too.  */
-	      gcc_assert (node->created_for);
-
-	      if (DECL_P (node->created_for))
-		origin = get_context_die (DECL_CONTEXT (node->created_for));
-	      else if (TYPE_P (node->created_for))
-		origin = scope_die_for (node->created_for, comp_unit_die ());
-	      else
-		origin = comp_unit_die ();
-
-	      add_child_die (origin, die);
-	    }
-	}
-    }
-
-  limbo_die_list = NULL;
-
 #if ENABLE_ASSERT_CHECKING
   {
     dw_die_ref die = comp_unit_die (), c;
@@ -24632,23 +25136,6 @@ dwarf2out_finish (const char *filename)
   resolve_addr (comp_unit_die ());
   move_marked_base_types ();
 
-  for (node = deferred_asm_name; node; node = node->next)
-    {
-      tree decl = node->created_for;
-      /* When generating LTO bytecode we can not generate new assembler
-         names at this point and all important decls got theirs via
-	 free-lang-data.  */
-      if (((!flag_generate_lto && !flag_generate_offload)
-	   || DECL_ASSEMBLER_NAME_SET_P (decl))
-	  && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
-	{
-	  add_linkage_attr (node->die, decl);
-	  move_linkage_attr (node->die);
-	}
-    }
-
-  deferred_asm_name = NULL;
-
   /* Walk through the list of incomplete types again, trying once more to
      emit full debugging info for them.  */
   retry_incomplete_types ();
@@ -24687,6 +25174,7 @@ dwarf2out_finish (const char *filename)
   /* Traverse the DIE's and add add sibling attributes to those DIE's
      that have children.  */
   add_sibling_attributes (comp_unit_die ());
+  limbo_die_node *node;
   for (node = limbo_die_list; node; node = node->next)
     add_sibling_attributes (node->die);
   for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
@@ -24948,6 +25436,88 @@ dwarf2out_finish (const char *filename)
     output_indirect_strings ();
 }
 
+/* Perform any cleanups needed after the early debug generation pass
+   has run.  */
+
+static void
+dwarf2out_early_finish (void)
+{
+  limbo_die_node *node, *next_node;
+
+  /* Add DW_AT_linkage_name for all deferred DIEs.  */
+  for (node = deferred_asm_name; node; node = node->next)
+    {
+      tree decl = node->created_for;
+      /* When generating LTO bytecode we can not generate new assembler
+         names at this point and all important decls got theirs via
+	 free-lang-data.  */
+      if (((!flag_generate_lto && !flag_generate_offload)
+	   || DECL_ASSEMBLER_NAME_SET_P (decl))
+	  && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)
+	  /* A missing DECL_ASSEMBLER_NAME can be a constant DIE that
+	     ended up in in deferred_asm_name before we knew it was
+	     constant and never written to disk.  */
+	  && DECL_ASSEMBLER_NAME (decl))
+	{
+	  add_linkage_attr (node->die, decl);
+	  move_linkage_attr (node->die);
+	}
+    }
+  deferred_asm_name = NULL;
+
+  /* Traverse the limbo die list, and add parent/child links.  The only
+     dies without parents that should be here are concrete instances of
+     inline functions, and the comp_unit_die.  We can ignore the comp_unit_die.
+     For concrete instances, we can get the parent die from the abstract
+     instance.
+
+     The point here is to flush out the limbo list so that it is empty
+     and we don't need to stream it for LTO.  */
+  for (node = limbo_die_list; node; node = next_node)
+    {
+      dw_die_ref die = node->die;
+      next_node = node->next;
+
+      if (die->die_parent == NULL)
+	{
+	  dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
+
+	  if (origin && origin->die_parent)
+	    add_child_die (origin->die_parent, die);
+	  else if (is_cu_die (die))
+	    ;
+	  else if (seen_error ())
+	    /* It's OK to be confused by errors in the input.  */
+	    add_child_die (comp_unit_die (), die);
+	  else
+	    {
+	      /* In certain situations, the lexical block containing a
+		 nested function can be optimized away, which results
+		 in the nested function die being orphaned.  Likewise
+		 with the return type of that nested function.  Force
+		 this to be a child of the containing function.
+
+		 It may happen that even the containing function got fully
+		 inlined and optimized out.  In that case we are lost and
+		 assign the empty child.  This should not be big issue as
+		 the function is likely unreachable too.  */
+	      gcc_assert (node->created_for);
+
+	      if (DECL_P (node->created_for))
+		origin = get_context_die (DECL_CONTEXT (node->created_for));
+	      else if (TYPE_P (node->created_for))
+		origin = scope_die_for (node->created_for, comp_unit_die ());
+	      else
+		origin = comp_unit_die ();
+
+	      add_child_die (origin, die);
+	    }
+	}
+    }
+
+  limbo_die_list = NULL;
+}
+
 /* Reset all state within dwarf2out.c so that we can rerun the compiler
    within the same process.  For use by toplev::finalize.  */
 
@@ -24986,13 +25556,10 @@ dwarf2out_c_finalize (void)
   cold_text_section = NULL;
   current_unit_personality = NULL;
 
-  deferred_locations_list = NULL;
-
   next_die_offset = 0;
   single_comp_unit_die = NULL;
   comdat_type_list = NULL;
   limbo_die_list = NULL;
-  deferred_asm_name = NULL;
   file_table = NULL;
   decl_die_table = NULL;
   common_block_die_table = NULL;
@@ -25026,7 +25593,6 @@ dwarf2out_c_finalize (void)
   poc_label_num = 0;
   last_emitted_file = NULL;
   label_num = 0;
-  file_table_last_lookup = NULL;
   tmpl_value_parm_die_table = NULL;
   generic_type_instances = NULL;
   frame_pointer_fb_offset = 0;
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index 02012d5..15b6dd2 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -4718,7 +4718,8 @@ write_roots (pair_p variables, bool emit_pch)
    this funcion will have to be adjusted to be more like
    output_mangled_typename.  */
 
-static void
+/* ?? Why are we keeping this?  Is this actually used anywhere?  */
+static void ATTRIBUTE_UNUSED
 output_typename (outf_p of, const_type_p t)
 {
   switch (t->kind)
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index 303b4b6..18ac84d 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -205,7 +205,7 @@ extern tree lhd_make_node (enum tree_code);
 #define LANG_HOOKS_FUNCTION_DECL_EXPLICIT_P hook_bool_tree_false
 #define LANG_HOOKS_FUNCTION_DECL_DELETED_P hook_bool_tree_false
 #define LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL lhd_warn_unused_global_decl
-#define LANG_HOOKS_WRITE_GLOBALS write_global_declarations
+#define LANG_HOOKS_POST_COMPILATION_PARSING_CLEANUPS NULL
 #define LANG_HOOKS_DECL_OK_FOR_SIBCALL	lhd_decl_ok_for_sibcall
 #define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE hook_bool_const_tree_false
 #define LANG_HOOKS_OMP_PREDETERMINED_SHARING lhd_omp_predetermined_sharing
@@ -230,7 +230,7 @@ extern tree lhd_make_node (enum tree_code);
   LANG_HOOKS_FUNCTION_PARM_EXPANDED_FROM_PACK_P, \
   LANG_HOOKS_GET_GENERIC_FUNCTION_DECL, \
   LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL, \
-  LANG_HOOKS_WRITE_GLOBALS, \
+  LANG_HOOKS_POST_COMPILATION_PARSING_CLEANUPS, \
   LANG_HOOKS_DECL_OK_FOR_SIBCALL, \
   LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE, \
   LANG_HOOKS_OMP_PREDETERMINED_SHARING, \
diff --git a/gcc/langhooks.c b/gcc/langhooks.c
index 74f8351..84058b1 100644
--- a/gcc/langhooks.c
+++ b/gcc/langhooks.c
@@ -139,12 +139,12 @@ lhd_print_tree_nothing (FILE * ARG_UNUSED (file),
 {
 }
 
-/* Called from check_global_declarations.  */
+/* Called from check_global_declaration.  */
 
 bool
 lhd_warn_unused_global_decl (const_tree decl)
 {
-  /* This is what used to exist in check_global_declarations.  Probably
+  /* This is what used to exist in check_global_declaration.  Probably
      not many of these actually apply to non-C languages.  */
 
   if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl))
@@ -311,14 +311,17 @@ lhd_decl_ok_for_sibcall (const_tree decl ATTRIBUTE_UNUSED)
   return true;
 }
 
-/* lang_hooks.decls.final_write_globals: perform final processing on
-   global variables.  */
+/* Generic global declaration processing.  This is meant to be called
+   by the front-ends at the end of parsing.  C/C++ do their own thing,
+   but other front-ends may call this.  */
+
 void
-write_global_declarations (void)
+global_decl_processing (void)
 {
   tree globals, decl, *vec;
   int len, i;
 
+  timevar_stop (TV_PHASE_PARSING);
   timevar_start (TV_PHASE_DEFERRED);
   /* Really define vars that have had only a tentative definition.
      Really output inline functions that must actually be callable
@@ -335,20 +338,9 @@ write_global_declarations (void)
     vec[len - i - 1] = decl;
 
   wrapup_global_declarations (vec, len);
-  check_global_declarations (vec, len);
   timevar_stop (TV_PHASE_DEFERRED);
 
-  timevar_start (TV_PHASE_OPT_GEN);
-  /* This lang hook is dual-purposed, and also finalizes the
-     compilation unit.  */
-  symtab->finalize_compilation_unit ();
-  timevar_stop (TV_PHASE_OPT_GEN);
-
-  timevar_start (TV_PHASE_DBGINFO);
-  emit_debug_global_declarations (vec, len);
-  timevar_stop (TV_PHASE_DBGINFO);
-
-  /* Clean up.  */
+  timevar_start (TV_PHASE_PARSING);
   free (vec);
 }
 
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index 4039e8f..d8d01fa 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -184,9 +184,11 @@ struct lang_hooks_for_decls
      We will already have checked that it has static binding.  */
   bool (*warn_unused_global) (const_tree);
 
-  /* Obtain a list of globals and do final output on them at end
-     of compilation */
-  void (*final_write_globals) (void);
+  /* Perform any post compilation-proper parser cleanups and
+     processing.  This is currently only needed for the C++ parser,
+     which hopefully can be cleaned up so this hook is no longer
+     necessary.  */
+  void (*post_compilation_parsing_cleanups) (void);
 
   /* True if this decl may be called via a sibcall.  */
   bool (*ok_for_sibcall) (const_tree);
diff --git a/gcc/passes.c b/gcc/passes.c
index 04ff042..4dee8ad 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -293,6 +293,28 @@ rest_of_decl_compilation (tree decl,
   else if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl)
 	   && TREE_STATIC (decl))
     varpool_node::get_create (decl);
+
+  /* Generate early debug for global variables.  Any local variables will
+     be handled by either handling reachable functions from
+     finalize_compilation_unit (and by consequence, locally scoped
+     symbols), or by rest_of_type_compilation below.
+
+     Also, pick up function prototypes, which will be mostly ignored
+     by the different early_global_decl() hooks, but will at least be
+     used by Go's hijack of the debug_hooks to implement
+     -fdump-go-spec.  */
+  if (!flag_wpa
+      && !in_lto_p
+      && (TREE_CODE (decl) != FUNCTION_DECL
+	  /* This will pick up function prototypes with no bodies,
+	     which are not visible in finalize_compilation_unit()
+	     while iterating with FOR_EACH_*_FUNCTION through the
+	     symbol table.  */
+	  || !DECL_SAVED_TREE (decl))
+      && !decl_function_context (decl)
+      && !current_function_decl
+      && !decl_type_context (decl))
+    (*debug_hooks->early_global_decl) (decl);
 }
 
 /* Called after finishing a record, union or enumeral type.  */
diff --git a/gcc/sdbout.c b/gcc/sdbout.c
index b4f7325..029b104 100644
--- a/gcc/sdbout.c
+++ b/gcc/sdbout.c
@@ -128,7 +128,8 @@ static void sdbout_begin_block		(unsigned int, unsigned int);
 static void sdbout_end_block		(unsigned int, unsigned int);
 static void sdbout_source_line		(unsigned int, const char *, int, bool);
 static void sdbout_end_epilogue		(unsigned int, const char *);
-static void sdbout_global_decl		(tree);
+static void sdbout_early_global_decl	(tree);
+static void sdbout_late_global_decl	(tree);
 static void sdbout_begin_prologue	(unsigned int, const char *);
 static void sdbout_end_prologue		(unsigned int, const char *);
 static void sdbout_begin_function	(tree);
@@ -151,7 +152,6 @@ static void sdbout_field_types		(tree);
 static void sdbout_one_type		(tree);
 static void sdbout_parms		(tree);
 static void sdbout_reg_parms		(tree);
-static void sdbout_global_decl		(tree);
 
 /* Random macros describing parts of SDB data.  */
 
@@ -288,6 +288,7 @@ const struct gcc_debug_hooks sdb_debug_hooks =
 {
   sdbout_init,			         /* init */
   sdbout_finish,		         /* finish */
+  debug_nothing_void,			 /* early_finish */
   debug_nothing_void,			 /* assembly_start */
   debug_nothing_int_charstar,	         /* define */
   debug_nothing_int_charstar,	         /* undef */
@@ -304,7 +305,8 @@ const struct gcc_debug_hooks sdb_debug_hooks =
   sdbout_begin_function,	         /* begin_function */
   sdbout_end_function,		         /* end_function */
   debug_nothing_tree,		         /* function_decl */
-  sdbout_global_decl,		         /* global_decl */
+  sdbout_early_global_decl,		 /* early_global_decl */
+  sdbout_late_global_decl,		 /* late_global_decl */
   sdbout_symbol,			 /* type_decl */
   debug_nothing_tree_tree_tree_bool,	 /* imported_module_or_decl */
   debug_nothing_tree,		         /* deferred_inline_function */
@@ -1430,11 +1432,20 @@ sdbout_reg_parms (tree parms)
       }
 }
 
-/* Output debug information for a global DECL.  Called from toplev.c
-   after compilation proper has finished.  */
+/* Output early debug information for a global DECL.  Called from
+   rest_of_decl_compilation during parsing.  */
 
 static void
-sdbout_global_decl (tree decl)
+sdbout_early_global_decl (tree decl ATTRIBUTE_UNUSED)
+{
+  /* NYI for non-dwarf.  */
+}
+
+/* Output late debug information for a global DECL after location
+   information is available.  */
+
+static void
+sdbout_late_global_decl (tree decl)
 {
   if (TREE_CODE (decl) == VAR_DECL
       && !DECL_EXTERNAL (decl)
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 711bbed..d8d42c2 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -31,11 +31,17 @@
 
 /* The total execution time.  */
 DEFTIMEVAR (TV_TOTAL                 , "total time")
-/* The compiler phases.  These must be mutually exclusive.
-   Ideally, they would sum to near the total time.  */
+/* The compiler phases.
+
+   These must be mutually exclusive, and the NAME field must begin
+   with "phase".
+
+   Also, their sum must be within a millionth of the total time (see
+   validate_phases).  */
 DEFTIMEVAR (TV_PHASE_SETUP           , "phase setup")
 DEFTIMEVAR (TV_PHASE_PARSING         , "phase parsing")
 DEFTIMEVAR (TV_PHASE_DEFERRED        , "phase lang. deferred")
+DEFTIMEVAR (TV_PHASE_LATE_PARSING_CLEANUPS, "phase late parsing cleanups")
 DEFTIMEVAR (TV_PHASE_OPT_GEN         , "phase opt and generate")
 DEFTIMEVAR (TV_PHASE_DBGINFO         , "phase debug info")
 DEFTIMEVAR (TV_PHASE_CHECK_DBGINFO   , "phase check & debug info")
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 38de36b..37fee4c 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -497,15 +497,15 @@ wrapup_global_declarations (tree *vec, int len)
   return output_something;
 }
 
-/* A subroutine of check_global_declarations.  Issue appropriate warnings
-   for the global declaration DECL.  */
+/* Issue appropriate warnings for the global declaration DECL.  */
 
 void
-check_global_declaration_1 (tree decl)
+check_global_declaration (tree decl)
 {
   /* Warn about any function declared static but not defined.  We don't
      warn about variables, because many programs have static variables
      that exist only to get some text into the object file.  */
+  symtab_node *snode = symtab_node::get (decl);
   if (TREE_CODE (decl) == FUNCTION_DECL
       && DECL_INITIAL (decl) == 0
       && DECL_EXTERNAL (decl)
@@ -513,9 +513,9 @@ check_global_declaration_1 (tree decl)
       && ! TREE_NO_WARNING (decl)
       && ! TREE_PUBLIC (decl)
       && (warn_unused_function
-	  || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))))
+	  || snode->referred_to_p (/*include_self=*/false)))
     {
-      if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
+      if (snode->referred_to_p (/*include_self=*/false))
 	pedwarn (input_location, 0, "%q+F used but never defined", decl);
       else
 	warning (OPT_Wunused_function, "%q+F declared %<static%> but never defined", decl);
@@ -530,6 +530,10 @@ check_global_declaration_1 (tree decl)
        || (warn_unused_variable
 	   && TREE_CODE (decl) == VAR_DECL && ! TREE_READONLY (decl)))
       && ! DECL_IN_SYSTEM_HEADER (decl)
+      && ! snode->referred_to_p (/*include_self=*/false)
+      /* This TREE_USED check is needed in addition to referred_to_p
+	 above, because the `__unused__' attribute is not being
+	 considered for referred_to_p.  */
       && ! TREE_USED (decl)
       /* The TREE_USED bit for file-scope decls is kept in the identifier,
 	 to handle multiple external decls in different scopes.  */
@@ -540,6 +544,10 @@ check_global_declaration_1 (tree decl)
       && ! TREE_THIS_VOLATILE (decl)
       /* Global register variables must be declared to reserve them.  */
       && ! (TREE_CODE (decl) == VAR_DECL && DECL_REGISTER (decl))
+      /* Global ctors and dtors are called by the runtime.  */
+      && (TREE_CODE (decl) != FUNCTION_DECL
+	  || (!DECL_STATIC_CONSTRUCTOR (decl)
+	      && !DECL_STATIC_DESTRUCTOR (decl)))
       /* Otherwise, ask the language.  */
       && lang_hooks.decls.warn_unused_global (decl))
     warning ((TREE_CODE (decl) == FUNCTION_DECL)
@@ -548,19 +556,8 @@ check_global_declaration_1 (tree decl)
 	     "%q+D defined but not used", decl);
 }
 
-/* Issue appropriate warnings for the global declarations in V (of
-   which there are LEN).  */
-
-void
-check_global_declarations (tree *v, int len)
-{
-  int i;
-
-  for (i = 0; i < len; i++)
-    check_global_declaration_1 (v[i]);
-}
-
-/* Emit debugging information for all global declarations in VEC.  */
+/* Emit late debugging information (post compilation) for all global
+   declarations in VEC.  */
 
 void
 emit_debug_global_declarations (tree *vec, int len)
@@ -573,7 +570,7 @@ emit_debug_global_declarations (tree *vec, int len)
 
   timevar_push (TV_SYMOUT);
   for (i = 0; i < len; i++)
-    debug_hooks->global_decl (vec[i]);
+    debug_hooks->late_global_decl (vec[i]);
   timevar_pop (TV_SYMOUT);
 }
 
@@ -586,8 +583,7 @@ compile_file (void)
   timevar_start (TV_PHASE_PARSING);
   timevar_push (TV_PARSE_GLOBAL);
 
-  /* Call the parser, which parses the entire file (calling
-     rest_of_compilation for each function).  */
+  /* Parse entire file and generate initial debug information.  */
   lang_hooks.parse_file ();
 
   timevar_pop (TV_PARSE_GLOBAL);
@@ -601,12 +597,33 @@ compile_file (void)
 
   ggc_protect_identifiers = false;
 
-  /* This must also call finalize_compilation_unit.  */
-  lang_hooks.decls.final_write_globals ();
+  /* Run the actual compilation process.  */
+  if (!in_lto_p)
+    {
+      timevar_start (TV_PHASE_OPT_GEN);
+      symtab->finalize_compilation_unit ();
+      timevar_stop (TV_PHASE_OPT_GEN);
+    }
+
+  /* Perform any post compilation-proper parser cleanups and
+     processing.  This is currently only needed for the C++ parser,
+     which can be hopefully cleaned up so this hook is no longer
+     necessary.  */
+  if (lang_hooks.decls.post_compilation_parsing_cleanups)
+    lang_hooks.decls.post_compilation_parsing_cleanups ();
 
   if (seen_error ())
     return;
 
+  /* After the parser has generated debugging information, augment
+     this information with any new location/etc information that may
+     have become available after the compilation proper.  */
+  timevar_start (TV_PHASE_DBGINFO);
+  symtab_node *node;
+  FOR_EACH_DEFINED_SYMBOL (node)
+    debug_hooks->late_global_decl (node->decl);
+  timevar_stop (TV_PHASE_DBGINFO);
+
   timevar_start (TV_PHASE_LATE_ASM);
 
   /* Compilation unit is finalized.  When producing non-fat LTO object, we are
diff --git a/gcc/toplev.h b/gcc/toplev.h
index 9527f76..732f7e9 100644
--- a/gcc/toplev.h
+++ b/gcc/toplev.h
@@ -59,10 +59,11 @@ extern void announce_function (tree);
 extern void wrapup_global_declaration_1 (tree);
 extern bool wrapup_global_declaration_2 (tree);
 extern bool wrapup_global_declarations (tree *, int);
-extern void check_global_declaration_1 (tree);
-extern void check_global_declarations (tree *, int);
+extern void check_global_declaration (tree);
+
 extern void emit_debug_global_declarations (tree *, int);
-extern void write_global_declarations (void);
+
+extern void global_decl_processing (void);
 
 extern void dump_memory_report (bool);
 extern void dump_profile_report (void);
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index ad1bb23..2a9f417 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1334,6 +1334,9 @@ struct GTY(()) tree_block {
   tree abstract_origin;
   tree fragment_origin;
   tree fragment_chain;
+
+  /* Pointer to the DWARF lexical block.  */
+  struct die_struct *die;
 };
 
 struct GTY(()) tree_type_common {
diff --git a/gcc/tree.h b/gcc/tree.h
index 1974186..c29d503 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1584,6 +1584,7 @@ extern void protected_set_expr_location (tree, location_t);
 #define BLOCK_CHAIN(NODE) (BLOCK_CHECK (NODE)->block.chain)
 #define BLOCK_ABSTRACT_ORIGIN(NODE) (BLOCK_CHECK (NODE)->block.abstract_origin)
 #define BLOCK_ABSTRACT(NODE) (BLOCK_CHECK (NODE)->block.abstract_flag)
+#define BLOCK_DIE(NODE) (BLOCK_CHECK (NODE)->block.die)
 
 /* True if BLOCK has the same ranges as its BLOCK_SUPERCONTEXT.  */
 #define BLOCK_SAME_RANGE(NODE) (BLOCK_CHECK (NODE)->base.u.bits.nameless_flag)
diff --git a/gcc/vmsdbgout.c b/gcc/vmsdbgout.c
index 23d8365..7d70c1f 100644
--- a/gcc/vmsdbgout.c
+++ b/gcc/vmsdbgout.c
@@ -174,7 +174,8 @@ static void vmsdbgout_begin_epilogue (unsigned int, const char *);
 static void vmsdbgout_end_epilogue (unsigned int, const char *);
 static void vmsdbgout_begin_function (tree);
 static void vmsdbgout_decl (tree);
-static void vmsdbgout_global_decl (tree);
+static void vmsdbgout_early_global_decl (tree);
+static void vmsdbgout_late_global_decl (tree);
 static void vmsdbgout_type_decl (tree, int);
 static void vmsdbgout_abstract_function (tree);
 
@@ -183,6 +184,7 @@ static void vmsdbgout_abstract_function (tree);
 const struct gcc_debug_hooks vmsdbg_debug_hooks
 = {vmsdbgout_init,
    vmsdbgout_finish,
+   debug_nothing_void,
    vmsdbgout_assembly_start,
    vmsdbgout_define,
    vmsdbgout_undef,
@@ -198,8 +200,9 @@ const struct gcc_debug_hooks vmsdbg_debug_hooks
    vmsdbgout_end_epilogue,
    vmsdbgout_begin_function,
    vmsdbgout_end_function,
-   vmsdbgout_decl,
-   vmsdbgout_global_decl,
+   vmsdbgout_function_decl,
+   vmsdbgout_early_global_decl,
+   vmsdbgout_late_global_decl,
    vmsdbgout_type_decl,		  /* type_decl */
    debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
    debug_nothing_tree,		  /* deferred_inline_function */
@@ -1512,7 +1515,7 @@ vmsdbgout_undef (unsigned int lineno, const char *buffer)
 /* Not implemented in VMS Debug.  */
 
 static void
-vmsdbgout_decl (tree decl)
+vmsdbgout_function_decl (tree decl)
 {
   if (write_symbols == VMS_AND_DWARF2_DEBUG)
     (*dwarf2_debug_hooks.function_decl) (decl);
@@ -1521,10 +1524,19 @@ vmsdbgout_decl (tree decl)
 /* Not implemented in VMS Debug.  */
 
 static void
-vmsdbgout_global_decl (tree decl)
+vmsdbgout_early_global_decl (tree decl)
 {
   if (write_symbols == VMS_AND_DWARF2_DEBUG)
-    (*dwarf2_debug_hooks.global_decl) (decl);
+    (*dwarf2_debug_hooks.early_global_decl) (decl);
+}
+
+/* Not implemented in VMS Debug.  */
+
+static void
+vmsdbgout_late_global_decl (tree decl)
+{
+  if (write_symbols == VMS_AND_DWARF2_DEBUG)
+    (*dwarf2_debug_hooks.late_global_decl) (decl);
 }
 
 /* Not implemented in VMS Debug.  */

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-08  0:41 [patch 10/10] debug-early merge: compiler proper Aldy Hernandez
@ 2015-05-18 11:06 ` Richard Biener
  2015-05-18 14:47   ` Jan Hubicka
       [not found]   ` <555CAD35.5040304@redhat.com>
  0 siblings, 2 replies; 34+ messages in thread
From: Richard Biener @ 2015-05-18 11:06 UTC (permalink / raw)
  To: Aldy Hernandez, Jan Hubicka, Jason Merrill; +Cc: gcc-patches

On Fri, May 8, 2015 at 2:40 AM, Aldy Hernandez <aldyh@redhat.com> wrote:
> As seen on TV.

+/* FIRST_TIME is set to TRUE for the first time we are called for a
+   translation unit from finalize_compilation_unit() or false
+   otherwise.  */
+
 static void
-analyze_functions (void)
+analyze_functions (bool first_time)
 {
...
+  if (first_time)
+    {
+      symtab_node *snode;
+      FOR_EACH_SYMBOL (snode)
+       check_global_declaration (snode->decl);
+    }
+

I think it is better to split analyze_functions (why does it have it's own copy
of unreachable node removal?) into analysis and unused-symbol removal
and have the
check_global_declaration call be in finalize_compilation_unit directly.  Honza?

@@ -1113,6 +1131,19 @@ analyze_functions (void)
        {
          if (symtab->dump_file)
            fprintf (symtab->dump_file, " %s", node->name ());
+
+         /* See if the debugger can use anything before the DECL
+            passes away.  Perhaps it can notice a DECL that is now a
+            constant and can tag the early DIE with an appropriate
+            attribute.
+
+            Otherwise, this is the last chance the debug_hooks have
+            at looking at optimized away DECLs, since
+            late_global_decl will subsequently be called from the
+            contents of the now pruned symbol table.  */
+         if (!decl_function_context (node->decl))
+           (*debug_hooks->late_global_decl) (node->decl);
+
          node->remove ();

so this applies to VAR_DECLs only - shouldn't this be in the
varpool_node::remove function then?  You can even register/deregister
a hook for this in finalize_compilation_unit.  That would IMHO be better.

All debug stuff apart from dwarf2out.c changes (I assume Jason reviews
them) are ok.

diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index 02012d5..15b6dd2 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -4718,7 +4718,8 @@ write_roots (pair_p variables, bool emit_pch)
    this funcion will have to be adjusted to be more like
    output_mangled_typename.  */

-static void
+/* ?? Why are we keeping this?  Is this actually used anywhere?  */
+static void ATTRIBUTE_UNUSED
 output_typename (outf_p of, const_type_p t)
 {
   switch (t->kind)

Just remove the function.

The langhooks changes are ok.

diff --git a/gcc/passes.c b/gcc/passes.c
index 04ff042..4dee8ad 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -293,6 +293,28 @@ rest_of_decl_compilation (tree decl,
   else if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl)
           && TREE_STATIC (decl))
     varpool_node::get_create (decl);
+
+  /* Generate early debug for global variables.  Any local variables will
+     be handled by either handling reachable functions from
+     finalize_compilation_unit (and by consequence, locally scoped
+     symbols), or by rest_of_type_compilation below.
+
+     Also, pick up function prototypes, which will be mostly ignored
+     by the different early_global_decl() hooks, but will at least be
+     used by Go's hijack of the debug_hooks to implement
+     -fdump-go-spec.  */
+  if (!flag_wpa
+      && !in_lto_p

Just check !in_lto_p, !flag_wpa is redundant.

+      && !decl_function_context (decl)
+      && !current_function_decl

Why that?  !decl_function_context should catch relevant cases?

+      && !decl_type_context (decl))
+    (*debug_hooks->early_global_decl) (decl);

I'll note that nested functions and class methods are not getting
early_global_decl()ed here.  I suppose their containing function/type
is supposed to generate early dwarf by means of dwarf2out walking
over children.

timevar changes are ok.

the toplev changes are ok.

diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index ad1bb23..2a9f417 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1334,6 +1334,9 @@ struct GTY(()) tree_block {
   tree abstract_origin;
   tree fragment_origin;
   tree fragment_chain;
+
+  /* Pointer to the DWARF lexical block.  */
+  struct die_struct *die;
 };

 struct GTY(()) tree_type_common {

Ick - do we need this?  dwarf2out.c has a hashtable to map blocks to
DIEs (which you don't remove in turn).

Jason - did you intentionally not yet "approve" the dwarf2out.c
changes (like, are you expecting somebody else
to do a review)?

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-18 11:06 ` Richard Biener
@ 2015-05-18 14:47   ` Jan Hubicka
       [not found]   ` <555CAD35.5040304@redhat.com>
  1 sibling, 0 replies; 34+ messages in thread
From: Jan Hubicka @ 2015-05-18 14:47 UTC (permalink / raw)
  To: Richard Biener; +Cc: Aldy Hernandez, Jan Hubicka, Jason Merrill, gcc-patches

> On Fri, May 8, 2015 at 2:40 AM, Aldy Hernandez <aldyh@redhat.com> wrote:
> > As seen on TV.
> 
> +/* FIRST_TIME is set to TRUE for the first time we are called for a
> +   translation unit from finalize_compilation_unit() or false
> +   otherwise.  */
> +
>  static void
> -analyze_functions (void)
> +analyze_functions (bool first_time)
>  {
> ...
> +  if (first_time)
> +    {
> +      symtab_node *snode;
> +      FOR_EACH_SYMBOL (snode)
> +       check_global_declaration (snode->decl);
> +    }
> +
> 
> I think it is better to split analyze_functions (why does it have it's own copy
> of unreachable node removal?) into analysis and unused-symbol removal
> and have the
> check_global_declaration call be in finalize_compilation_unit directly.  Honza?

It is trying to avoid analyzing functions that are never used. Analyzing
include gimplification and other stuff that is not for free.
remove_unreachable_nodes works only on fully built cgraph.

Main reason why analyze_functions is intended to be called multiple times was
--combine support.  After each end of C source file you called
symbol_table::finalize_compilation_unit which did unreachable code removal and
saved some memory.

I am not sure symbol table is useful for debug info this way: we insert only
function definitions into symbol table and external declarations are inserted
lazilly.  That is why we still have the (convoluted) check_global_declarations
that walks the vectors provided by frontends.
> 
> @@ -1113,6 +1131,19 @@ analyze_functions (void)
>         {
>           if (symtab->dump_file)
>             fprintf (symtab->dump_file, " %s", node->name ());
> +
> +         /* See if the debugger can use anything before the DECL
> +            passes away.  Perhaps it can notice a DECL that is now a
> +            constant and can tag the early DIE with an appropriate
> +            attribute.
> +
> +            Otherwise, this is the last chance the debug_hooks have
> +            at looking at optimized away DECLs, since
> +            late_global_decl will subsequently be called from the
> +            contents of the now pruned symbol table.  */
> +         if (!decl_function_context (node->decl))
> +           (*debug_hooks->late_global_decl) (node->decl);
> +
>           node->remove ();
> 
> so this applies to VAR_DECLs only - shouldn't this be in the
> varpool_node::remove function then?  You can even register/deregister
> a hook for this in finalize_compilation_unit.  That would IMHO be better.

There is varpool_node::remove_initializer that is intended to throw away the
constructor.  I suppose late_global_decl can be called from there?
> @@ -1334,6 +1334,9 @@ struct GTY(()) tree_block {
>    tree abstract_origin;
>    tree fragment_origin;
>    tree fragment_chain;
> +
> +  /* Pointer to the DWARF lexical block.  */
> +  struct die_struct *die;
>  };
> 
>  struct GTY(()) tree_type_common {
> 
> Ick - do we need this?  dwarf2out.c has a hashtable to map blocks to
> DIEs (which you don't remove in turn).

Note that types also have tree_type_symtab that in turn contains die pointer.

Honza
> 
> Jason - did you intentionally not yet "approve" the dwarf2out.c
> changes (like, are you expecting somebody else
> to do a review)?
> 
> Thanks,
> Richard.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
       [not found]   ` <555CAD35.5040304@redhat.com>
@ 2015-05-20 21:03     ` Aldy Hernandez
  2015-05-20 21:11       ` Jan Hubicka
  2015-05-22 11:26     ` Richard Biener
  2015-05-27 12:50     ` Jason Merrill
  2 siblings, 1 reply; 34+ messages in thread
From: Aldy Hernandez @ 2015-05-20 21:03 UTC (permalink / raw)
  To: Richard Biener, Jan Hubicka, Jason Merrill; +Cc: gcc-patches


> How does this version, which has been committed to the debug-early
> branch, look?

One more thing Richi.  I merged trunk into the branch once again, and Go 
broke.  I tracked it down to a temporary that was being created late 
that IMO shouldn't even get debug info.

The fact that it gets created with create_tmp_var_name() in the first 
place is suspect.  The problem is actually the type, which doesn't even 
get passed through rest_of_type* or the debug_hooks->type_decl(). 
However, I see no reason to have these temporary variables even get fed 
to the debugger, so I'm marking them as DECL_IGNORED_P.

If you want I can repost the whole compiler proper patch, but this is a 
small enough change that y'all can just wave through.

I've committed the snippet below to the branch.  Everything else is as 
it was.

Branch retested on x86-64 Linux and has been merged with trunk.

commit 8824b5ecba26cef065e47b34609c72677c3c36fc
Author: Aldy Hernandez <aldyh@redhat.com>
Date:   Wed May 20 16:31:14 2015 -0400

     Set DECL_IGNORED_P on temporary arrays created in the switch
     conversion pass.

diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c
index 6b68a16..a4bcdba 100644
--- a/gcc/tree-switch-conversion.c
+++ b/gcc/tree-switch-conversion.c
@@ -1097,6 +1097,7 @@ build_one_array (gswitch *swtch, int num, tree 
arr_index_type,
        DECL_ARTIFICIAL (decl) = 1;
        TREE_CONSTANT (decl) = 1;
        TREE_READONLY (decl) = 1;
+      DECL_IGNORED_P (decl) = 1;
        varpool_node::finalize_decl (decl);

        fetch = build4 (ARRAY_REF, value_type, decl, tidx, NULL_TREE,

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-20 21:03     ` Aldy Hernandez
@ 2015-05-20 21:11       ` Jan Hubicka
  2015-05-20 22:11         ` Aldy Hernandez
  0 siblings, 1 reply; 34+ messages in thread
From: Jan Hubicka @ 2015-05-20 21:11 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Richard Biener, Jan Hubicka, Jason Merrill, gcc-patches

> 
> commit 8824b5ecba26cef065e47b34609c72677c3c36fc
> Author: Aldy Hernandez <aldyh@redhat.com>
> Date:   Wed May 20 16:31:14 2015 -0400
> 
>     Set DECL_IGNORED_P on temporary arrays created in the switch
>     conversion pass.
> 
> diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c
> index 6b68a16..a4bcdba 100644
> --- a/gcc/tree-switch-conversion.c
> +++ b/gcc/tree-switch-conversion.c
> @@ -1097,6 +1097,7 @@ build_one_array (gswitch *swtch, int num, tree
> arr_index_type,
>        DECL_ARTIFICIAL (decl) = 1;
>        TREE_CONSTANT (decl) = 1;
>        TREE_READONLY (decl) = 1;
> +      DECL_IGNORED_P (decl) = 1;
>        varpool_node::finalize_decl (decl);

This looks obvious enough to me.  Technically speaking the array type constructed
probalby should be TREE_ARTIFICAIL, but probably it does not matter.
If you grep for finalize_decl, there are several other calls:
asan.c:      varpool_node::finalize_decl (var);
asan.c:      varpool_node::finalize_decl (var);
cgraphbuild.c:      varpool_node::finalize_decl (decl);
cgraphunit.c:    - varpool_finalize_decl
cgraphunit.c:   varpool_node::finalize_decl (decl);
cgraphunit.c:varpool_node::finalize_decl (tree decl)
coverage.c:           varpool_node::finalize_decl (var);
coverage.c:  varpool_node::finalize_decl (var);
coverage.c:  varpool_node::finalize_decl (fn_info_ary);
coverage.c:  varpool_node::finalize_decl (gcov_info_var);
omp-low.c:        varpool_node::finalize_decl (t);
omp-low.c:        varpool_node::finalize_decl (t);
omp-low.c:        varpool_node::finalize_decl (decl);
omp-low.c:      varpool_node::finalize_decl (vars_decl);
omp-low.c:      varpool_node::finalize_decl (funcs_decl);
passes.c:           varpool_node::finalize_decl (decl);
tree-chkp.c:  varpool_node::finalize_decl (var);
tree-chkp.c:  varpool_node::finalize_decl (bnd_var);
tree-profile.c:  varpool_node::finalize_decl (ic_void_ptr_var);
tree-profile.c:  varpool_node::finalize_decl (ic_gcov_type_ptr_var);
tree-switch-conversion.c:      varpool_node::finalize_decl (decl);
ubsan.c:  varpool_node::finalize_decl (decl);
ubsan.c:  varpool_node::finalize_decl (var);
ubsan.c:      varpool_node::finalize_decl (array);
varasm.c:  varpool_node::finalize_decl (decl);
varpool.c:   Unlike finalize_decl function is intended to be used
varpool.c:  varpool_node::finalize_decl (decl);

I would say most of them needs similar treatment (I am not 100% sure about OMP
ones that may be user visible)

Honza
> 
>        fetch = build4 (ARRAY_REF, value_type, decl, tidx, NULL_TREE,

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-20 21:11       ` Jan Hubicka
@ 2015-05-20 22:11         ` Aldy Hernandez
  2015-05-22  9:00           ` Eric Botcazou
  2015-05-22 11:45           ` Richard Biener
  0 siblings, 2 replies; 34+ messages in thread
From: Aldy Hernandez @ 2015-05-20 22:11 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Richard Biener, Jason Merrill, gcc-patches

On 05/20/2015 05:01 PM, Jan Hubicka wrote:
>>
>> commit 8824b5ecba26cef065e47b34609c72677c3c36fc
>> Author: Aldy Hernandez <aldyh@redhat.com>
>> Date:   Wed May 20 16:31:14 2015 -0400
>>
>>      Set DECL_IGNORED_P on temporary arrays created in the switch
>>      conversion pass.
>>
>> diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c
>> index 6b68a16..a4bcdba 100644
>> --- a/gcc/tree-switch-conversion.c
>> +++ b/gcc/tree-switch-conversion.c
>> @@ -1097,6 +1097,7 @@ build_one_array (gswitch *swtch, int num, tree
>> arr_index_type,
>>         DECL_ARTIFICIAL (decl) = 1;
>>         TREE_CONSTANT (decl) = 1;
>>         TREE_READONLY (decl) = 1;
>> +      DECL_IGNORED_P (decl) = 1;
>>         varpool_node::finalize_decl (decl);
>
> This looks obvious enough to me.  Technically speaking the array type constructed
> probalby should be TREE_ARTIFICAIL, but probably it does not matter.

Yeah, that's what I thought.  I ignored the type because it won't make 
it to the debugging back end if we stop things at the DECL itself.

FWIW, Ada is filled with these temporaries and/or types that should 
really be ignored, and are currently causing grief.

> If you grep for finalize_decl, there are several other calls:
> asan.c:      varpool_node::finalize_decl (var);
> asan.c:      varpool_node::finalize_decl (var);
> cgraphbuild.c:      varpool_node::finalize_decl (decl);
> cgraphunit.c:    - varpool_finalize_decl
> cgraphunit.c:   varpool_node::finalize_decl (decl);
> cgraphunit.c:varpool_node::finalize_decl (tree decl)
> coverage.c:           varpool_node::finalize_decl (var);
> coverage.c:  varpool_node::finalize_decl (var);

Etc etc.

Hmmm, I bet mainline is generating dwarf for all this.  I don't feel 
comfortable touching all this (ok, I'm lazy), but it would seem like 
almost all of these calls would benefit from DECL_IGNORED_P.  Perhaps we 
could add an argument to finalize_decl() and do it in there.

Aldy

> coverage.c:  varpool_node::finalize_decl (fn_info_ary);
> coverage.c:  varpool_node::finalize_decl (gcov_info_var);
> omp-low.c:        varpool_node::finalize_decl (t);
> omp-low.c:        varpool_node::finalize_decl (t);
> omp-low.c:        varpool_node::finalize_decl (decl);
> omp-low.c:      varpool_node::finalize_decl (vars_decl);
> omp-low.c:      varpool_node::finalize_decl (funcs_decl);
> passes.c:           varpool_node::finalize_decl (decl);
> tree-chkp.c:  varpool_node::finalize_decl (var);
> tree-chkp.c:  varpool_node::finalize_decl (bnd_var);
> tree-profile.c:  varpool_node::finalize_decl (ic_void_ptr_var);
> tree-profile.c:  varpool_node::finalize_decl (ic_gcov_type_ptr_var);
> tree-switch-conversion.c:      varpool_node::finalize_decl (decl);
> ubsan.c:  varpool_node::finalize_decl (decl);
> ubsan.c:  varpool_node::finalize_decl (var);
> ubsan.c:      varpool_node::finalize_decl (array);
> varasm.c:  varpool_node::finalize_decl (decl);
> varpool.c:   Unlike finalize_decl function is intended to be used
> varpool.c:  varpool_node::finalize_decl (decl);
>
> I would say most of them needs similar treatment (I am not 100% sure about OMP
> ones that may be user visible)
>
> Honza
>>
>>         fetch = build4 (ARRAY_REF, value_type, decl, tidx, NULL_TREE,

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-20 22:11         ` Aldy Hernandez
@ 2015-05-22  9:00           ` Eric Botcazou
  2015-05-22 11:45           ` Richard Biener
  1 sibling, 0 replies; 34+ messages in thread
From: Eric Botcazou @ 2015-05-22  9:00 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: gcc-patches, Jan Hubicka, Richard Biener, Jason Merrill

> FWIW, Ada is filled with these temporaries and/or types that should
> really be ignored, and are currently causing grief.

It's a little hard to believe that types created in a front-end should be 
marked ignored.  Either they are used by some objects and thus can be needed 
in the debug info, or they aren't and will be discarded by -feliminate-unused-
debug-types.  And those not present in the source should be marked artificial.

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
       [not found]   ` <555CAD35.5040304@redhat.com>
  2015-05-20 21:03     ` Aldy Hernandez
@ 2015-05-22 11:26     ` Richard Biener
  2015-05-22 14:29       ` Aldy Hernandez
  2015-05-27 12:50     ` Jason Merrill
  2 siblings, 1 reply; 34+ messages in thread
From: Richard Biener @ 2015-05-22 11:26 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Jan Hubicka, Jason Merrill, gcc-patches

On Wed, May 20, 2015 at 5:50 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
> On 05/18/2015 06:56 AM, Richard Biener wrote:
>
> BTW, thanks for the review.
>
>> On Fri, May 8, 2015 at 2:40 AM, Aldy Hernandez <aldyh@redhat.com> wrote:
>>>
>>> As seen on TV.
>>
>>
>> +/* FIRST_TIME is set to TRUE for the first time we are called for a
>> +   translation unit from finalize_compilation_unit() or false
>> +   otherwise.  */
>> +
>>   static void
>> -analyze_functions (void)
>> +analyze_functions (bool first_time)
>>   {
>> ...
>> +  if (first_time)
>> +    {
>> +      symtab_node *snode;
>> +      FOR_EACH_SYMBOL (snode)
>> +       check_global_declaration (snode->decl);
>> +    }
>> +
>>
>> I think it is better to split analyze_functions (why does it have it's own
>> copy
>> of unreachable node removal?) into analysis and unused-symbol removal
>> and have the
>> check_global_declaration call be in finalize_compilation_unit directly.
>> Honza?
>
>
> Leaving things as is, as per Honza's comment ??
>
>>
>> @@ -1113,6 +1131,19 @@ analyze_functions (void)
>>          {
>>            if (symtab->dump_file)
>>              fprintf (symtab->dump_file, " %s", node->name ());
>> +
>> +         /* See if the debugger can use anything before the DECL
>> +            passes away.  Perhaps it can notice a DECL that is now a
>> +            constant and can tag the early DIE with an appropriate
>> +            attribute.
>> +
>> +            Otherwise, this is the last chance the debug_hooks have
>> +            at looking at optimized away DECLs, since
>> +            late_global_decl will subsequently be called from the
>> +            contents of the now pruned symbol table.  */
>> +         if (!decl_function_context (node->decl))
>> +           (*debug_hooks->late_global_decl) (node->decl);
>> +
>>            node->remove ();
>>
>> so this applies to VAR_DECLs only - shouldn't this be in the
>> varpool_node::remove function then?  You can even register/deregister
>> a hook for this in finalize_compilation_unit.  That would IMHO be better.
>
>
> The problem is that varpool_node::remove() may be called before we
> have finished parsing the DECL, thus before we call
> early_global_decl() on it.  So we would essentially be calling
> late_global_decl() on a DECL for which we haven't called
> early_global_decl().
>
> To complicate matters, we may call ::remove() before we finish parsing
> a decl.  In the C front-end, for instance, we call ::remove() from
> duplicate_decls(), before we even call rest_of_decl_compilation (where
> we call early_global_decl).
>
> Calling late_global_decl so early, before we have even finished
> parsing, seems wrong and obviously causes problems.  One example is
> dwarf2out can put the DECL into the deferred_asm_names list, only to
> have duplicate_decls() gcc_free it from under us.
>
>>
>> All debug stuff apart from dwarf2out.c changes (I assume Jason reviews
>> them) are ok.
>>
>> diff --git a/gcc/gengtype.c b/gcc/gengtype.c
>> index 02012d5..15b6dd2 100644
>> --- a/gcc/gengtype.c
>> +++ b/gcc/gengtype.c
>> @@ -4718,7 +4718,8 @@ write_roots (pair_p variables, bool emit_pch)
>>      this funcion will have to be adjusted to be more like
>>      output_mangled_typename.  */
>>
>> -static void
>> +/* ?? Why are we keeping this?  Is this actually used anywhere?  */
>> +static void ATTRIBUTE_UNUSED
>>   output_typename (outf_p of, const_type_p t)
>>   {
>>     switch (t->kind)
>>
>> Just remove the function.
>
>
> Done.
>
>>
>> The langhooks changes are ok.
>>
>> diff --git a/gcc/passes.c b/gcc/passes.c
>> index 04ff042..4dee8ad 100644
>> --- a/gcc/passes.c
>> +++ b/gcc/passes.c
>> @@ -293,6 +293,28 @@ rest_of_decl_compilation (tree decl,
>>     else if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl)
>>             && TREE_STATIC (decl))
>>       varpool_node::get_create (decl);
>> +
>> +  /* Generate early debug for global variables.  Any local variables will
>> +     be handled by either handling reachable functions from
>> +     finalize_compilation_unit (and by consequence, locally scoped
>> +     symbols), or by rest_of_type_compilation below.
>> +
>> +     Also, pick up function prototypes, which will be mostly ignored
>> +     by the different early_global_decl() hooks, but will at least be
>> +     used by Go's hijack of the debug_hooks to implement
>> +     -fdump-go-spec.  */
>> +  if (!flag_wpa
>> +      && !in_lto_p
>>
>> Just check !in_lto_p, !flag_wpa is redundant.
>
>
> Done.
>
>>
>> +      && !decl_function_context (decl)
>> +      && !current_function_decl
>>
>> Why that?  !decl_function_context should catch relevant cases?
>
>
> You'd think, huh?  The issue here are extern declarations appearing
> inside of a function.  For this case, decl_function_context is NULL,
> because the actual context is toplevel, but current_function_decl is
> set to the function where the extern declaration appears.
>
> For example:
>
> namespace S
> {
>   int
>   f()
>   {
>     {
>       int i = 42;
>       {
>         extern int i; // Local extern declaration.
>         return i;
>       }
>     }
>   }
> }
>
> I have added a big fat comment in the code now, since it's clearly not
> obvious why we need current_function_decl.
>
>>
>> +      && !decl_type_context (decl))
>> +    (*debug_hooks->early_global_decl) (decl);
>>
>> I'll note that nested functions and class methods are not getting
>> early_global_decl()ed here.  I suppose their containing function/type
>> is supposed to generate early dwarf by means of dwarf2out walking
>> over children.
>
>
> Indeed, and I had properly commented this:
>
>   /* Emit early debug for reachable functions, and by consequence,
>      locally scoped symbols.  */
>   struct cgraph_node *cnode;
>   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cnode)
>     (*debug_hooks->early_global_decl) (cnode->decl);
>
> I did, however, remove the !decl_function_context() restriction in this
> snippet from the previous iteration of this patch because of the nested
> function problem you mention.
>
> Doubly nested functions were fine because dwarf2out will walk the inner
> function, by virtue of it being a symbol local to the top level function,
> however it was missing triply nested functions because the 2nd nested
> functions was considered a declaration so its children (> 2 nested
> functions) were not walked.  I ran into this with Ada, and removed the
> !decl_function_context() while generating early dwarf. IIRC, the restriction
> was originally there to limit extra DIEs that may be generated, but since
> I'm already on the hook for cleaning up DIEs shortly after the merge, we're
> going to have deal with this anyhow.
>
> I also added a test for triply nested functions for C+debug-early, since Ada
> seemed to be the only front-end stressing >= 3 nested functions.  I will
> repost the test when I repost the testsuite changes.
>
>>
>> timevar changes are ok.
>>
>> the toplev changes are ok.
>>
>> diff --git a/gcc/tree-core.h b/gcc/tree-core.h
>> index ad1bb23..2a9f417 100644
>> --- a/gcc/tree-core.h
>> +++ b/gcc/tree-core.h
>> @@ -1334,6 +1334,9 @@ struct GTY(()) tree_block {
>>     tree abstract_origin;
>>     tree fragment_origin;
>>     tree fragment_chain;
>> +
>> +  /* Pointer to the DWARF lexical block.  */
>> +  struct die_struct *die;
>>   };
>>
>>   struct GTY(()) tree_type_common {
>>
>> Ick - do we need this?  dwarf2out.c has a hashtable to map blocks to
>> DIEs (which you don't remove in turn).
>
>
> We need a way to reference the early created DIE from late debugging, and we
> can't use block_map because it gets cloberred across functions. It's
> currently being released in late debug (dwarf2out_function_decl),
> that's why you see it not set to NULL in dwarf2out_c_finalize.
>
> Also, it uses BLOCK_NUMBERs, which according to the documentation in
> tree.h, are not guaranteed to be unique across functions.
>
> As Honza mentioned, we're already using a DIE map in types through
> TYPE_SYMTAB_DIE.  See lookup_type_die() in dwarf2out.c.
>
> Could we leave this as is?

But why then not eliminate block_map in favor of using the new ->die member?
Having both looks very odd to me.

Can you cook up a patch for trunk adding that field to tree_block and removing
the block_map map in favor of sth like what we do for
lookup_type_die/equate_type_number_to_die
and TYPE_SYMTAB_DIE?

> How does this version, which has been committed to the debug-early branch,
> look?

No further look right now, but I assume it's fine apart from the
block_map issue (and dwarf2out.c of course).

Richard.

> Aldy

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-20 22:11         ` Aldy Hernandez
  2015-05-22  9:00           ` Eric Botcazou
@ 2015-05-22 11:45           ` Richard Biener
  2015-05-22 13:41             ` Aldy Hernandez
  1 sibling, 1 reply; 34+ messages in thread
From: Richard Biener @ 2015-05-22 11:45 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Jan Hubicka, Jason Merrill, gcc-patches

On Wed, May 20, 2015 at 11:45 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
> On 05/20/2015 05:01 PM, Jan Hubicka wrote:
>>>
>>>
>>> commit 8824b5ecba26cef065e47b34609c72677c3c36fc
>>> Author: Aldy Hernandez <aldyh@redhat.com>
>>> Date:   Wed May 20 16:31:14 2015 -0400
>>>
>>>      Set DECL_IGNORED_P on temporary arrays created in the switch
>>>      conversion pass.
>>>
>>> diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c
>>> index 6b68a16..a4bcdba 100644
>>> --- a/gcc/tree-switch-conversion.c
>>> +++ b/gcc/tree-switch-conversion.c
>>> @@ -1097,6 +1097,7 @@ build_one_array (gswitch *swtch, int num, tree
>>> arr_index_type,
>>>         DECL_ARTIFICIAL (decl) = 1;
>>>         TREE_CONSTANT (decl) = 1;
>>>         TREE_READONLY (decl) = 1;
>>> +      DECL_IGNORED_P (decl) = 1;
>>>         varpool_node::finalize_decl (decl);
>>
>>
>> This looks obvious enough to me.  Technically speaking the array type
>> constructed
>> probalby should be TREE_ARTIFICAIL, but probably it does not matter.

Fine to commit to trunk btw.

>
> Yeah, that's what I thought.  I ignored the type because it won't make it to
> the debugging back end if we stop things at the DECL itself.
>
> FWIW, Ada is filled with these temporaries and/or types that should really
> be ignored, and are currently causing grief.
>
>> If you grep for finalize_decl, there are several other calls:
>> asan.c:      varpool_node::finalize_decl (var);
>> asan.c:      varpool_node::finalize_decl (var);
>> cgraphbuild.c:      varpool_node::finalize_decl (decl);
>> cgraphunit.c:    - varpool_finalize_decl
>> cgraphunit.c:   varpool_node::finalize_decl (decl);
>> cgraphunit.c:varpool_node::finalize_decl (tree decl)
>> coverage.c:           varpool_node::finalize_decl (var);
>> coverage.c:  varpool_node::finalize_decl (var);
>
>
> Etc etc.
>
> Hmmm, I bet mainline is generating dwarf for all this.  I don't feel
> comfortable touching all this (ok, I'm lazy), but it would seem like almost
> all of these calls would benefit from DECL_IGNORED_P.  Perhaps we could add
> an argument to finalize_decl() and do it in there.

The only issue are in passes using build_decl directly.  I guess we'd want
a middle-end-ish "create new global static" similar to what we have for
locals (create_tmp_var).  Some of the callers above already set DECL_IGNORED_P
properly.

Richard.

> Aldy
>
>
>> coverage.c:  varpool_node::finalize_decl (fn_info_ary);
>> coverage.c:  varpool_node::finalize_decl (gcov_info_var);
>> omp-low.c:        varpool_node::finalize_decl (t);
>> omp-low.c:        varpool_node::finalize_decl (t);
>> omp-low.c:        varpool_node::finalize_decl (decl);
>> omp-low.c:      varpool_node::finalize_decl (vars_decl);
>> omp-low.c:      varpool_node::finalize_decl (funcs_decl);
>> passes.c:           varpool_node::finalize_decl (decl);
>> tree-chkp.c:  varpool_node::finalize_decl (var);
>> tree-chkp.c:  varpool_node::finalize_decl (bnd_var);
>> tree-profile.c:  varpool_node::finalize_decl (ic_void_ptr_var);
>> tree-profile.c:  varpool_node::finalize_decl (ic_gcov_type_ptr_var);
>> tree-switch-conversion.c:      varpool_node::finalize_decl (decl);
>> ubsan.c:  varpool_node::finalize_decl (decl);
>> ubsan.c:  varpool_node::finalize_decl (var);
>> ubsan.c:      varpool_node::finalize_decl (array);
>> varasm.c:  varpool_node::finalize_decl (decl);
>> varpool.c:   Unlike finalize_decl function is intended to be used
>> varpool.c:  varpool_node::finalize_decl (decl);
>>
>> I would say most of them needs similar treatment (I am not 100% sure about
>> OMP
>> ones that may be user visible)
>>
>> Honza
>>>
>>>
>>>         fetch = build4 (ARRAY_REF, value_type, decl, tidx, NULL_TREE,
>
>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-22 11:45           ` Richard Biener
@ 2015-05-22 13:41             ` Aldy Hernandez
  0 siblings, 0 replies; 34+ messages in thread
From: Aldy Hernandez @ 2015-05-22 13:41 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jan Hubicka, gcc-patches

On 05/22/2015 07:26 AM, Richard Biener wrote:
> On Wed, May 20, 2015 at 11:45 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
>> On 05/20/2015 05:01 PM, Jan Hubicka wrote:
>>>>
>>>>
>>>> commit 8824b5ecba26cef065e47b34609c72677c3c36fc
>>>> Author: Aldy Hernandez <aldyh@redhat.com>
>>>> Date:   Wed May 20 16:31:14 2015 -0400
>>>>
>>>>       Set DECL_IGNORED_P on temporary arrays created in the switch
>>>>       conversion pass.
>>>>
>>>> diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c
>>>> index 6b68a16..a4bcdba 100644
>>>> --- a/gcc/tree-switch-conversion.c
>>>> +++ b/gcc/tree-switch-conversion.c
>>>> @@ -1097,6 +1097,7 @@ build_one_array (gswitch *swtch, int num, tree
>>>> arr_index_type,
>>>>          DECL_ARTIFICIAL (decl) = 1;
>>>>          TREE_CONSTANT (decl) = 1;
>>>>          TREE_READONLY (decl) = 1;
>>>> +      DECL_IGNORED_P (decl) = 1;
>>>>          varpool_node::finalize_decl (decl);
>>>
>>>
>>> This looks obvious enough to me.  Technically speaking the array type
>>> constructed
>>> probalby should be TREE_ARTIFICAIL, but probably it does not matter.
>
> Fine to commit to trunk btw.

Tested independently on trunk, and committed there.

Thanks.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-22 11:26     ` Richard Biener
@ 2015-05-22 14:29       ` Aldy Hernandez
  2015-05-27 13:18         ` Richard Biener
  0 siblings, 1 reply; 34+ messages in thread
From: Aldy Hernandez @ 2015-05-22 14:29 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jan Hubicka, Jason Merrill, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2197 bytes --]

On 05/22/2015 07:23 AM, Richard Biener wrote:
> On Wed, May 20, 2015 at 5:50 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
>> On 05/18/2015 06:56 AM, Richard Biener wrote:

>>> diff --git a/gcc/tree-core.h b/gcc/tree-core.h
>>> index ad1bb23..2a9f417 100644
>>> --- a/gcc/tree-core.h
>>> +++ b/gcc/tree-core.h
>>> @@ -1334,6 +1334,9 @@ struct GTY(()) tree_block {
>>>      tree abstract_origin;
>>>      tree fragment_origin;
>>>      tree fragment_chain;
>>> +
>>> +  /* Pointer to the DWARF lexical block.  */
>>> +  struct die_struct *die;
>>>    };
>>>
>>>    struct GTY(()) tree_type_common {
>>>
>>> Ick - do we need this?  dwarf2out.c has a hashtable to map blocks to
>>> DIEs (which you don't remove in turn).
>>
>>
>> We need a way to reference the early created DIE from late debugging, and we
>> can't use block_map because it gets cloberred across functions. It's
>> currently being released in late debug (dwarf2out_function_decl),
>> that's why you see it not set to NULL in dwarf2out_c_finalize.
>>
>> Also, it uses BLOCK_NUMBERs, which according to the documentation in
>> tree.h, are not guaranteed to be unique across functions.
>>
>> As Honza mentioned, we're already using a DIE map in types through
>> TYPE_SYMTAB_DIE.  See lookup_type_die() in dwarf2out.c.
>>
>> Could we leave this as is?
>
> But why then not eliminate block_map in favor of using the new ->die member?
> Having both looks very odd to me.

Oh, I would love to.  I just didn't want to rip things apart elsewhere 
until I was sure you guys were on board with the approach.

> Can you cook up a patch for trunk adding that field to tree_block and removing
> the block_map map in favor of sth like what we do for
> lookup_type_die/equate_type_number_to_die
> and TYPE_SYMTAB_DIE?

Absolutely!  The attached patch removes block_map in favor of BLOCK_DIE. 
  I did not add lookup_block_die/equate_block_number_to_die abstractions 
because I think BLOCK_DIE is pretty straightforward.

The attached patch is against mainline.  I also ported it to the branch 
for testing, and neither the branch nor mainline exhibit any regressions.

Tested on x86-64 Linux with --enable-languages=all,go,ada.

OK for trunk?

Aldy


[-- Attachment #2: curr --]
[-- Type: text/plain, Size: 3849 bytes --]

commit 9a82ff7b044a8d17eaaaec5eaec3e73f836224df
Author: Aldy Hernandez <aldyh@redhat.com>
Date:   Fri May 22 10:07:17 2015 -0400

    	* dwarf2out.c: Remove block_map.
    	(gen_call_site_die): Replace block_map use with BLOCK_DIE.
    	(gen_lexical_block_die): Same.
    	(dwarf2out_function_decl): Remove block_map use.
    	(dwarf2out_c_finalize): Same.
    	* tree-core.h (struct tree_block): Add die field.
    	* tree.h (BLOCK_DIE): New.

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index cc7ac84..15c545e 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2908,10 +2908,6 @@ static int call_site_count = -1;
 /* Number of tail call sites in the current function.  */
 static int tail_call_site_count = -1;
 
-/* Vector mapping block numbers to DW_TAG_{lexical_block,inlined_subroutine}
-   DIEs.  */
-static vec<dw_die_ref> block_map;
-
 /* A cached location list.  */
 struct GTY ((for_user)) cached_dw_loc_list_def {
   /* The DECL_UID of the decl that this entry describes.  */
@@ -18368,8 +18364,7 @@ gen_call_site_die (tree decl, dw_die_ref subr_die,
 	 && block != DECL_INITIAL (decl)
 	 && TREE_CODE (block) == BLOCK)
     {
-      if (block_map.length () > BLOCK_NUMBER (block))
-	stmt_die = block_map[BLOCK_NUMBER (block)];
+      stmt_die = BLOCK_DIE (block);
       if (stmt_die)
 	break;
       block = BLOCK_SUPERCONTEXT (block);
@@ -19469,11 +19464,7 @@ gen_lexical_block_die (tree stmt, dw_die_ref context_die)
   dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
 
   if (call_arg_locations)
-    {
-      if (block_map.length () <= BLOCK_NUMBER (stmt))
-	block_map.safe_grow_cleared (BLOCK_NUMBER (stmt) + 1);
-      block_map[BLOCK_NUMBER (stmt)] = stmt_die;
-    }
+    BLOCK_DIE (stmt) = stmt_die;
 
   if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
     add_high_low_attributes (stmt, stmt_die);
@@ -19506,11 +19497,7 @@ gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die)
 	= new_die (DW_TAG_inlined_subroutine, context_die, stmt);
 
       if (call_arg_locations)
-	{
-	  if (block_map.length () <= BLOCK_NUMBER (stmt))
-	    block_map.safe_grow_cleared (BLOCK_NUMBER (stmt) + 1);
-	  block_map[BLOCK_NUMBER (stmt)] = subr_die;
-	}
+	BLOCK_DIE (stmt) = subr_die;
       add_abstract_origin_attribute (subr_die, decl);
       if (TREE_ASM_WRITTEN (stmt))
         add_high_low_attributes (stmt, subr_die);
@@ -21407,7 +21394,6 @@ dwarf2out_function_decl (tree decl)
   call_arg_loc_last = NULL;
   call_site_count = -1;
   tail_call_site_count = -1;
-  block_map.release ();
   decl_loc_table->empty ();
   cached_dw_loc_list_table->empty ();
 }
@@ -25008,7 +24994,6 @@ dwarf2out_c_finalize (void)
   call_arg_loc_last = NULL;
   call_site_count = -1;
   tail_call_site_count = -1;
-  //block_map = NULL;
   cached_dw_loc_list_table = NULL;
   abbrev_die_table = NULL;
   abbrev_die_table_allocated = 0;
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index ad1bb23..2a9f417 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1334,6 +1334,9 @@ struct GTY(()) tree_block {
   tree abstract_origin;
   tree fragment_origin;
   tree fragment_chain;
+
+  /* Pointer to the DWARF lexical block.  */
+  struct die_struct *die;
 };
 
 struct GTY(()) tree_type_common {
diff --git a/gcc/tree.h b/gcc/tree.h
index 2bac698..ad32af0 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1589,6 +1589,7 @@ extern void protected_set_expr_location (tree, location_t);
 #define BLOCK_CHAIN(NODE) (BLOCK_CHECK (NODE)->block.chain)
 #define BLOCK_ABSTRACT_ORIGIN(NODE) (BLOCK_CHECK (NODE)->block.abstract_origin)
 #define BLOCK_ABSTRACT(NODE) (BLOCK_CHECK (NODE)->block.abstract_flag)
+#define BLOCK_DIE(NODE) (BLOCK_CHECK (NODE)->block.die)
 
 /* True if BLOCK has the same ranges as its BLOCK_SUPERCONTEXT.  */
 #define BLOCK_SAME_RANGE(NODE) (BLOCK_CHECK (NODE)->base.u.bits.nameless_flag)

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
       [not found]   ` <555CAD35.5040304@redhat.com>
  2015-05-20 21:03     ` Aldy Hernandez
  2015-05-22 11:26     ` Richard Biener
@ 2015-05-27 12:50     ` Jason Merrill
  2015-05-28 20:12       ` Aldy Hernandez
  2015-05-28 21:31       ` Aldy Hernandez
  2 siblings, 2 replies; 34+ messages in thread
From: Jason Merrill @ 2015-05-27 12:50 UTC (permalink / raw)
  To: Aldy Hernandez, Richard Biener, Jan Hubicka; +Cc: gcc-patches

On 05/20/2015 11:50 AM, Aldy Hernandez wrote:
> +     determine anscestry later.  */

ancestry

> +static bool early_dwarf_dumping;

Sorry for the late bikeshedding, but "dumping" suddently strikes me as 
odd, since there is no output as with other dumping in the compiler. 
Can we change that to "generation" or "building"?

> +	      /* Reuse DIE even with a differing context.
> +
> +		 This happens when called through
> +		 dwarf2out_abstract_function for formal parameter
> +		 packs.  */
> +	      gcc_assert (parm_die->die_parent->die_tag
> +			  == DW_TAG_GNU_formal_parameter_pack);

Does this mean we're generating a new DW_TAG_GNU_formal_parameter_pack 
in late debug even though we already generated one in early debug?  If 
so, why?

> -  /* It is possible to have both DECL_ABSTRACT_P and DECLARATION be true if we
> -     started to generate the abstract instance of an inline, decided to output
> -     its containing class, and proceeded to emit the declaration of the inline
> -     from the member list for the class.  If so, DECLARATION takes priority;
> -     we'll get back to the abstract instance when done with the class.  */
> -
> -  /* The class-scope declaration DIE must be the primary DIE.  */
> -  if (origin && declaration && class_or_namespace_scope_p (context_die))
> -    {
> -      origin = NULL;
> -      gcc_assert (!old_die);
> -    }

Can't this happen anymore?

> +      if ((is_cu_die (old_die->die_parent)
> +	   /* FIXME: Jason doesn't like this condition, but it fixes
> +	      the inconsistency/ICE with the following Fortran test:
> +
> +		 module some_m
> +		 contains
> +		    logical function funky (FLAG)
> +		      funky = .true.
> +		   end function
> +		 end module
> +
> +	      Another alternative is !is_cu_die (context_die).
> +	   */
> +	   || old_die->die_parent->die_tag == DW_TAG_module

I like it now.  :)
You can leave the rest of the comment.

> +  /* For non DECL_EXTERNALs, if range information is available, fill
> +     the DIE with it.  */
>    else if (!DECL_EXTERNAL (decl))
>      {
>        HOST_WIDE_INT cfa_fb_offset;
> +
>        struct function *fun = DECL_STRUCT_FUNCTION (decl);
>
> -      if (!old_die || !get_AT (old_die, DW_AT_inline))
> -	equate_decl_number_to_die (decl, subr_die);
> +      /* If we have no fun->fde, we have no range information.
> +	 Skip over and fill in range information in the second
> +	 dwarf pass.  */
> +      if (!fun->fde)
> +	goto no_fde_continue;

How about controlling this block with !early_dwarf so you don't need to 
deal with missing FDE?

>  	  if (generic_decl_parm
>  	      && lang_hooks.function_parameter_pack_p (generic_decl_parm))
> -	    gen_formal_parameter_pack_die (generic_decl_parm,
> -					   parm, subr_die,
> -					   &parm);
> +	    {
> +	      if (early_dwarf_dumping)
> +		gen_formal_parameter_pack_die (generic_decl_parm,
> +					       parm, subr_die,
> +					       &parm);
> +	      else if (parm)
> +		parm = DECL_CHAIN (parm);
> +	    }

Let's try only setting generic_decl when early_dwarf.

> +  /* Unless we have an existing non-declaration DIE, equate the new
> +     DIE.  */
> +  if (!old_die || is_declaration_die (old_die))
> +    equate_decl_number_to_die (decl, subr_die);
...
> +  if (decl && (DECL_ABSTRACT_P (decl) || declaration || old_die == NULL
> +	       /* If we make it to a specialization, we have already
> +		  handled the declaration by virtue of early dwarf.
> +		  If so, make a new assocation if available, so late
> +		  dwarf can find it.  */
> +	       || (specialization_p && early_dwarf_dumping)))
>      equate_decl_number_to_die (decl, var_die);

Why are the conditions so different?  Can we use the function condition 
for variables, too?

> +	  /* Do nothing.  This must have been early dumped and it
> +	     won't even need location information since it's a
> +	     DW_AT_inline function.  */
> +	  for (dw_die_ref c = context_die; c; c = c->die_parent)
> +	    if (c->die_tag == DW_TAG_inlined_subroutine
> +		|| c->die_tag == DW_TAG_subprogram)
> +	      {
> +		gcc_assert (get_AT (c, DW_AT_inline));
> +		break;
> +	      }

Maybe wrap this in #ifdef ENABLE_CHECKING.

> +	  /* Do the new DIE dance.  */
> +	  stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
> +	  BLOCK_DIE (stmt) = stmt_die;
> +	}
> +    }
> +  else if (BLOCK_ABSTRACT_ORIGIN (stmt))
> +    {
> +      /* If this is an inlined instance, create a new lexical die for
> +	 anything below to attach DW_AT_abstract_origin to.  */
> +      stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
> +    }
> +  else
> +    {
> +      if (!stmt_die)
> +	{
> +	  /* This is the first time we are creating something for this
> +	     block.  */
> +	  stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
> +	  BLOCK_DIE (stmt) = stmt_die;
> +	}

Surely we don't need to repeat the new_die call three times; the first 
and last are both controlled by !stmt_die.  And don't we want to set 
BLOCK_DIE for the inlined case as well, so that we can find the DIE 
again in late debug?

> +  /* Fill in the size of variable-length fields in late dwarf.  */
> +  if (TREE_ASM_WRITTEN (type)
> +      && !early_dwarf_dumping)
> +    {
> +      tree member;
> +      for (member = TYPE_FIELDS (type); member; member = DECL_CHAIN (member))
> +	fill_variable_array_bounds (TREE_TYPE (member));
> +      return;
> +    }

Why is this happening in late dwarf?  I'm concerned that front-end 
information that is necessary to do this might be lost by that point.

> +      /* Variable-length types may be incomplete even if
> +	 TREE_ASM_WRITTEN.  For such types, fall through to
> +	 gen_array_type_die() and possibly fill in
> +	 DW_AT_{upper,lower}_bound attributes.  */
> +      if ((TREE_CODE (type) != ARRAY_TYPE
> +	   && TREE_CODE (type) != RECORD_TYPE
> +	   && TREE_CODE (type) != UNION_TYPE
> +	   && TREE_CODE (type) != QUAL_UNION_TYPE)
> +	  || (TYPE_SIZE (type)
> +	      && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST))

Similarly, why check for INTEGER_CST here?

> +      bool t = early_dwarf_dumping;
> +      early_dwarf_dumping = true;
> +      dwarf2out_decl (decl);
> +      early_dwarf_dumping = t;

Let's use a RAII (resource acquisition is initialization) pattern for 
this and dwarf2out_imported_module_or_decl and dwarf2out_early_global_decl:

struct set_early_dwarf {
  bool saved;
  set_early_dwarf(): saved(early_dwarf) { early_dwarf = true; }
  ~set_early_dwarf() { early_dwarf = saved; }
};

set_early_dwarf s;
dwarf2out_decl (decl);

> +      /* When generating LTO bytecode we can not generate new assembler
> +         names at this point and all important decls got theirs via
> +	 free-lang-data.  */
> +      if (((!flag_generate_lto && !flag_generate_offload)
> +	   || DECL_ASSEMBLER_NAME_SET_P (decl))
> +	  && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)

Doesn't early_finish happen before free_lang_data, so we should be fine?

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-22 14:29       ` Aldy Hernandez
@ 2015-05-27 13:18         ` Richard Biener
  0 siblings, 0 replies; 34+ messages in thread
From: Richard Biener @ 2015-05-27 13:18 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Jan Hubicka, Jason Merrill, gcc-patches

On Fri, May 22, 2015 at 4:12 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
> On 05/22/2015 07:23 AM, Richard Biener wrote:
>>
>> On Wed, May 20, 2015 at 5:50 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
>>>
>>> On 05/18/2015 06:56 AM, Richard Biener wrote:
>
>
>>>> diff --git a/gcc/tree-core.h b/gcc/tree-core.h
>>>> index ad1bb23..2a9f417 100644
>>>> --- a/gcc/tree-core.h
>>>> +++ b/gcc/tree-core.h
>>>> @@ -1334,6 +1334,9 @@ struct GTY(()) tree_block {
>>>>      tree abstract_origin;
>>>>      tree fragment_origin;
>>>>      tree fragment_chain;
>>>> +
>>>> +  /* Pointer to the DWARF lexical block.  */
>>>> +  struct die_struct *die;
>>>>    };
>>>>
>>>>    struct GTY(()) tree_type_common {
>>>>
>>>> Ick - do we need this?  dwarf2out.c has a hashtable to map blocks to
>>>> DIEs (which you don't remove in turn).
>>>
>>>
>>>
>>> We need a way to reference the early created DIE from late debugging, and
>>> we
>>> can't use block_map because it gets cloberred across functions. It's
>>> currently being released in late debug (dwarf2out_function_decl),
>>> that's why you see it not set to NULL in dwarf2out_c_finalize.
>>>
>>> Also, it uses BLOCK_NUMBERs, which according to the documentation in
>>> tree.h, are not guaranteed to be unique across functions.
>>>
>>> As Honza mentioned, we're already using a DIE map in types through
>>> TYPE_SYMTAB_DIE.  See lookup_type_die() in dwarf2out.c.
>>>
>>> Could we leave this as is?
>>
>>
>> But why then not eliminate block_map in favor of using the new ->die
>> member?
>> Having both looks very odd to me.
>
>
> Oh, I would love to.  I just didn't want to rip things apart elsewhere until
> I was sure you guys were on board with the approach.
>
>> Can you cook up a patch for trunk adding that field to tree_block and
>> removing
>> the block_map map in favor of sth like what we do for
>> lookup_type_die/equate_type_number_to_die
>> and TYPE_SYMTAB_DIE?
>
>
> Absolutely!  The attached patch removes block_map in favor of BLOCK_DIE.  I
> did not add lookup_block_die/equate_block_number_to_die abstractions because
> I think BLOCK_DIE is pretty straightforward.
>
> The attached patch is against mainline.  I also ported it to the branch for
> testing, and neither the branch nor mainline exhibit any regressions.
>
> Tested on x86-64 Linux with --enable-languages=all,go,ada.
>
> OK for trunk?

Ok.

Thanks,
Richard.

> Aldy
>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-27 12:50     ` Jason Merrill
@ 2015-05-28 20:12       ` Aldy Hernandez
  2015-05-28 20:54         ` Jason Merrill
  2015-05-28 21:31       ` Aldy Hernandez
  1 sibling, 1 reply; 34+ messages in thread
From: Aldy Hernandez @ 2015-05-28 20:12 UTC (permalink / raw)
  To: Jason Merrill, Richard Biener, Jan Hubicka; +Cc: gcc-patches

On 05/27/2015 08:39 AM, Jason Merrill wrote:
> On 05/20/2015 11:50 AM, Aldy Hernandez wrote:

>> +  /* Fill in the size of variable-length fields in late dwarf.  */
>> +  if (TREE_ASM_WRITTEN (type)
>> +      && !early_dwarf_dumping)
>> +    {
>> +      tree member;
>> +      for (member = TYPE_FIELDS (type); member; member = DECL_CHAIN
>> (member))
>> +    fill_variable_array_bounds (TREE_TYPE (member));
>> +      return;
>> +    }
>
> Why is this happening in late dwarf?  I'm concerned that front-end
> information that is necessary to do this might be lost by that point.

I thought only after the optimizations had run their course would we be 
guaranteed to have accurate bound information.  At least, that's what my 
experience showed.

Do you have something else in mind?

>
>> +      /* Variable-length types may be incomplete even if
>> +     TREE_ASM_WRITTEN.  For such types, fall through to
>> +     gen_array_type_die() and possibly fill in
>> +     DW_AT_{upper,lower}_bound attributes.  */
>> +      if ((TREE_CODE (type) != ARRAY_TYPE
>> +       && TREE_CODE (type) != RECORD_TYPE
>> +       && TREE_CODE (type) != UNION_TYPE
>> +       && TREE_CODE (type) != QUAL_UNION_TYPE)
>> +      || (TYPE_SIZE (type)
>> +          && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST))
>
> Similarly, why check for INTEGER_CST here?

The INTEGER_CST check was supposed to mean "we have bound information 
already, no need to look further".

I guess we could have a variable length bound that does not decay to a 
constant.  Perhaps I could check the presence of a cached DIE with a 
type DIE containing a DW_TAG_subrange_type *and* 
DW_AT_{lower,upper}_bound ??.  Basically I just want to add bound 
information, if available and not already present.

Suggestions?

Aldy

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-28 20:12       ` Aldy Hernandez
@ 2015-05-28 20:54         ` Jason Merrill
  2015-05-28 21:01           ` Jan Hubicka
                             ` (2 more replies)
  0 siblings, 3 replies; 34+ messages in thread
From: Jason Merrill @ 2015-05-28 20:54 UTC (permalink / raw)
  To: Aldy Hernandez, Richard Biener, Jan Hubicka; +Cc: gcc-patches

On 05/28/2015 02:53 PM, Aldy Hernandez wrote:
> On 05/27/2015 08:39 AM, Jason Merrill wrote:
>> On 05/20/2015 11:50 AM, Aldy Hernandez wrote:
>
>>> +  /* Fill in the size of variable-length fields in late dwarf.  */
>>> +  if (TREE_ASM_WRITTEN (type)
>>> +      && !early_dwarf_dumping)
>>> +    {
>>> +      tree member;
>>> +      for (member = TYPE_FIELDS (type); member; member = DECL_CHAIN
>>> (member))
>>> +    fill_variable_array_bounds (TREE_TYPE (member));
>>> +      return;
>>> +    }
>>
>> Why is this happening in late dwarf?  I'm concerned that front-end
>> information that is necessary to do this might be lost by that point.
>
> I thought only after the optimizations had run their course would we be
> guaranteed to have accurate bound information.  At least, that's what my
> experience showed.

Hmm, I'm don't know why optimizations would change the representation of 
the array type.

>>> +      /* Variable-length types may be incomplete even if
>>> +     TREE_ASM_WRITTEN.  For such types, fall through to
>>> +     gen_array_type_die() and possibly fill in
>>> +     DW_AT_{upper,lower}_bound attributes.  */
>>> +      if ((TREE_CODE (type) != ARRAY_TYPE
>>> +       && TREE_CODE (type) != RECORD_TYPE
>>> +       && TREE_CODE (type) != UNION_TYPE
>>> +       && TREE_CODE (type) != QUAL_UNION_TYPE)
>>> +      || (TYPE_SIZE (type)
>>> +          && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST))
>>
>> Similarly, why check for INTEGER_CST here?
>
> The INTEGER_CST check was supposed to mean "we have bound information
> already, no need to look further".
>
> I guess we could have a variable length bound that does not decay to a
> constant.

Right.  I would expect that to usually be the case with VLAs.

> Perhaps I could check the presence of a cached DIE with a
> type DIE containing a DW_TAG_subrange_type *and*
> DW_AT_{lower,upper}_bound ??.  Basically I just want to add bound
> information, if available and not already present.
>
> Suggestions?

I'm still not sure why we can't just emit bound info in early dwarf. 
Can you be more specific about the optimization thing?

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-28 20:54         ` Jason Merrill
@ 2015-05-28 21:01           ` Jan Hubicka
  2015-05-28 21:10             ` Jason Merrill
  2015-05-29 12:07           ` Richard Biener
  2015-05-29 19:33           ` Aldy Hernandez
  2 siblings, 1 reply; 34+ messages in thread
From: Jan Hubicka @ 2015-05-28 21:01 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Aldy Hernandez, Richard Biener, Jan Hubicka, gcc-patches

> On 05/28/2015 02:53 PM, Aldy Hernandez wrote:
> >On 05/27/2015 08:39 AM, Jason Merrill wrote:
> >>On 05/20/2015 11:50 AM, Aldy Hernandez wrote:
> >
> >>>+  /* Fill in the size of variable-length fields in late dwarf.  */
> >>>+  if (TREE_ASM_WRITTEN (type)
> >>>+      && !early_dwarf_dumping)
> >>>+    {
> >>>+      tree member;
> >>>+      for (member = TYPE_FIELDS (type); member; member = DECL_CHAIN
> >>>(member))
> >>>+    fill_variable_array_bounds (TREE_TYPE (member));
> >>>+      return;
> >>>+    }
> >>
> >>Why is this happening in late dwarf?  I'm concerned that front-end
> >>information that is necessary to do this might be lost by that point.
> >
> >I thought only after the optimizations had run their course would we be
> >guaranteed to have accurate bound information.  At least, that's what my
> >experience showed.
> 
> Hmm, I'm don't know why optimizations would change the
> representation of the array type.

I don't think we change representation ATM, but eventually we want to get into
the datastructure reordering busyness.  I suppose to get this debug output
friendly, we will need a way to update the existing dwarf DIE to whatever
changes we want.

As for optimization changing type representation, I suppose one case is when
function with varray type gets inlined and the array bound happens to be a
different expression afterwards.  We produce a new copy of the original type
with different bounds then.

Honza

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-28 21:01           ` Jan Hubicka
@ 2015-05-28 21:10             ` Jason Merrill
  2015-05-28 21:16               ` Jan Hubicka
  0 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2015-05-28 21:10 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Aldy Hernandez, Richard Biener, gcc-patches

On 05/28/2015 04:42 PM, Jan Hubicka wrote:
> As for optimization changing type representation, I suppose one case is when
> function with varray type gets inlined and the array bound happens to be a
> different expression afterwards.  We produce a new copy of the original type
> with different bounds then.

That makes sense, but that would be a new type rather than modifications 
to the old type.

Jason


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-28 21:10             ` Jason Merrill
@ 2015-05-28 21:16               ` Jan Hubicka
  0 siblings, 0 replies; 34+ messages in thread
From: Jan Hubicka @ 2015-05-28 21:16 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jan Hubicka, Aldy Hernandez, Richard Biener, gcc-patches

> On 05/28/2015 04:42 PM, Jan Hubicka wrote:
> >As for optimization changing type representation, I suppose one case is when
> >function with varray type gets inlined and the array bound happens to be a
> >different expression afterwards.  We produce a new copy of the original type
> >with different bounds then.
> 
> That makes sense, but that would be a new type rather than
> modifications to the old type.

Yep, that is all I can think of :)
Somehow the early dwarf needs to bind to the sizes that are represented as gimple
registers.  How this case is handled with early debug?

Honza
> 
> Jason
> 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-27 12:50     ` Jason Merrill
  2015-05-28 20:12       ` Aldy Hernandez
@ 2015-05-28 21:31       ` Aldy Hernandez
  2015-05-29  6:33         ` Jason Merrill
  1 sibling, 1 reply; 34+ messages in thread
From: Aldy Hernandez @ 2015-05-28 21:31 UTC (permalink / raw)
  To: Jason Merrill, Richard Biener, Jan Hubicka; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 8503 bytes --]

On 05/27/2015 08:39 AM, Jason Merrill wrote:
> On 05/20/2015 11:50 AM, Aldy Hernandez wrote:
>> +     determine anscestry later.  */
>
> ancestry

Fixed.

>
>> +static bool early_dwarf_dumping;
>
> Sorry for the late bikeshedding, but "dumping" suddently strikes me as
> odd, since there is no output as with other dumping in the compiler. Can
> we change that to "generation" or "building"?

Fixed.

>
>> +          /* Reuse DIE even with a differing context.
>> +
>> +         This happens when called through
>> +         dwarf2out_abstract_function for formal parameter
>> +         packs.  */
>> +          gcc_assert (parm_die->die_parent->die_tag
>> +              == DW_TAG_GNU_formal_parameter_pack);
>
> Does this mean we're generating a new DW_TAG_GNU_formal_parameter_pack
> in late debug even though we already generated one in early debug?  If
> so, why?

I will be addressing this separately, as we're likely to iterate many 
times on this :).

>
>> -  /* It is possible to have both DECL_ABSTRACT_P and DECLARATION be
>> true if we
>> -     started to generate the abstract instance of an inline, decided
>> to output
>> -     its containing class, and proceeded to emit the declaration of
>> the inline
>> -     from the member list for the class.  If so, DECLARATION takes
>> priority;
>> -     we'll get back to the abstract instance when done with the
>> class.  */
>> -
>> -  /* The class-scope declaration DIE must be the primary DIE.  */
>> -  if (origin && declaration && class_or_namespace_scope_p (context_die))
>> -    {
>> -      origin = NULL;
>> -      gcc_assert (!old_die);
>> -    }
>
> Can't this happen anymore?

As discussed on IRC, this is dead code in the presence of debug-early, 
and no longer applicable with the upcoming DECL_ABSTRACT* redesign.

>
>> +      if ((is_cu_die (old_die->die_parent)
>> +       /* FIXME: Jason doesn't like this condition, but it fixes
>> +          the inconsistency/ICE with the following Fortran test:
>> +
>> +         module some_m
>> +         contains
>> +            logical function funky (FLAG)
>> +              funky = .true.
>> +           end function
>> +         end module
>> +
>> +          Another alternative is !is_cu_die (context_die).
>> +       */
>> +       || old_die->die_parent->die_tag == DW_TAG_module
>
> I like it now.  :)
> You can leave the rest of the comment.

Updated comment.

>
>> +  /* For non DECL_EXTERNALs, if range information is available, fill
>> +     the DIE with it.  */
>>    else if (!DECL_EXTERNAL (decl))
>>      {
>>        HOST_WIDE_INT cfa_fb_offset;
>> +
>>        struct function *fun = DECL_STRUCT_FUNCTION (decl);
>>
>> -      if (!old_die || !get_AT (old_die, DW_AT_inline))
>> -    equate_decl_number_to_die (decl, subr_die);
>> +      /* If we have no fun->fde, we have no range information.
>> +     Skip over and fill in range information in the second
>> +     dwarf pass.  */
>> +      if (!fun->fde)
>> +    goto no_fde_continue;
>
> How about controlling this block with !early_dwarf so you don't need to
> deal with missing FDE?

Fixed.

>
>>        if (generic_decl_parm
>>            && lang_hooks.function_parameter_pack_p (generic_decl_parm))
>> -        gen_formal_parameter_pack_die (generic_decl_parm,
>> -                       parm, subr_die,
>> -                       &parm);
>> +        {
>> +          if (early_dwarf_dumping)
>> +        gen_formal_parameter_pack_die (generic_decl_parm,
>> +                           parm, subr_die,
>> +                           &parm);
>> +          else if (parm)
>> +        parm = DECL_CHAIN (parm);
>> +        }
>
> Let's try only setting generic_decl when early_dwarf.

Fixed.

>
>> +  /* Unless we have an existing non-declaration DIE, equate the new
>> +     DIE.  */
>> +  if (!old_die || is_declaration_die (old_die))
>> +    equate_decl_number_to_die (decl, subr_die);
> ...
>> +  if (decl && (DECL_ABSTRACT_P (decl) || declaration || old_die == NULL
>> +           /* If we make it to a specialization, we have already
>> +          handled the declaration by virtue of early dwarf.
>> +          If so, make a new assocation if available, so late
>> +          dwarf can find it.  */
>> +           || (specialization_p && early_dwarf_dumping)))
>>      equate_decl_number_to_die (decl, var_die);
>
> Why are the conditions so different?  Can we use the function condition
> for variables, too?

Hmmm...because they were already that way when I arrived? :).

How about what I do in the attached patch, which also seems to do the 
trick?:

   if (decl && (DECL_ABSTRACT_P (decl)
	       || !old_die || is_declaration_die (old_die)))

>> +      /* Do nothing.  This must have been early dumped and it
>> +         won't even need location information since it's a
>> +         DW_AT_inline function.  */
>> +      for (dw_die_ref c = context_die; c; c = c->die_parent)
>> +        if (c->die_tag == DW_TAG_inlined_subroutine
>> +        || c->die_tag == DW_TAG_subprogram)
>> +          {
>> +        gcc_assert (get_AT (c, DW_AT_inline));
>> +        break;
>> +          }
>
> Maybe wrap this in #ifdef ENABLE_CHECKING.

Done.

>
>> +      /* Do the new DIE dance.  */
>> +      stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
>> +      BLOCK_DIE (stmt) = stmt_die;
>> +    }
>> +    }
>> +  else if (BLOCK_ABSTRACT_ORIGIN (stmt))
>> +    {
>> +      /* If this is an inlined instance, create a new lexical die for
>> +     anything below to attach DW_AT_abstract_origin to.  */
>> +      stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
>> +    }
>> +  else
>> +    {
>> +      if (!stmt_die)
>> +    {
>> +      /* This is the first time we are creating something for this
>> +         block.  */
>> +      stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
>> +      BLOCK_DIE (stmt) = stmt_die;
>> +    }
>
> Surely we don't need to repeat the new_die call three times; the first
> and last are both controlled by !stmt_die.  And don't we want to set
> BLOCK_DIE for the inlined case as well, so that we can find the DIE
> again in late debug?

Done.

>
>> +  /* Fill in the size of variable-length fields in late dwarf.  */
>> +  if (TREE_ASM_WRITTEN (type)
>> +      && !early_dwarf_dumping)
>> +    {
>> +      tree member;
>> +      for (member = TYPE_FIELDS (type); member; member = DECL_CHAIN
>> (member))
>> +    fill_variable_array_bounds (TREE_TYPE (member));
>> +      return;
>> +    }
>
> Why is this happening in late dwarf?  I'm concerned that front-end
> information that is necessary to do this might be lost by that point.
>
>> +      /* Variable-length types may be incomplete even if
>> +     TREE_ASM_WRITTEN.  For such types, fall through to
>> +     gen_array_type_die() and possibly fill in
>> +     DW_AT_{upper,lower}_bound attributes.  */
>> +      if ((TREE_CODE (type) != ARRAY_TYPE
>> +       && TREE_CODE (type) != RECORD_TYPE
>> +       && TREE_CODE (type) != UNION_TYPE
>> +       && TREE_CODE (type) != QUAL_UNION_TYPE)
>> +      || (TYPE_SIZE (type)
>> +          && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST))
>
> Similarly, why check for INTEGER_CST here?

Will work on this now.

>> +      bool t = early_dwarf_dumping;
>> +      early_dwarf_dumping = true;
>> +      dwarf2out_decl (decl);
>> +      early_dwarf_dumping = t;
>
> Let's use a RAII (resource acquisition is initialization) pattern for
> this and dwarf2out_imported_module_or_decl and dwarf2out_early_global_decl:
>
> struct set_early_dwarf {
>   bool saved;
>   set_early_dwarf(): saved(early_dwarf) { early_dwarf = true; }
>   ~set_early_dwarf() { early_dwarf = saved; }
> };

Done.

>> +      /* When generating LTO bytecode we can not generate new assembler
>> +         names at this point and all important decls got theirs via
>> +     free-lang-data.  */
>> +      if (((!flag_generate_lto && !flag_generate_offload)
>> +       || DECL_ASSEMBLER_NAME_SET_P (decl))
>> +      && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)
>
> Doesn't early_finish happen before free_lang_data, so we should be fine?

Done.

Could you please verify that all the changes so far are what you had in 
mind, before I move onto the variable-length arrays and the 
DECL_ABSTRACT rework?  I am only including the diff for dwarf2out, which 
is what are reviewing.  I can include the rest in subsequent iterations 
if you prefer.

The attached patch has been retested for --enable-languages=all,go,ada, 
and with the GDB testsuite.

Please let me know.  Thanks.

Aldy

[-- Attachment #2: dearly-dwarf2out.patch --]
[-- Type: text/x-patch, Size: 63866 bytes --]

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 15c545e..2c120a3 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -1268,16 +1268,6 @@ struct GTY((for_user)) dwarf_file_data {
   int emitted_number;
 };
 
-typedef struct GTY(()) deferred_locations_struct
-{
-  tree variable;
-  dw_die_ref die;
-} deferred_locations;
-
-
-static GTY(()) vec<deferred_locations, va_gc> *deferred_locations_list;
-
-
 /* Describe an entry into the .debug_addr section.  */
 
 enum ate_kind {
@@ -2448,6 +2438,7 @@ build_cfa_aligned_loc (dw_cfa_location *cfa,
 
 static void dwarf2out_init (const char *);
 static void dwarf2out_finish (const char *);
+static void dwarf2out_early_finish (void);
 static void dwarf2out_assembly_start (void);
 static void dwarf2out_define (unsigned int, const char *);
 static void dwarf2out_undef (unsigned int, const char *);
@@ -2457,7 +2448,8 @@ static void dwarf2out_function_decl (tree);
 static void dwarf2out_begin_block (unsigned, unsigned);
 static void dwarf2out_end_block (unsigned, unsigned);
 static bool dwarf2out_ignore_block (const_tree);
-static void dwarf2out_global_decl (tree);
+static void dwarf2out_early_global_decl (tree);
+static void dwarf2out_late_global_decl (tree);
 static void dwarf2out_type_decl (tree, int);
 static void dwarf2out_imported_module_or_decl (tree, tree, tree, bool);
 static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree,
@@ -2474,6 +2466,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
 {
   dwarf2out_init,
   dwarf2out_finish,
+  dwarf2out_early_finish,
   dwarf2out_assembly_start,
   dwarf2out_define,
   dwarf2out_undef,
@@ -2495,7 +2488,8 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   dwarf2out_begin_function,
   dwarf2out_end_function,	/* end_function */
   dwarf2out_function_decl,	/* function_decl */
-  dwarf2out_global_decl,
+  dwarf2out_early_global_decl,
+  dwarf2out_late_global_decl,
   dwarf2out_type_decl,		/* type_decl */
   dwarf2out_imported_module_or_decl,
   debug_nothing_tree,		/* deferred_inline_function */
@@ -2636,10 +2630,20 @@ typedef struct GTY((chain_circular ("%h.die_sib"), for_user)) die_struct {
   /* Die is used and must not be pruned as unused.  */
   BOOL_BITFIELD die_perennial_p : 1;
   BOOL_BITFIELD comdat_type_p : 1; /* DIE has a type signature */
+  /* Die was generated early via dwarf2out_early_global_decl.  */
+  BOOL_BITFIELD dumped_early : 1;
   /* Lots of spare bits.  */
 }
 die_node;
 
+/* Set to TRUE while dwarf2out_early_global_decl is running.  */
+static bool early_dwarf;
+struct set_early_dwarf {
+  bool saved;
+  set_early_dwarf () : saved(early_dwarf) { early_dwarf = true; }
+  ~set_early_dwarf () { early_dwarf = saved; }
+};
+
 /* Evaluate 'expr' while 'c' is set to each child of DIE in order.  */
 #define FOR_EACH_CHILD(die, c, expr) do {	\
   c = die->die_child;				\
@@ -2690,9 +2694,13 @@ typedef struct GTY(()) comdat_type_struct
 }
 comdat_type_node;
 
-/* The limbo die list structure.  */
+/* A list of DIEs for which we can't determine ancestry (parent_die
+   field) just yet.  Later in dwarf2out_finish we will fill in the
+   missing bits.  */
 typedef struct GTY(()) limbo_die_struct {
   dw_die_ref die;
+  /* The tree for which this DIE was created for.  We use this to
+     determine ancestry later.  */
   tree created_for;
   struct limbo_die_struct *next;
 }
@@ -2939,7 +2947,7 @@ static GTY((length ("abbrev_die_table_allocated")))
 /* Number of elements currently allocated for abbrev_die_table.  */
 static GTY(()) unsigned abbrev_die_table_allocated;
 
-/* Number of elements in type_die_table currently in use.  */
+/* Number of elements in abbrev_die_table currently in use.  */
 static GTY(()) unsigned abbrev_die_table_in_use;
 
 /* Size (in elements) of increments by which we may expand the
@@ -3021,9 +3029,6 @@ static GTY(()) struct dwarf_file_data * last_emitted_file;
 /* Number of internal labels generated by gen_internal_sym().  */
 static GTY(()) int label_num;
 
-/* Cached result of previous call to lookup_filename.  */
-static GTY(()) struct dwarf_file_data * file_table_last_lookup;
-
 static GTY(()) vec<die_arg_entry, va_gc> *tmpl_value_parm_die_table;
 
 /* Instances of generic types for which we need to generate debug
@@ -3108,7 +3113,7 @@ static inline dw_die_ref get_AT_ref (dw_die_ref, enum dwarf_attribute);
 static bool is_cxx (void);
 static bool is_fortran (void);
 static bool is_ada (void);
-static void remove_AT (dw_die_ref, enum dwarf_attribute);
+static bool remove_AT (dw_die_ref, enum dwarf_attribute);
 static void remove_child_TAG (dw_die_ref, enum dwarf_tag);
 static void add_child_die (dw_die_ref, dw_die_ref);
 static dw_die_ref new_die (enum dwarf_tag, dw_die_ref, tree);
@@ -4748,16 +4753,17 @@ is_ada (void)
   return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83;
 }
 
-/* Remove the specified attribute if present.  */
+/* Remove the specified attribute if present.  Return TRUE if removal
+   was successful.  */
 
-static void
+static bool
 remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
 {
   dw_attr_ref a;
   unsigned ix;
 
   if (! die)
-    return;
+    return false;
 
   FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
     if (a->dw_attr == attr_kind)
@@ -4769,8 +4775,9 @@ remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
 	/* vec::ordered_remove should help reduce the number of abbrevs
 	   that are needed.  */
 	die->die_attr->ordered_remove (ix);
-	return;
+	return true;
       }
+  return false;
 }
 
 /* Remove CHILD from its parent.  PREV must have the property that
@@ -4844,6 +4851,7 @@ remove_child_TAG (dw_die_ref die, enum dwarf_tag tag)
     while (c->die_tag == tag)
       {
 	remove_child_with_prev (c, prev);
+	c->die_parent = NULL;
 	/* Might have removed every child.  */
 	if (c == c->die_sib)
 	  return;
@@ -4873,6 +4881,21 @@ add_child_die (dw_die_ref die, dw_die_ref child_die)
   die->die_child = child_die;
 }
 
+/* Unassociate CHILD from its parent, and make its parent be
+   NEW_PARENT.  */
+
+static void
+reparent_child (dw_die_ref child, dw_die_ref new_parent)
+{
+  for (dw_die_ref p = child->die_parent->die_child; ; p = p->die_sib)
+    if (p->die_sib == child)
+      {
+	remove_child_with_prev (child, p);
+	break;
+      }
+  add_child_die (new_parent, child);
+}
+
 /* Move CHILD, which must be a child of PARENT or the DIE for which PARENT
    is the specification, to the end of PARENT's list of children.
    This is done by removing and re-adding it.  */
@@ -4880,8 +4903,6 @@ add_child_die (dw_die_ref die, dw_die_ref child_die)
 static void
 splice_child_die (dw_die_ref parent, dw_die_ref child)
 {
-  dw_die_ref p;
-
   /* We want the declaration DIE from inside the class, not the
      specification DIE at toplevel.  */
   if (child->die_parent != parent)
@@ -4896,17 +4917,13 @@ splice_child_die (dw_die_ref parent, dw_die_ref child)
 	      || (child->die_parent
 		  == get_AT_ref (parent, DW_AT_specification)));
 
-  for (p = child->die_parent->die_child; ; p = p->die_sib)
-    if (p->die_sib == child)
-      {
-	remove_child_with_prev (child, p);
-	break;
-      }
-
-  add_child_die (parent, child);
+  reparent_child (child, parent);
 }
 
-/* Return a pointer to a newly created DIE node.  */
+/* Create and return a new die with a parent of PARENT_DIE.  If
+   PARENT_DIE is NULL, the new DIE is placed in limbo and an
+   associated tree T must be supplied to determine parenthood
+   later.  */
 
 static inline dw_die_ref
 new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
@@ -4915,12 +4932,44 @@ new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
 
   die->die_tag = tag_value;
 
+  if (early_dwarf)
+    die->dumped_early = true;
+
   if (parent_die != NULL)
     add_child_die (parent_die, die);
   else
     {
       limbo_die_node *limbo_node;
 
+      /* No DIEs created after early dwarf should end up in limbo,
+	 because the limbo list should not persist past LTO
+	 streaming.  */
+      if (tag_value != DW_TAG_compile_unit
+	  /* These are allowed because they're generated while
+	     breaking out COMDAT units late.  */
+	  && tag_value != DW_TAG_type_unit
+	  && !early_dwarf
+	  /* Allow nested functions to live in limbo because they will
+	     only temporarily live there, as decls_for_scope will fix
+	     them up.  */
+	  && (TREE_CODE (t) != FUNCTION_DECL
+	      || !decl_function_context (t))
+	  /* Same as nested functions above but for types.  Types that
+	     are local to a function will be fixed in
+	     decls_for_scope.  */
+	  && (!RECORD_OR_UNION_TYPE_P (t)
+	      || !TYPE_CONTEXT (t)
+	      || TREE_CODE (TYPE_CONTEXT (t)) != FUNCTION_DECL)
+	  /* FIXME debug-early: Allow late limbo DIE creation for LTO,
+	     especially in the ltrans stage, but once we implement LTO
+	     dwarf streaming, we should remove this exception.  */
+	  && !in_lto_p)
+	{
+	  fprintf (stderr, "symbol ended up in limbo too late:");
+	  debug_generic_stmt (t);
+	  gcc_unreachable ();
+	}
+
       limbo_node = ggc_cleared_alloc<limbo_die_node> ();
       limbo_node->die = die;
       limbo_node->created_for = t;
@@ -5576,9 +5625,18 @@ print_die (dw_die_ref die, FILE *outfile)
   unsigned ix;
 
   print_spaces (outfile);
-  fprintf (outfile, "DIE %4ld: %s (%p)\n",
+  fprintf (outfile, "DIE %4ld: %s (%p)",
 	   die->die_offset, dwarf_tag_name (die->die_tag),
 	   (void*) die);
+  if (die->dumped_early)
+    {
+      fprintf (outfile, " (DUMPED EARLY");
+      const char *name = get_AT_string (die, DW_AT_name);
+      if (name)
+	fprintf (outfile, ": %s", name);
+      fputc (')', outfile);
+    }
+  fputc ('\n', outfile);
   print_spaces (outfile);
   fprintf (outfile, "  abbrev id: %lu", die->die_abbrev);
   fprintf (outfile, " offset: %ld", die->die_offset);
@@ -5652,6 +5710,34 @@ debug_dwarf (void)
   print_indent = 0;
   print_die (comp_unit_die (), stderr);
 }
+
+/* Sanity checks on DIEs.  */
+
+static void
+check_die (dw_die_ref die)
+{
+  /* A debugging information entry that is a member of an abstract
+     instance tree [that has DW_AT_inline] should not contain any
+     attributes which describe aspects of the subroutine which vary
+     between distinct inlined expansions or distinct out-of-line
+     expansions.  */
+  unsigned ix;
+  dw_attr_ref a;
+  bool inline_found = false;
+  FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+    if (a->dw_attr == DW_AT_inline && a->dw_attr_val.v.val_unsigned)
+      inline_found = true;
+  if (inline_found)
+    {
+      /* Catch the most common mistakes.  */
+      FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+	gcc_assert (a->dw_attr != DW_AT_low_pc
+		    && a->dw_attr != DW_AT_high_pc
+		    && a->dw_attr != DW_AT_location
+		    && a->dw_attr != DW_AT_frame_base
+		    && a->dw_attr != DW_AT_GNU_all_call_sites);
+    }
+}
 \f
 /* Start a new compilation unit DIE for an include file.  OLD_UNIT is the CU
    for the enclosing include file, if any.  BINCL_DIE is the DW_TAG_GNU_BINCL
@@ -8799,9 +8885,10 @@ output_die (dw_die_ref die)
   if (! die->comdat_type_p && die->die_id.die_symbol)
     output_die_symbol (die);
 
-  dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)",
+  dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)%s",
 			       (unsigned long)die->die_offset,
-			       dwarf_tag_name (die->die_tag));
+			       dwarf_tag_name (die->die_tag),
+			       die->dumped_early ? " (early)" : "");
 
   FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
     {
@@ -16106,17 +16193,6 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, bool cache_p,
   return tree_add_const_value_attribute_for_decl (die, decl);
 }
 
-/* Add VARIABLE and DIE into deferred locations list.  */
-
-static void
-defer_location (tree variable, dw_die_ref die)
-{
-  deferred_locations entry;
-  entry.variable = variable;
-  entry.die = die;
-  vec_safe_push (deferred_locations_list, entry);
-}
-
 /* Helper function for tree_add_const_value_attribute.  Natively encode
    initializer INIT into an array.  Return true if successful.  */
 
@@ -16798,14 +16874,17 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr,
 /* Add subscript info to TYPE_DIE, describing an array TYPE, collapsing
    possibly nested array subscripts in a flat sequence if COLLAPSE_P is true.
    Note that the block of subscript information for an array type also
-   includes information about the element type of the given array type.  */
+   includes information about the element type of the given array type.
+
+   This function reuses previously set type and bound information if
+   available.  */
 
 static void
 add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
 {
   unsigned dimension_number;
   tree lower, upper;
-  dw_die_ref subrange_die;
+  dw_die_ref child = type_die->die_child;
 
   for (dimension_number = 0;
        TREE_CODE (type) == ARRAY_TYPE && (dimension_number == 0 || collapse_p);
@@ -16819,7 +16898,37 @@ add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
       /* Arrays come in three flavors: Unspecified bounds, fixed bounds,
 	 and (in GNU C only) variable bounds.  Handle all three forms
 	 here.  */
-      subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
+
+      /* Find and reuse a previously generated DW_TAG_subrange_type if
+	 available.
+
+         For multi-dimensional arrays, as we iterate through the
+         various dimensions in the enclosing for loop above, we also
+         iterate through the DIE children and pick at each
+         DW_TAG_subrange_type previously generated (if available).
+         Each child DW_TAG_subrange_type DIE describes the range of
+         the current dimension.  At this point we should have as many
+         DW_TAG_subrange_type's as we have dimensions in the
+         array.  */
+      dw_die_ref subrange_die = NULL;
+      if (child)
+	while (1)
+	  {
+	    child = child->die_sib;
+	    if (child->die_tag == DW_TAG_subrange_type)
+	      subrange_die = child;
+	    if (child == type_die->die_child)
+	      {
+		/* If we wrapped around, stop looking next time.  */
+		child = NULL;
+		break;
+	      }
+	    if (child->die_tag == DW_TAG_subrange_type)
+	      break;
+	  }
+      if (!subrange_die)
+	subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
+
       if (domain)
 	{
 	  /* We have an array type with specified bounds.  */
@@ -16827,7 +16936,8 @@ add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
 	  upper = TYPE_MAX_VALUE (domain);
 
 	  /* Define the index type.  */
-	  if (TREE_TYPE (domain))
+	  if (TREE_TYPE (domain)
+	      && !get_AT (subrange_die, DW_AT_type))
 	    {
 	      /* ??? This is probably an Ada unnamed subrange type.  Ignore the
 		 TREE_TYPE field.  We can't emit debug info for this
@@ -16849,8 +16959,9 @@ add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
 	     to produce useful results, go ahead and output the lower
 	     bound solo, and hope the debugger can cope.  */
 
-	  add_bound_info (subrange_die, DW_AT_lower_bound, lower, NULL);
-	  if (upper)
+	  if (!get_AT (subrange_die, DW_AT_lower_bound))
+	    add_bound_info (subrange_die, DW_AT_lower_bound, lower, NULL);
+	  if (upper && !get_AT (subrange_die, DW_AT_upper_bound))
 	    add_bound_info (subrange_die, DW_AT_upper_bound, upper, NULL);
 	}
 
@@ -17477,6 +17588,26 @@ decl_start_label (tree decl)
 }
 #endif
 \f
+/* For variable-length arrays that have been previously generated, but
+   may be incomplete due to missing subscript info, fill the subscript
+   info.  Return TRUE if this is one of those cases.  */
+static bool
+fill_variable_array_bounds (tree type)
+{
+  if (TREE_ASM_WRITTEN (type)
+      && TREE_CODE (type) == ARRAY_TYPE
+      && TYPE_SIZE (type)
+      && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+    {
+      dw_die_ref array_die = lookup_type_die (type);
+      if (!array_die)
+	return false;
+      add_subscript_info (array_die, type, !is_ada ());
+      return true;
+    }
+  return false;
+}
+
 /* These routines generate the internal representation of the DIE's for
    the compilation unit.  Debugging information is collected by walking
    the declaration trees passed in from dwarf2out_decl().  */
@@ -17484,7 +17615,6 @@ decl_start_label (tree decl)
 static void
 gen_array_type_die (tree type, dw_die_ref context_die)
 {
-  dw_die_ref scope_die = scope_die_for (type, context_die);
   dw_die_ref array_die;
 
   /* GNU compilers represent multidimensional array types as sequences of one
@@ -17498,6 +17628,11 @@ gen_array_type_die (tree type, dw_die_ref context_die)
      flexibilty wrt arrays of variable size.  */
 
   bool collapse_nested_arrays = !is_ada ();
+
+  if (fill_variable_array_bounds (type))
+    return;
+
+  dw_die_ref scope_die = scope_die_for (type, context_die);
   tree element_type;
 
   /* Emit DW_TAG_string_type for Fortran character types (with kind 1 only, as
@@ -17853,8 +17988,64 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
 {
   tree node_or_origin = node ? node : origin;
   tree ultimate_origin;
-  dw_die_ref parm_die
-    = new_die (DW_TAG_formal_parameter, context_die, node);
+  dw_die_ref parm_die = NULL;
+  
+  if (TREE_CODE_CLASS (TREE_CODE (node_or_origin)) == tcc_declaration)
+    {
+      parm_die = lookup_decl_die (node);
+
+      /* If the contexts differ, we may not be talking about the same
+	 thing.  */
+      if (parm_die && parm_die->die_parent != context_die)
+	{
+	  if (!DECL_ABSTRACT_P (node))
+	    {
+	      /* This can happen when creating an inlined instance, in
+		 which case we need to create a new DIE that will get
+		 annotated with DW_AT_abstract_origin.  */
+	      parm_die = NULL;
+	    }
+	  else
+	    {
+	      /* Reuse DIE even with a differing context.
+
+		 This happens when called through
+		 dwarf2out_abstract_function for formal parameter
+		 packs.  */
+	      gcc_assert (parm_die->die_parent->die_tag
+			  == DW_TAG_GNU_formal_parameter_pack);
+	    }
+	}
+
+      if (parm_die && parm_die->die_parent == NULL)
+	{
+	  /* Check that parm_die already has the right attributes that
+	     we would have added below.  If any attributes are
+	     missing, fall through to add them.  */
+	  if (! DECL_ABSTRACT_P (node_or_origin)
+	      && !get_AT (parm_die, DW_AT_location)
+	      && !get_AT (parm_die, DW_AT_const_value))
+	    /* We are missing  location info, and are about to add it.  */
+	    ;
+	  else
+	    {
+	      add_child_die (context_die, parm_die);
+	      return parm_die;
+	    }
+	}
+    }
+
+  /* If we have a previously generated DIE, use it, unless this is an
+     concrete instance (origin != NULL), in which case we need a new
+     DIE with a corresponding DW_AT_abstract_origin.  */
+  bool reusing_die;
+  if (parm_die && origin == NULL)
+    reusing_die = true;
+  else
+    {
+      parm_die = new_die (DW_TAG_formal_parameter, context_die, node);
+      reusing_die = false;
+    }
 
   switch (TREE_CODE_CLASS (TREE_CODE (node_or_origin)))
     {
@@ -17862,6 +18053,10 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
       ultimate_origin = decl_ultimate_origin (node_or_origin);
       if (node || ultimate_origin)
 	origin = ultimate_origin;
+
+      if (reusing_die)
+	goto add_location;
+
       if (origin != NULL)
 	add_abstract_origin_attribute (parm_die, origin);
       else if (emit_name_p)
@@ -17881,6 +18076,7 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
 				decl_quals (node_or_origin),
 				context_die);
 	}
+    add_location:
       if (origin == NULL && DECL_ARTIFICIAL (node))
 	add_AT_flag (parm_die, DW_AT_artificial, 1);
 
@@ -18394,26 +18590,94 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 {
   tree origin = decl_ultimate_origin (decl);
   dw_die_ref subr_die;
-  tree outer_scope;
   dw_die_ref old_die = lookup_decl_die (decl);
+
+  /* This function gets called multiple times for different stages of
+     the debug process.  For example, for func() in this code:
+
+	namespace S
+	{
+	  void func() { ... }
+	}
+
+     ...we get called 4 times.  Twice in early debug and twice in
+     late debug:
+
+     Early debug
+     -----------
+
+       1. Once while generating func() within the namespace.  This is
+          the declaration.  The declaration bit below is set, as the
+          context is the namespace.
+
+	  A new DIE will be generated with DW_AT_declaration set.
+
+       2. Once for func() itself.  This is the specification.  The
+          declaration bit below is clear as the context is the CU.
+
+	  We will use the cached DIE from (1) to create a new DIE with
+	  DW_AT_specification pointing to the declaration in (1).
+
+     Late debug via rest_of_handle_final()
+     -------------------------------------
+
+       3. Once generating func() within the namespace.  This is also the
+          declaration, as in (1), but this time we will early exit below
+          as we have a cached DIE and a declaration needs no additional
+          annotations (no locations), as the source declaration line
+          info is enough.
+
+       4. Once for func() itself.  As in (2), this is the specification,
+          but this time we will re-use the cached DIE, and just annotate
+          it with the location information that should now be available.
+
+     For something without namespaces, but with abstract instances, we
+     are also called a multiple times:
+
+        class Base
+	{
+	public:
+	  Base ();	  // constructor declaration (1)
+	};
+
+	Base::Base () { } // constructor specification (2)
+
+    Early debug
+    -----------
+
+       1. Once for the Base() constructor by virtue of it being a
+          member of the Base class.  This is done via
+          rest_of_type_compilation.
+
+	  This is a declaration, so a new DIE will be created with
+	  DW_AT_declaration.
+
+       2. Once for the Base() constructor definition, but this time
+          while generating the abstract instance of the base
+          constructor (__base_ctor) which is being generated via early
+          debug of reachable functions.
+
+	  Even though we have a cached version of the declaration (1),
+	  we will create a DW_AT_specification of the declaration DIE
+	  in (1).
+
+       3. Once for the __base_ctor itself, but this time, we generate
+          an DW_AT_abstract_origin version of the DW_AT_specification in
+	  (2).
+
+    Late debug via rest_of_handle_final
+    -----------------------------------
+
+       4. One final time for the __base_ctor (which will have a cached
+          DIE with DW_AT_abstract_origin created in (3).  This time,
+          we will just annotate the location information now
+          available.
+  */
   int declaration = (current_function_decl != decl
 		     || class_or_namespace_scope_p (context_die));
 
   premark_used_types (DECL_STRUCT_FUNCTION (decl));
 
-  /* It is possible to have both DECL_ABSTRACT_P and DECLARATION be true if we
-     started to generate the abstract instance of an inline, decided to output
-     its containing class, and proceeded to emit the declaration of the inline
-     from the member list for the class.  If so, DECLARATION takes priority;
-     we'll get back to the abstract instance when done with the class.  */
-
-  /* The class-scope declaration DIE must be the primary DIE.  */
-  if (origin && declaration && class_or_namespace_scope_p (context_die))
-    {
-      origin = NULL;
-      gcc_assert (!old_die);
-    }
-
   /* Now that the C++ front end lazily declares artificial member fns, we
      might need to retrofit the declaration into its class.  */
   if (!declaration && !origin && !old_die
@@ -18422,6 +18686,8 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       && debug_info_level > DINFO_LEVEL_TERSE)
     old_die = force_decl_die (decl);
 
+  bool dumped_early = false;
+  /* An inlined instance, tag a new DIE with DW_AT_abstract_origin.  */
   if (origin != NULL)
     {
       gcc_assert (!declaration || local_scope_p (context_die));
@@ -18431,19 +18697,34 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       if (old_die && old_die->die_parent == NULL)
 	add_child_die (context_die, old_die);
 
-      subr_die = new_die (DW_TAG_subprogram, context_die, decl);
-      add_abstract_origin_attribute (subr_die, origin);
-      /*  This is where the actual code for a cloned function is.
-	  Let's emit linkage name attribute for it.  This helps
-	  debuggers to e.g, set breakpoints into
-	  constructors/destructors when the user asks "break
-	  K::K".  */
-      add_linkage_name (subr_die, decl);
+      if (old_die && get_AT_ref (old_die, DW_AT_abstract_origin))
+	{
+	  /* If we have a DW_AT_abstract_origin we have a working
+	     cached version.  */
+	  subr_die = old_die;
+	}
+      else
+	{
+	  subr_die = new_die (DW_TAG_subprogram, context_die, decl);
+	  add_abstract_origin_attribute (subr_die, origin);
+	  /*  This is where the actual code for a cloned function is.
+	      Let's emit linkage name attribute for it.  This helps
+	      debuggers to e.g, set breakpoints into
+	      constructors/destructors when the user asks "break
+	      K::K".  */
+	  add_linkage_name (subr_die, decl);
+	}
     }
+  /* A cached copy, possibly from early dwarf generation.  Reuse as
+     much as possible.  */
   else if (old_die)
     {
-      expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
-      struct dwarf_file_data * file_index = lookup_filename (s.file);
+      /* A declaration that has been previously dumped needs no
+	 additional information.  */
+      if (declaration)
+	return;
+
+      dumped_early = old_die->dumped_early;
 
       if (!get_AT_flag (old_die, DW_AT_declaration)
 	  /* We can have a normal definition following an inline one in the
@@ -18453,7 +18734,13 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	{
 	  /* Detect and ignore this case, where we are trying to output
 	     something we have already output.  */
-	  return;
+	  if (get_AT (old_die, DW_AT_low_pc)
+	      || get_AT (old_die, DW_AT_ranges))
+	    return;
+
+	  /* If we have no location information, this must be a
+	     partially generated DIE from early dwarf generation.
+	     Fall through and generate it.  */
 	}
 
       /* If the definition comes from the same place as the declaration,
@@ -18463,23 +18750,43 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	 instances of inlines, since the spec requires the out-of-line copy
 	 to have the same parent.  For local class methods, this doesn't
 	 apply; we just use the old DIE.  */
-      if ((is_cu_die (old_die->die_parent) || context_die == NULL)
-	  && (DECL_ARTIFICIAL (decl)
-	      || (get_AT_file (old_die, DW_AT_decl_file) == file_index
-		  && (get_AT_unsigned (old_die, DW_AT_decl_line)
-		      == (unsigned) s.line))))
+      expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
+      struct dwarf_file_data * file_index = lookup_filename (s.file);
+      if ((is_cu_die (old_die->die_parent)
+	   /* This condition fixes the inconsistency/ICE with the
+	      following Fortran test (or some derivative thereof) while
+	      building libgfortran:
+
+		 module some_m
+		 contains
+		    logical function funky (FLAG)
+		      funky = .true.
+		   end function
+		 end module
+	   */
+	   || old_die->die_parent->die_tag == DW_TAG_module
+	   || context_die == NULL)
+	   && (DECL_ARTIFICIAL (decl)
+	       || (get_AT_file (old_die, DW_AT_decl_file) == file_index
+		   && (get_AT_unsigned (old_die, DW_AT_decl_line)
+		       == (unsigned) s.line))))
 	{
 	  subr_die = old_die;
 
-	  /* Clear out the declaration attribute and the formal parameters.
-	     Do not remove all children, because it is possible that this
-	     declaration die was forced using force_decl_die(). In such
-	     cases die that forced declaration die (e.g. TAG_imported_module)
-	     is one of the children that we do not want to remove.  */
-	  remove_AT (subr_die, DW_AT_declaration);
-	  remove_AT (subr_die, DW_AT_object_pointer);
-	  remove_child_TAG (subr_die, DW_TAG_formal_parameter);
+	  /* Clear out the declaration attribute, but leave the
+	     parameters so they can be augmented with location
+	     information later.  Unless this was a declaration, in
+	     which case, wipe out the nameless parameters and recreate
+	     them further down.  */
+	  if (remove_AT (subr_die, DW_AT_declaration))
+	    {
+
+	      remove_AT (subr_die, DW_AT_object_pointer);
+	      remove_child_TAG (subr_die, DW_TAG_formal_parameter);
+	    }
 	}
+      /* Make a specification pointing to the previously built
+	 declaration.  */
       else
 	{
 	  subr_die = new_die (DW_TAG_subprogram, context_die, decl);
@@ -18501,6 +18808,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	    }
 	}
     }
+  /* Create a fresh DIE for anything else.  */
   else
     {
       subr_die = new_die (DW_TAG_subprogram, context_die, decl);
@@ -18527,6 +18835,11 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       add_accessibility_attribute (subr_die, decl);
     }
 
+  /* Unless we have an existing non-declaration DIE, equate the new
+     DIE.  */
+  if (!old_die || is_declaration_die (old_die))
+    equate_decl_number_to_die (decl, subr_die);
+
   if (declaration)
     {
       if (!old_die || !get_AT (old_die, DW_AT_inline))
@@ -18544,17 +18857,9 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	  if (lang_hooks.decls.function_decl_deleted_p (decl)
 	      && (! dwarf_strict))
 	    add_AT_flag (subr_die, DW_AT_GNU_deleted, 1);
-
-	  /* The first time we see a member function, it is in the context of
-	     the class to which it belongs.  We make sure of this by emitting
-	     the class first.  The next time is the definition, which is
-	     handled above.  The two may come from the same source text.
-
-	     Note that force_decl_die() forces function declaration die. It is
-	     later reused to represent definition.  */
-	  equate_decl_number_to_die (decl, subr_die);
 	}
     }
+  /* Tag abstract instances with DW_AT_inline.  */
   else if (DECL_ABSTRACT_P (decl))
     {
       if (DECL_DECLARED_INLINE_P (decl))
@@ -18575,18 +18880,15 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       if (DECL_DECLARED_INLINE_P (decl)
 	  && lookup_attribute ("artificial", DECL_ATTRIBUTES (decl)))
 	add_AT_flag (subr_die, DW_AT_artificial, 1);
-
-      equate_decl_number_to_die (decl, subr_die);
     }
-  else if (!DECL_EXTERNAL (decl))
+  /* For non DECL_EXTERNALs, if range information is available, fill
+     the DIE with it.  */
+  else if (!DECL_EXTERNAL (decl) && !early_dwarf)
     {
       HOST_WIDE_INT cfa_fb_offset;
-      struct function *fun = DECL_STRUCT_FUNCTION (decl);
 
-      if (!old_die || !get_AT (old_die, DW_AT_inline))
-	equate_decl_number_to_die (decl, subr_die);
+      struct function *fun = DECL_STRUCT_FUNCTION (decl);
 
-      gcc_checking_assert (fun);
       if (!flag_reorder_blocks_and_partition)
 	{
 	  dw_fde_ref fde = fun->fde;
@@ -18740,12 +19042,13 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       compute_frame_pointer_to_fb_displacement (cfa_fb_offset);
 
       if (fun->static_chain_decl)
-	add_AT_location_description (subr_die, DW_AT_static_link,
-		 loc_list_from_tree (fun->static_chain_decl, 2, NULL));
+	add_AT_location_description
+	  (subr_die, DW_AT_static_link,
+	   loc_list_from_tree (fun->static_chain_decl, 2, NULL));
     }
 
   /* Generate child dies for template paramaters.  */
-  if (debug_info_level > DINFO_LEVEL_TERSE)
+  if (early_dwarf && debug_info_level > DINFO_LEVEL_TERSE)
     gen_generic_params_dies (decl);
 
   /* Now output descriptions of the arguments for this function. This gets
@@ -18764,12 +19067,17 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
   if (debug_info_level <= DINFO_LEVEL_TERSE)
     ;
   else if (declaration)
-    gen_formal_types_die (decl, subr_die);
+    {
+      /* Only generate a prototype's parameters once.  */
+      if (!dumped_early)
+	gen_formal_types_die (decl, subr_die);
+    }
   else
     {
       /* Generate DIEs to represent all known formal parameters.  */
       tree parm = DECL_ARGUMENTS (decl);
-      tree generic_decl = lang_hooks.decls.get_generic_function_decl (decl);
+      tree generic_decl = early_dwarf
+	? lang_hooks.decls.get_generic_function_decl (decl) : NULL;
       tree generic_decl_parm = generic_decl
 				? DECL_ARGUMENTS (generic_decl)
 				: NULL;
@@ -18834,11 +19142,14 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	gen_unspecified_parameters_die (decl, subr_die);
     }
 
+  if (subr_die != old_die)
+    /* Add the calling convention attribute if requested.  */
+    add_calling_convention_attribute (subr_die, decl);
+
   /* Output Dwarf info for all of the stuff within the body of the function
-     (if it has one - it may be just a declaration).  */
-  outer_scope = DECL_INITIAL (decl);
+     (if it has one - it may be just a declaration).
 
-  /* OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent
+     OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent
      a function.  This BLOCK actually represents the outermost binding contour
      for the function, i.e. the contour in which the function's formal
      parameters and labels get declared. Curiously, it appears that the front
@@ -18852,6 +19163,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
      a BLOCK node representing the function's outermost pair of curly braces,
      and any blocks used for the base and member initializers of a C++
      constructor function.  */
+  tree outer_scope = DECL_INITIAL (decl);
   if (! declaration && outer_scope && TREE_CODE (outer_scope) != ERROR_MARK)
     {
       int call_site_note_count = 0;
@@ -18861,6 +19173,9 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       if (DECL_NAME (DECL_RESULT (decl)))
 	gen_decl_die (DECL_RESULT (decl), NULL, subr_die);
 
+      /* The first time through decls_for_scope we will generate the
+	 DIEs for the locals.  The second time, we fill in the
+	 location info.  */
       decls_for_scope (outer_scope, subr_die);
 
       if (call_arg_locations && !dwarf_strict)
@@ -19012,10 +19327,6 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       call_site_count = -1;
       tail_call_site_count = -1;
     }
-
-  if (subr_die != old_die)
-    /* Add the calling convention attribute if requested.  */
-    add_calling_convention_attribute (subr_die, decl);
 }
 
 /* Returns a hash value for X (which really is a die_struct).  */
@@ -19035,6 +19346,33 @@ block_die_hasher::equal (die_struct *x, die_struct *y)
   return x->decl_id == y->decl_id && x->die_parent == y->die_parent;
 }
 
+/* Return TRUE if DECL, which may have been previously generated as
+   OLD_DIE, is a candidate for a DW_AT_specification.  DECLARATION is
+   true if decl (or its origin) is either an extern declaration or a
+   class/namespace scoped declaration.
+
+   The declare_in_namespace support causes us to get two DIEs for one
+   variable, both of which are declarations.  We want to avoid
+   considering one to be a specification, so we must test for
+   DECLARATION and DW_AT_declaration.  */
+static inline bool
+decl_will_get_specification_p (dw_die_ref old_die, tree decl, bool declaration)
+{
+  return (old_die && TREE_STATIC (decl) && !declaration
+	  && get_AT_flag (old_die, DW_AT_declaration) == 1);
+}
+
+/* Return true if DECL is a local static.  */
+
+static inline bool
+local_function_static (tree decl)
+{
+  gcc_assert (TREE_CODE (decl) == VAR_DECL);
+  return TREE_STATIC (decl)
+    && DECL_CONTEXT (decl)
+    && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL;
+}
+
 /* Generate a DIE to represent a declared data object.
    Either DECL or ORIGIN must be non-null.  */
 
@@ -19047,7 +19385,6 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
   tree ultimate_origin;
   dw_die_ref var_die;
   dw_die_ref old_die = decl ? lookup_decl_die (decl) : NULL;
-  dw_die_ref origin_die;
   bool declaration = (DECL_EXTERNAL (decl_or_origin)
 		      || class_or_namespace_scope_p (context_die));
   bool specialization_p = false;
@@ -19162,11 +19499,74 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
       return;
     }
 
+  dw_die_ref origin_die = NULL;
+
+  if (old_die && old_die->dumped_early)
+    {
+      if (decl_will_get_specification_p (old_die, decl, declaration))
+	{
+	  /* If we already have a DW_AT_specification, all we need is
+	     location info.  */
+	  if (get_AT (old_die, DW_AT_specification))
+	    {
+	      var_die = old_die;
+	      goto gen_variable_die_location;
+	    }
+	  /* Otherwise fall-thru so we can make a new variable die
+	     along with a DW_AT_specification.  */
+	}
+      else if (declaration)
+	{
+	  /* A declaration that has been previously dumped, needs no
+	     further annotations, since it doesn't need location on
+	     the second pass.  */
+	  return;
+	}
+      else if (old_die->die_parent != context_die)
+	{
+	  /* If the contexts differ, it means we _MAY_ not be talking
+	     about the same thing.  */
+	  if (origin)
+	    {
+	      /* If we will be creating an inlined instance, we need a
+		 new DIE that will get annotated with
+		 DW_AT_abstract_origin.  Clear things so we can get a
+		 new DIE.  */
+	      gcc_assert (!DECL_ABSTRACT_P (decl));
+	      old_die = NULL;
+	    }
+	  else
+	    {
+	      /* In some cases we end up with different contexts because
+		 the context_die is set to the context of the containing
+		 function, whereas the cached die is correctly set to the
+		 (possible) enclosing lexical scope (DW_TAG_lexical_block).
+		 In which case, special case it (hack).
+
+		 See dwarf2out_decl and its use of
+		 local_function_static to see how this can happened.
+		 In java, it can happen with non local statics, hence
+		 we do not check for TREE_STATIC here.  */
+	      gcc_assert (!DECL_CONTEXT (decl)
+			  || TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL);
+	      var_die = old_die;
+	      goto gen_variable_die_location;
+	    }
+	}
+      else
+	{
+	  /* If a DIE was dumped early, it still needs location info.
+	     Skip to where we fill the location bits.  */
+	  var_die = old_die;
+	  goto gen_variable_die_location;
+	}
+    }
+
   /* If the compiler emitted a definition for the DECL declaration
-     and if we already emitted a DIE for it, don't emit a second
+     and we already emitted a DIE for it, don't emit a second
      DIE for it again. Allow re-declarations of DECLs that are
      inside functions, though.  */
-  if (old_die && declaration && !local_scope_p (context_die))
+  else if (old_die && !declaration && !local_scope_p (context_die))
     return;
 
   /* For static data members, the declaration in the class is supposed
@@ -19177,7 +19577,6 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
   else
     var_die = new_die (DW_TAG_variable, context_die, decl);
 
-  origin_die = NULL;
   if (origin != NULL)
     origin_die = add_abstract_origin_attribute (var_die, origin);
 
@@ -19188,14 +19587,8 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
      copy decls and set the DECL_ABSTRACT_P flag on them instead of
      sharing them.
 
-     ??? Duplicated blocks have been rewritten to use .debug_ranges.
-
-     ??? The declare_in_namespace support causes us to get two DIEs for one
-     variable, both of which are declarations.  We want to avoid considering
-     one to be a specification, so we must test that this DIE is not a
-     declaration.  */
-  else if (old_die && TREE_STATIC (decl) && ! declaration
-	   && get_AT_flag (old_die, DW_AT_declaration) == 1)
+     ??? Duplicated blocks have been rewritten to use .debug_ranges.  */
+  else if (decl_will_get_specification_p (old_die, decl, declaration))
     {
       /* This is a definition of a C++ class level static.  */
       add_AT_specification (var_die, old_die);
@@ -19249,9 +19642,11 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
   if (declaration)
     add_AT_flag (var_die, DW_AT_declaration, 1);
 
-  if (decl && (DECL_ABSTRACT_P (decl) || declaration || old_die == NULL))
+  if (decl && (DECL_ABSTRACT_P (decl)
+	       || !old_die || is_declaration_die (old_die)))
     equate_decl_number_to_die (decl, var_die);
 
+ gen_variable_die_location:
   if (! declaration
       && (! DECL_ABSTRACT_P (decl_or_origin)
 	  /* Local static vars are shared between all clones/inlines,
@@ -19264,13 +19659,11 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
 	 to add it again.  */
       && (origin_die == NULL || get_AT (origin_die, DW_AT_location) == NULL))
     {
-      if (TREE_CODE (decl_or_origin) == VAR_DECL && TREE_STATIC (decl_or_origin)
-          && !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl_or_origin)))
-	defer_location (decl_or_origin, var_die);
+      if (early_dwarf)
+	add_pubname (decl_or_origin, var_die);
       else
-        add_location_or_const_value_attribute (var_die, decl_or_origin,
+	add_location_or_const_value_attribute (var_die, decl_or_origin,
 					       decl == NULL, DW_AT_location);
-      add_pubname (decl_or_origin, var_die);
     }
   else
     tree_add_const_value_attribute_for_decl (var_die, decl_or_origin);
@@ -19284,7 +19677,12 @@ gen_const_die (tree decl, dw_die_ref context_die)
   dw_die_ref const_die;
   tree type = TREE_TYPE (decl);
 
+  const_die = lookup_decl_die (decl);
+  if (const_die)
+    return;
+
   const_die = new_die (DW_TAG_constant, context_die, decl);
+  equate_decl_number_to_die (decl, const_die);
   add_name_and_src_coords_attributes (const_die, decl);
   add_type_attribute (const_die, type, TYPE_QUAL_CONST, context_die);
   if (TREE_PUBLIC (decl))
@@ -19300,14 +19698,20 @@ static void
 gen_label_die (tree decl, dw_die_ref context_die)
 {
   tree origin = decl_ultimate_origin (decl);
-  dw_die_ref lbl_die = new_die (DW_TAG_label, context_die, decl);
+  dw_die_ref lbl_die = lookup_decl_die (decl);
   rtx insn;
   char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
-  if (origin != NULL)
-    add_abstract_origin_attribute (lbl_die, origin);
-  else
-    add_name_and_src_coords_attributes (lbl_die, decl);
+  if (!lbl_die)
+    {
+      lbl_die = new_die (DW_TAG_label, context_die, decl);
+      equate_decl_number_to_die (decl, lbl_die);
+
+      if (origin != NULL)
+	add_abstract_origin_attribute (lbl_die, origin);
+      else
+	add_name_and_src_coords_attributes (lbl_die, decl);
+    }
 
   if (DECL_ABSTRACT_P (decl))
     equate_decl_number_to_die (decl, lbl_die);
@@ -19461,13 +19865,56 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
 static void
 gen_lexical_block_die (tree stmt, dw_die_ref context_die)
 {
-  dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+  dw_die_ref old_die = BLOCK_DIE (stmt);
+  dw_die_ref stmt_die;
+  if (!old_die)
+    {
+      stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+      BLOCK_DIE (stmt) = stmt_die;
+    }
 
-  if (call_arg_locations)
-    BLOCK_DIE (stmt) = stmt_die;
+  if (BLOCK_ABSTRACT (stmt))
+    {
+      if (old_die)
+	{
+#ifdef ENABLE_CHECKING
+	  /* This must have been generated early and it won't even
+	     need location information since it's a DW_AT_inline
+	     function.  */
+	  for (dw_die_ref c = context_die; c; c = c->die_parent)
+	    if (c->die_tag == DW_TAG_inlined_subroutine
+		|| c->die_tag == DW_TAG_subprogram)
+	      {
+		gcc_assert (get_AT (c, DW_AT_inline));
+		break;
+	      }
+#endif
+	  return;
+	}
+    }
+  else if (BLOCK_ABSTRACT_ORIGIN (stmt))
+    {
+      /* If this is an inlined instance, create a new lexical die for
+	 anything below to attach DW_AT_abstract_origin to.  */
+      if (old_die)
+	{
+	  stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+	  BLOCK_DIE (stmt) = stmt_die;
+	  old_die = NULL;
+	}
+    }
 
-  if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
-    add_high_low_attributes (stmt, stmt_die);
+  if (old_die)
+    stmt_die = old_die;
+
+  if (!early_dwarf)
+    {
+      /* A non abstract block whose blocks have already been reordered
+	 should have the instruction range for this block.  If so, set the
+	 high/low attributes.  */
+      if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
+	add_high_low_attributes (stmt, stmt_die);
+    }
 
   decls_for_scope (stmt, stmt_die);
 }
@@ -19962,6 +20409,16 @@ static void
 gen_struct_or_union_type_die (tree type, dw_die_ref context_die,
 				enum debug_info_usage usage)
 {
+  /* Fill in the size of variable-length fields in late dwarf.  */
+  if (TREE_ASM_WRITTEN (type)
+      && !early_dwarf)
+    {
+      tree member;
+      for (member = TYPE_FIELDS (type); member; member = DECL_CHAIN (member))
+	fill_variable_array_bounds (TREE_TYPE (member));
+      return;
+    }
+
   dw_die_ref type_die = lookup_type_die (type);
   dw_die_ref scope_die = 0;
   int nested = 0;
@@ -20081,7 +20538,11 @@ gen_typedef_die (tree decl, dw_die_ref context_die)
   tree origin;
 
   if (TREE_ASM_WRITTEN (decl))
-    return;
+    {
+      if (DECL_ORIGINAL_TYPE (decl))
+	fill_variable_array_bounds (DECL_ORIGINAL_TYPE (decl));
+      return;
+    }
 
   TREE_ASM_WRITTEN (decl) = 1;
   type_die = new_die (DW_TAG_typedef, context_die, decl);
@@ -20097,6 +20558,9 @@ gen_typedef_die (tree decl, dw_die_ref context_die)
 	{
 	  type = DECL_ORIGINAL_TYPE (decl);
 
+	  if (type == error_mark_node)
+	    return;
+
 	  gcc_assert (type != TREE_TYPE (decl));
 	  equate_type_number_to_die (TREE_TYPE (decl), type_die);
 	}
@@ -20104,6 +20568,9 @@ gen_typedef_die (tree decl, dw_die_ref context_die)
 	{
 	  type = TREE_TYPE (decl);
 
+	  if (type == error_mark_node)
+	    return;
+
 	  if (is_naming_typedef_decl (TYPE_NAME (type)))
 	    {
 	      /* Here, we are in the case of decl being a typedef naming
@@ -20164,13 +20631,15 @@ gen_tagged_type_die (tree type,
       || !is_tagged_type (type))
     return;
 
+  if (TREE_ASM_WRITTEN (type))
+    need_pop = 0;
   /* If this is a nested type whose containing class hasn't been written
      out yet, writing it out will cover this one, too.  This does not apply
      to instantiations of member class templates; they need to be added to
      the containing class as they are generated.  FIXME: This hurts the
      idea of combining type decls from multiple TUs, since we can't predict
      what set of template instantiations we'll get.  */
-  if (TYPE_CONTEXT (type)
+  else if (TYPE_CONTEXT (type)
       && AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
       && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
     {
@@ -20302,7 +20771,19 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
     }
 
   if (TREE_ASM_WRITTEN (type))
-    return;
+    {
+      /* Variable-length types may be incomplete even if
+	 TREE_ASM_WRITTEN.  For such types, fall through to
+	 gen_array_type_die() and possibly fill in
+	 DW_AT_{upper,lower}_bound attributes.  */
+      if ((TREE_CODE (type) != ARRAY_TYPE
+	   && TREE_CODE (type) != RECORD_TYPE
+	   && TREE_CODE (type) != UNION_TYPE
+	   && TREE_CODE (type) != QUAL_UNION_TYPE)
+	  || (TYPE_SIZE (type)
+	      && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST))
+	return;
+    }
 
   switch (TREE_CODE (type))
     {
@@ -20354,9 +20835,6 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
       break;
 
     case ARRAY_TYPE:
-      gen_array_type_die (type, context_die);
-      break;
-
     case VECTOR_TYPE:
       gen_array_type_die (type, context_die);
       break;
@@ -20527,8 +21005,11 @@ process_scope_var (tree stmt, tree decl, tree origin, dw_die_ref context_die)
   if (die != NULL && die->die_parent == NULL)
     add_child_die (context_die, die);
   else if (TREE_CODE (decl_or_origin) == IMPORTED_DECL)
-    dwarf2out_imported_module_or_decl_1 (decl_or_origin, DECL_NAME (decl_or_origin),
-					 stmt, context_die);
+    {
+      if (early_dwarf)
+	dwarf2out_imported_module_or_decl_1 (decl_or_origin, DECL_NAME (decl_or_origin),
+					     stmt, context_die);
+    }
   else
     gen_decl_die (decl, origin, context_die);
 }
@@ -20742,7 +21223,9 @@ setup_namespace_context (tree thing, dw_die_ref context_die)
    type) within its namespace, if appropriate.
 
    For compatibility with older debuggers, namespace DIEs only contain
-   declarations; all definitions are emitted at CU scope.  */
+   declarations; all definitions are emitted at CU scope, with
+   DW_AT_specification pointing to the declaration (like with class
+   members).  */
 
 static dw_die_ref
 declare_in_namespace (tree thing, dw_die_ref context_die)
@@ -21059,16 +21542,65 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
   return NULL;
 }
 \f
-/* Output debug information for global decl DECL.  Called from toplev.c after
-   compilation proper has finished.  */
+/* Output initial debug information for global DECL.  Called at the
+   end of the parsing process.
+
+   This is the initial debug generation process.  As such, the DIEs
+   generated may be incomplete.  A later debug generation pass
+   (dwarf2out_late_global_decl) will augment the information generated
+   in this pass (e.g., with complete location info).  */
 
 static void
-dwarf2out_global_decl (tree decl)
+dwarf2out_early_global_decl (tree decl)
 {
-  /* Output DWARF2 information for file-scope tentative data object
-     declarations, file-scope (extern) function declarations (which
-     had no corresponding body) and file-scope tagged type declarations
-     and definitions which have not yet been forced out.  */
+  set_early_dwarf s;
+
+  /* gen_decl_die() will set DECL_ABSTRACT because
+     cgraph_function_possibly_inlined_p() returns true.  This is in
+     turn will cause DW_AT_inline attributes to be set.
+
+     This happens because at early dwarf generation, there is no
+     cgraph information, causing cgraph_function_possibly_inlined_p()
+     to return true.  Trick cgraph_function_possibly_inlined_p()
+     while we generate dwarf early.  */
+  bool save = symtab->global_info_ready;
+  symtab->global_info_ready = true;
+
+  /* We don't handle TYPE_DECLs.  If required, they'll be reached via
+     other DECLs and they can point to template types or other things
+     that dwarf2out can't handle when done via dwarf2out_decl.  */
+  if (TREE_CODE (decl) != TYPE_DECL
+      && TREE_CODE (decl) != PARM_DECL)
+    {
+      tree save_fndecl = current_function_decl;
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+	{
+	  /* No cfun means the symbol has no body, so there's nothing
+	     to emit.  */
+	  if (!DECL_STRUCT_FUNCTION (decl))
+	    goto early_decl_exit;
+
+	  current_function_decl = decl;
+	}
+      dwarf2out_decl (decl);
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+	current_function_decl = save_fndecl;
+    }
+ early_decl_exit:
+  symtab->global_info_ready = save;
+}
+
+/* Output debug information for global decl DECL.  Called from
+   toplev.c after compilation proper has finished.  */
+
+static void
+dwarf2out_late_global_decl (tree decl)
+{
+  /* Output any global decls we missed or fill-in any location
+     information we were unable to determine on the first pass.
+
+     Skip over functions because they were handled by the
+     debug_hooks->function_decl() call in rest_of_handle_final.  */
   if ((TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl))
       && !POINTER_BOUNDS_P (decl))
     dwarf2out_decl (decl);
@@ -21080,7 +21612,10 @@ static void
 dwarf2out_type_decl (tree decl, int local)
 {
   if (!local)
-    dwarf2out_decl (decl);
+    {
+      set_early_dwarf s;
+      dwarf2out_decl (decl);
+    }
 }
 
 /* Output debug information for imported module or decl DECL.
@@ -21188,6 +21723,8 @@ dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
 
   gcc_assert (decl);
 
+  set_early_dwarf s;
+
   /* To emit DW_TAG_imported_module or DW_TAG_imported_decl, we need two DIEs.
      We need decl DIE for reference and scope die. First, get DIE for the decl
      itself.  */
@@ -21214,7 +21751,6 @@ dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
 
   /* OK, now we have DIEs for decl as well as scope. Emit imported die.  */
   dwarf2out_imported_module_or_decl_1 (decl, name, context, scope_die);
-
 }
 
 /* Output debug information for namelists.   */
@@ -21254,13 +21790,22 @@ gen_namelist_decl (tree name, dw_die_ref scope_die, tree item_decls)
 }
 
 
-/* Write the debugging output for DECL.  */
+/* Write the debugging output for DECL and return the DIE.  */
 
 static void
 dwarf2out_decl (tree decl)
 {
   dw_die_ref context_die = comp_unit_die ();
 
+#ifdef ENABLE_CHECKING
+  /* Save some info so we can later determine if we erroneously
+     created a DIE for something we had already created a DIE for.
+     We should always be reusing DIEs created early.  */
+  dw_die_ref early_die = NULL;
+  if (decl_die_table)
+    early_die = lookup_decl_die (decl);
+#endif
+
   switch (TREE_CODE (decl))
     {
     case ERROR_MARK:
@@ -21313,21 +21858,8 @@ dwarf2out_decl (tree decl)
       break;
 
     case VAR_DECL:
-      /* Ignore this VAR_DECL if it refers to a file-scope extern data object
-	 declaration and if the declaration was never even referenced from
-	 within this entire compilation unit.  We suppress these DIEs in
-	 order to save space in the .debug section (by eliminating entries
-	 which are probably useless).  Note that we must not suppress
-	 block-local extern declarations (whether used or not) because that
-	 would screw-up the debugger's name lookup mechanism and cause it to
-	 miss things which really ought to be in scope at a given point.  */
-      if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
-	return;
-
       /* For local statics lookup proper context die.  */
-      if (TREE_STATIC (decl)
-	  && DECL_CONTEXT (decl)
-	  && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
+      if (local_function_static (decl))
 	context_die = lookup_decl_die (DECL_CONTEXT (decl));
 
       /* If we are in terse mode, don't generate any DIEs to represent any
@@ -21382,6 +21914,19 @@ dwarf2out_decl (tree decl)
     }
 
   gen_decl_die (decl, NULL, context_die);
+
+  dw_die_ref die = lookup_decl_die (decl);
+  if (die)
+    check_die (die);
+#ifdef ENABLE_CHECKING
+  /* If we early created a DIE, make sure it didn't get re-created by
+     mistake.  */
+  if (early_die && early_die->dumped_early)
+    gcc_assert (early_die == die
+		/* We can have a differing DIE if and only if, the
+		   new one is a specification of the old one.  */
+		|| get_AT_ref (die, DW_AT_specification) == early_die);
+#endif
 }
 
 /* Write the debugging output for DECL.  */
@@ -21468,23 +22013,16 @@ dwarf_file_hasher::hash (dwarf_file_data *p)
    section) and references to those files numbers (in the .debug_srcinfo
    and.debug_macinfo sections).  If the filename given as an argument is not
    found in our current list, add it to the list and assign it the next
-   available unique index number.  In order to speed up searches, we remember
-   the index of the filename was looked up last.  This handles the majority of
-   all searches.  */
+   available unique index number.  */
 
 static struct dwarf_file_data *
 lookup_filename (const char *file_name)
 {
   struct dwarf_file_data * created;
 
-  /* Check to see if the file name that was searched on the previous
-     call matches this file name.  If so, return the index.  */
-  if (file_table_last_lookup
-      && (file_name == file_table_last_lookup->filename
-	  || filename_cmp (file_table_last_lookup->filename, file_name) == 0))
-    return file_table_last_lookup;
+  if (!file_name)
+    return NULL;
 
-  /* Didn't match the previous lookup, search the table.  */
   dwarf_file_data **slot
     = file_table->find_slot_with_hash (file_name, htab_hash_string (file_name),
 				       INSERT);
@@ -24523,11 +25061,20 @@ optimize_location_lists (dw_die_ref die)
 static void
 dwarf2out_finish (const char *filename)
 {
-  limbo_die_node *node, *next_node;
   comdat_type_node *ctnode;
-  unsigned int i;
   dw_die_ref main_comp_unit_die;
 
+  /* If the limbo list has anything, it should be things that were
+     created after the compilation proper.  Anything from the early
+     dwarf pass, should have parents and should never be in the limbo
+     list this late.  */
+  for (limbo_die_node *node = limbo_die_list; node; node = node->next)
+    gcc_assert (node->die->die_tag == DW_TAG_compile_unit
+		|| !node->die->dumped_early);
+
+  /* Flush out any latecomers to the limbo party.  */
+  dwarf2out_early_finish ();
+
   /* PCH might result in DW_AT_producer string being restored from the
      header compilation, so always fill it with empty string initially
      and overwrite only here.  */
@@ -24557,65 +25104,6 @@ dwarf2out_finish (const char *filename)
 	add_comp_dir_attribute (comp_unit_die ());
     }
 
-  if (deferred_locations_list)
-    for (i = 0; i < deferred_locations_list->length (); i++)
-      {
-	add_location_or_const_value_attribute (
-	    (*deferred_locations_list)[i].die,
-	    (*deferred_locations_list)[i].variable,
-	    false,
-	    DW_AT_location);
-      }
-
-  /* Traverse the limbo die list, and add parent/child links.  The only
-     dies without parents that should be here are concrete instances of
-     inline functions, and the comp_unit_die.  We can ignore the comp_unit_die.
-     For concrete instances, we can get the parent die from the abstract
-     instance.  */
-  for (node = limbo_die_list; node; node = next_node)
-    {
-      dw_die_ref die = node->die;
-      next_node = node->next;
-
-      if (die->die_parent == NULL)
-	{
-	  dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
-
-	  if (origin && origin->die_parent)
-	    add_child_die (origin->die_parent, die);
-	  else if (is_cu_die (die))
-	    ;
-	  else if (seen_error ())
-	    /* It's OK to be confused by errors in the input.  */
-	    add_child_die (comp_unit_die (), die);
-	  else
-	    {
-	      /* In certain situations, the lexical block containing a
-		 nested function can be optimized away, which results
-		 in the nested function die being orphaned.  Likewise
-		 with the return type of that nested function.  Force
-		 this to be a child of the containing function.
-
-		 It may happen that even the containing function got fully
-		 inlined and optimized out.  In that case we are lost and
-		 assign the empty child.  This should not be big issue as
-		 the function is likely unreachable too.  */
-	      gcc_assert (node->created_for);
-
-	      if (DECL_P (node->created_for))
-		origin = get_context_die (DECL_CONTEXT (node->created_for));
-	      else if (TYPE_P (node->created_for))
-		origin = scope_die_for (node->created_for, comp_unit_die ());
-	      else
-		origin = comp_unit_die ();
-
-	      add_child_die (origin, die);
-	    }
-	}
-    }
-
-  limbo_die_list = NULL;
-
 #if ENABLE_ASSERT_CHECKING
   {
     dw_die_ref die = comp_unit_die (), c;
@@ -24625,23 +25113,6 @@ dwarf2out_finish (const char *filename)
   resolve_addr (comp_unit_die ());
   move_marked_base_types ();
 
-  for (node = deferred_asm_name; node; node = node->next)
-    {
-      tree decl = node->created_for;
-      /* When generating LTO bytecode we can not generate new assembler
-         names at this point and all important decls got theirs via
-	 free-lang-data.  */
-      if (((!flag_generate_lto && !flag_generate_offload)
-	   || DECL_ASSEMBLER_NAME_SET_P (decl))
-	  && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
-	{
-	  add_linkage_attr (node->die, decl);
-	  move_linkage_attr (node->die);
-	}
-    }
-
-  deferred_asm_name = NULL;
-
   /* Walk through the list of incomplete types again, trying once more to
      emit full debugging info for them.  */
   retry_incomplete_types ();
@@ -24680,6 +25151,7 @@ dwarf2out_finish (const char *filename)
   /* Traverse the DIE's and add add sibling attributes to those DIE's
      that have children.  */
   add_sibling_attributes (comp_unit_die ());
+  limbo_die_node *node;
   for (node = limbo_die_list; node; node = node->next)
     add_sibling_attributes (node->die);
   for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
@@ -24941,6 +25413,83 @@ dwarf2out_finish (const char *filename)
     output_indirect_strings ();
 }
 
+/* Perform any cleanups needed after the early debug generation pass
+   has run.  */
+
+static void
+dwarf2out_early_finish (void)
+{
+  limbo_die_node *node, *next_node;
+
+  /* Add DW_AT_linkage_name for all deferred DIEs.  */
+  for (node = deferred_asm_name; node; node = node->next)
+    {
+      tree decl = node->created_for;
+      if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)
+	  /* A missing DECL_ASSEMBLER_NAME can be a constant DIE that
+	     ended up in in deferred_asm_name before we knew it was
+	     constant and never written to disk.  */
+	  && DECL_ASSEMBLER_NAME (decl))
+	{
+	  add_linkage_attr (node->die, decl);
+	  move_linkage_attr (node->die);
+	}
+    }
+  deferred_asm_name = NULL;
+
+  /* Traverse the limbo die list, and add parent/child links.  The only
+     dies without parents that should be here are concrete instances of
+     inline functions, and the comp_unit_die.  We can ignore the comp_unit_die.
+     For concrete instances, we can get the parent die from the abstract
+     instance.
+
+     The point here is to flush out the limbo list so that it is empty
+     and we don't need to stream it for LTO.  */
+  for (node = limbo_die_list; node; node = next_node)
+    {
+      dw_die_ref die = node->die;
+      next_node = node->next;
+
+      if (die->die_parent == NULL)
+	{
+	  dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
+
+	  if (origin && origin->die_parent)
+	    add_child_die (origin->die_parent, die);
+	  else if (is_cu_die (die))
+	    ;
+	  else if (seen_error ())
+	    /* It's OK to be confused by errors in the input.  */
+	    add_child_die (comp_unit_die (), die);
+	  else
+	    {
+	      /* In certain situations, the lexical block containing a
+		 nested function can be optimized away, which results
+		 in the nested function die being orphaned.  Likewise
+		 with the return type of that nested function.  Force
+		 this to be a child of the containing function.
+
+		 It may happen that even the containing function got fully
+		 inlined and optimized out.  In that case we are lost and
+		 assign the empty child.  This should not be big issue as
+		 the function is likely unreachable too.  */
+	      gcc_assert (node->created_for);
+
+	      if (DECL_P (node->created_for))
+		origin = get_context_die (DECL_CONTEXT (node->created_for));
+	      else if (TYPE_P (node->created_for))
+		origin = scope_die_for (node->created_for, comp_unit_die ());
+	      else
+		origin = comp_unit_die ();
+
+	      add_child_die (origin, die);
+	    }
+	}
+    }
+
+  limbo_die_list = NULL;
+}
+
 /* Reset all state within dwarf2out.c so that we can rerun the compiler
    within the same process.  For use by toplev::finalize.  */
 
@@ -24979,13 +25528,10 @@ dwarf2out_c_finalize (void)
   cold_text_section = NULL;
   current_unit_personality = NULL;
 
-  deferred_locations_list = NULL;
-
   next_die_offset = 0;
   single_comp_unit_die = NULL;
   comdat_type_list = NULL;
   limbo_die_list = NULL;
-  deferred_asm_name = NULL;
   file_table = NULL;
   decl_die_table = NULL;
   common_block_die_table = NULL;
@@ -25018,7 +25564,6 @@ dwarf2out_c_finalize (void)
   poc_label_num = 0;
   last_emitted_file = NULL;
   label_num = 0;
-  file_table_last_lookup = NULL;
   tmpl_value_parm_die_table = NULL;
   generic_type_instances = NULL;
   frame_pointer_fb_offset = 0;

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-28 21:31       ` Aldy Hernandez
@ 2015-05-29  6:33         ` Jason Merrill
  0 siblings, 0 replies; 34+ messages in thread
From: Jason Merrill @ 2015-05-29  6:33 UTC (permalink / raw)
  To: Aldy Hernandez, Richard Biener, Jan Hubicka; +Cc: gcc-patches

Looks good.

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-28 20:54         ` Jason Merrill
  2015-05-28 21:01           ` Jan Hubicka
@ 2015-05-29 12:07           ` Richard Biener
  2015-05-29 19:33           ` Aldy Hernandez
  2 siblings, 0 replies; 34+ messages in thread
From: Richard Biener @ 2015-05-29 12:07 UTC (permalink / raw)
  To: Jason Merrill, Tom Tromey; +Cc: Aldy Hernandez, Jan Hubicka, gcc-patches

On Thu, May 28, 2015 at 10:35 PM, Jason Merrill <jason@redhat.com> wrote:
> On 05/28/2015 02:53 PM, Aldy Hernandez wrote:
>>
>> On 05/27/2015 08:39 AM, Jason Merrill wrote:
>>>
>>> On 05/20/2015 11:50 AM, Aldy Hernandez wrote:
>>
>>
>>>> +  /* Fill in the size of variable-length fields in late dwarf.  */
>>>> +  if (TREE_ASM_WRITTEN (type)
>>>> +      && !early_dwarf_dumping)
>>>> +    {
>>>> +      tree member;
>>>> +      for (member = TYPE_FIELDS (type); member; member = DECL_CHAIN
>>>> (member))
>>>> +    fill_variable_array_bounds (TREE_TYPE (member));
>>>> +      return;
>>>> +    }
>>>
>>>
>>> Why is this happening in late dwarf?  I'm concerned that front-end
>>> information that is necessary to do this might be lost by that point.
>>
>>
>> I thought only after the optimizations had run their course would we be
>> guaranteed to have accurate bound information.  At least, that's what my
>> experience showed.
>
>
> Hmm, I'm don't know why optimizations would change the representation of the
> array type.

Correct.  It works fine with the LTO prototype I did apart from gdb not really
getting the association between the early DIEs

 <0><166>: Abbrev Number: 1 (DW_TAG_compile_unit)
...
 <1><1e5>: Abbrev Number: 6 (DW_TAG_subprogram)
...
 <2><1fc>: Abbrev Number: 8 (DW_TAG_variable)
    <1fd>   DW_AT_type        : <0x1d7>
    <201>   DW_AT_artificial  : 1
    <201>   DW_AT_declaration : 1
 <2><201>: Abbrev Number: 3 (DW_TAG_variable)
    <202>   DW_AT_name        : a
    <204>   DW_AT_decl_file   : 1
    <205>   DW_AT_decl_line   : 15
    <206>   DW_AT_type        : <0x20b>
 <2><20a>: Abbrev Number: 0
 <1><20b>: Abbrev Number: 9 (DW_TAG_array_type)
    <20c>   DW_AT_type        : <0x21e>
    <210>   DW_AT_sibling     : <0x21e>
 <2><214>: Abbrev Number: 10 (DW_TAG_subrange_type)
    <215>   DW_AT_type        : <0x1d7>
    <219>   DW_AT_upper_bound : <0x1fc>

and the late DIEs annotating the above

 <0><24c>: Abbrev Number: 1 (DW_TAG_compile_unit)
...
 <1><30c>: Abbrev Number: 3 (DW_TAG_subprogram)
    <30d>   DW_AT_abstract_origin: <0x1e5>
...
 <2><32e>: Abbrev Number: 4 (DW_TAG_variable)
    <32f>   DW_AT_abstract_origin: <0x1fc>
    <333>   DW_AT_location    : 11 byte block: 75 1 8 20 24 8 20 26 31
1c 9f    (DW_OP_breg5 (rdi): 1; DW_OP_const1u: 32; DW_OP_shl;
DW_OP_const1u: 32; DW_OP_shra; DW_OP_lit1; DW_OP_minus;
DW_OP_stack_value)
 <2><33f>: Abbrev Number: 11 (DW_TAG_variable)
    <340>   DW_AT_abstract_origin: <0x201>
<2><344>: Abbrev Number: 0
 <1><345>: Abbrev Number: 12 (DW_TAG_subprogram)

so it fails to jump through hoops when looking up the type of 'a'
seeing the annotation
to the variable used in the array types upper bound... (probably
expected, I'd probably
need to pull down the type, and the subrange-type as well, even though I do not
annotate them).

Or we can teach gdb to jump through the hoops (basically collect all
additional info
that a subprogram DIE children provide to the subprogram abstract
origin children DIEs
somewhen in advance...)

It would be a shame if I really had to create "empty" references to
all the dependence
chain formed via types from the array variable to the array subrange
type upper bound.

Richard.

>>>> +      /* Variable-length types may be incomplete even if
>>>> +     TREE_ASM_WRITTEN.  For such types, fall through to
>>>> +     gen_array_type_die() and possibly fill in
>>>> +     DW_AT_{upper,lower}_bound attributes.  */
>>>> +      if ((TREE_CODE (type) != ARRAY_TYPE
>>>> +       && TREE_CODE (type) != RECORD_TYPE
>>>> +       && TREE_CODE (type) != UNION_TYPE
>>>> +       && TREE_CODE (type) != QUAL_UNION_TYPE)
>>>> +      || (TYPE_SIZE (type)
>>>> +          && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST))
>>>
>>>
>>> Similarly, why check for INTEGER_CST here?
>>
>>
>> The INTEGER_CST check was supposed to mean "we have bound information
>> already, no need to look further".
>>
>> I guess we could have a variable length bound that does not decay to a
>> constant.
>
>
> Right.  I would expect that to usually be the case with VLAs.
>
>> Perhaps I could check the presence of a cached DIE with a
>> type DIE containing a DW_TAG_subrange_type *and*
>> DW_AT_{lower,upper}_bound ??.  Basically I just want to add bound
>> information, if available and not already present.
>>
>> Suggestions?
>
>
> I'm still not sure why we can't just emit bound info in early dwarf. Can you
> be more specific about the optimization thing?
>
> Jason
>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-28 20:54         ` Jason Merrill
  2015-05-28 21:01           ` Jan Hubicka
  2015-05-29 12:07           ` Richard Biener
@ 2015-05-29 19:33           ` Aldy Hernandez
  2015-05-29 19:40             ` Richard Biener
  2015-05-29 19:47             ` Jason Merrill
  2 siblings, 2 replies; 34+ messages in thread
From: Aldy Hernandez @ 2015-05-29 19:33 UTC (permalink / raw)
  To: Jason Merrill, Richard Biener, Jan Hubicka; +Cc: gcc-patches

On 05/28/2015 04:35 PM, Jason Merrill wrote:
> On 05/28/2015 02:53 PM, Aldy Hernandez wrote:
>> On 05/27/2015 08:39 AM, Jason Merrill wrote:
>>> On 05/20/2015 11:50 AM, Aldy Hernandez wrote:
>>
>>>> +  /* Fill in the size of variable-length fields in late dwarf.  */
>>>> +  if (TREE_ASM_WRITTEN (type)
>>>> +      && !early_dwarf_dumping)
>>>> +    {
>>>> +      tree member;
>>>> +      for (member = TYPE_FIELDS (type); member; member = DECL_CHAIN
>>>> (member))
>>>> +    fill_variable_array_bounds (TREE_TYPE (member));
>>>> +      return;
>>>> +    }
>>>
>>> Why is this happening in late dwarf?  I'm concerned that front-end
>>> information that is necessary to do this might be lost by that point.
>>
>> I thought only after the optimizations had run their course would we be
>> guaranteed to have accurate bound information.  At least, that's what my
>> experience showed.
>
> Hmm, I'm don't know why optimizations would change the representation of
> the array type.
>
>>>> +      /* Variable-length types may be incomplete even if
>>>> +     TREE_ASM_WRITTEN.  For such types, fall through to
>>>> +     gen_array_type_die() and possibly fill in
>>>> +     DW_AT_{upper,lower}_bound attributes.  */
>>>> +      if ((TREE_CODE (type) != ARRAY_TYPE
>>>> +       && TREE_CODE (type) != RECORD_TYPE
>>>> +       && TREE_CODE (type) != UNION_TYPE
>>>> +       && TREE_CODE (type) != QUAL_UNION_TYPE)
>>>> +      || (TYPE_SIZE (type)
>>>> +          && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST))
>>>
>>> Similarly, why check for INTEGER_CST here?
>>
>> The INTEGER_CST check was supposed to mean "we have bound information
>> already, no need to look further".
>>
>> I guess we could have a variable length bound that does not decay to a
>> constant.
>
> Right.  I would expect that to usually be the case with VLAs.
>
>> Perhaps I could check the presence of a cached DIE with a
>> type DIE containing a DW_TAG_subrange_type *and*
>> DW_AT_{lower,upper}_bound ??.  Basically I just want to add bound
>> information, if available and not already present.
>>
>> Suggestions?
>
> I'm still not sure why we can't just emit bound info in early dwarf. Can
> you be more specific about the optimization thing?

Ok, I see what I was trying to do, albeit incorrectly.  Imagine this:

unsigned int i=555;

int main()
{
   unsigned int array[i];
   ...
}

For the VLA, I'd like to check if we have an array type with a missing 
DW_AT_{upper,lower}_bound late in the game, and fill it in.

During early dwarf we only have an uninitialized gimple register 
representing the bound, and loc_list_from_tree() cannot find the RTL 
with the final bound location.  Thus, we end up with a missing bound, 
which I propose to fill in late dwarf.

Obviously I was doing some nonsense with TYPE_SIZE != INTEGER_CST, when 
in reality I should probably check that TREE_CODE (type) == ARRAY_TYPE 
and that we are missing the bound late (by looking for DW_AT_*_bound in 
the cached DIE).

Is this acceptable, or where you thinking of some other scheme?

Thanks.
Aldy

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-29 19:33           ` Aldy Hernandez
@ 2015-05-29 19:40             ` Richard Biener
  2015-05-29 19:49               ` Jason Merrill
  2015-05-29 19:47             ` Jason Merrill
  1 sibling, 1 reply; 34+ messages in thread
From: Richard Biener @ 2015-05-29 19:40 UTC (permalink / raw)
  To: Aldy Hernandez, Jason Merrill, Jan Hubicka; +Cc: gcc-patches

On May 29, 2015 8:42:50 PM GMT+02:00, Aldy Hernandez <aldyh@redhat.com> wrote:
>On 05/28/2015 04:35 PM, Jason Merrill wrote:
>> On 05/28/2015 02:53 PM, Aldy Hernandez wrote:
>>> On 05/27/2015 08:39 AM, Jason Merrill wrote:
>>>> On 05/20/2015 11:50 AM, Aldy Hernandez wrote:
>>>
>>>>> +  /* Fill in the size of variable-length fields in late dwarf. 
>*/
>>>>> +  if (TREE_ASM_WRITTEN (type)
>>>>> +      && !early_dwarf_dumping)
>>>>> +    {
>>>>> +      tree member;
>>>>> +      for (member = TYPE_FIELDS (type); member; member =
>DECL_CHAIN
>>>>> (member))
>>>>> +    fill_variable_array_bounds (TREE_TYPE (member));
>>>>> +      return;
>>>>> +    }
>>>>
>>>> Why is this happening in late dwarf?  I'm concerned that front-end
>>>> information that is necessary to do this might be lost by that
>point.
>>>
>>> I thought only after the optimizations had run their course would we
>be
>>> guaranteed to have accurate bound information.  At least, that's
>what my
>>> experience showed.
>>
>> Hmm, I'm don't know why optimizations would change the representation
>of
>> the array type.
>>
>>>>> +      /* Variable-length types may be incomplete even if
>>>>> +     TREE_ASM_WRITTEN.  For such types, fall through to
>>>>> +     gen_array_type_die() and possibly fill in
>>>>> +     DW_AT_{upper,lower}_bound attributes.  */
>>>>> +      if ((TREE_CODE (type) != ARRAY_TYPE
>>>>> +       && TREE_CODE (type) != RECORD_TYPE
>>>>> +       && TREE_CODE (type) != UNION_TYPE
>>>>> +       && TREE_CODE (type) != QUAL_UNION_TYPE)
>>>>> +      || (TYPE_SIZE (type)
>>>>> +          && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST))
>>>>
>>>> Similarly, why check for INTEGER_CST here?
>>>
>>> The INTEGER_CST check was supposed to mean "we have bound
>information
>>> already, no need to look further".
>>>
>>> I guess we could have a variable length bound that does not decay to
>a
>>> constant.
>>
>> Right.  I would expect that to usually be the case with VLAs.
>>
>>> Perhaps I could check the presence of a cached DIE with a
>>> type DIE containing a DW_TAG_subrange_type *and*
>>> DW_AT_{lower,upper}_bound ??.  Basically I just want to add bound
>>> information, if available and not already present.
>>>
>>> Suggestions?
>>
>> I'm still not sure why we can't just emit bound info in early dwarf.
>Can
>> you be more specific about the optimization thing?
>
>Ok, I see what I was trying to do, albeit incorrectly.  Imagine this:
>
>unsigned int i=555;
>
>int main()
>{
>   unsigned int array[i];
>   ...
>}
>
>For the VLA, I'd like to check if we have an array type with a missing 
>DW_AT_{upper,lower}_bound late in the game, and fill it in.
>
>During early dwarf we only have an uninitialized gimple register 
>representing the bound, and loc_list_from_tree() cannot find the RTL 
>with the final bound location.  Thus, we end up with a missing bound, 
>which I propose to fill in late dwarf.
>
>Obviously I was doing some nonsense with TYPE_SIZE != INTEGER_CST, when
>
>in reality I should probably check that TREE_CODE (type) == ARRAY_TYPE 
>and that we are missing the bound late (by looking for DW_AT_*_bound in
>
>the cached DIE).
>
>Is this acceptable, or where you thinking of some other scheme?

ISTR I had to mark the gimple reg used for the bound as non-DECL_IGNORED for the LTO stuff.

Richard.

>Thanks.
>Aldy


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-29 19:33           ` Aldy Hernandez
  2015-05-29 19:40             ` Richard Biener
@ 2015-05-29 19:47             ` Jason Merrill
  1 sibling, 0 replies; 34+ messages in thread
From: Jason Merrill @ 2015-05-29 19:47 UTC (permalink / raw)
  To: Aldy Hernandez, Richard Biener, Jan Hubicka; +Cc: gcc-patches

On 05/29/2015 02:42 PM, Aldy Hernandez wrote:
> unsigned int i=555;
>
> int main()
> {
>    unsigned int array[i];
>    ...
> }
>
> For the VLA, I'd like to check if we have an array type with a missing
> DW_AT_{upper,lower}_bound late in the game, and fill it in.
>
> During early dwarf we only have an uninitialized gimple register
> representing the bound

Ah, I see, from gimplify_type_sizes.

> and loc_list_from_tree() cannot find the RTL
> with the final bound location.  Thus, we end up with a missing bound,
> which I propose to fill in late dwarf.

OK, that makes sense.  I wonder if we should emit debug info for the 
gimple register; that would allow us to fill in the bound during early 
dwarf.

> Obviously I was doing some nonsense with TYPE_SIZE != INTEGER_CST, when
> in reality I should probably check that TREE_CODE (type) == ARRAY_TYPE
> and that we are missing the bound late (by looking for DW_AT_*_bound in
> the cached DIE).

But this sounds reasonable.

Jason


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-29 19:40             ` Richard Biener
@ 2015-05-29 19:49               ` Jason Merrill
  2015-05-31  7:53                 ` Aldy Hernandez
  0 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2015-05-29 19:49 UTC (permalink / raw)
  To: Richard Biener, Aldy Hernandez, Jan Hubicka; +Cc: gcc-patches

On 05/29/2015 03:26 PM, Richard Biener wrote:
> ISTR I had to mark the gimple reg used for the bound as non-DECL_IGNORED for the LTO stuff.

Let's go with that, then.

Jason


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-29 19:49               ` Jason Merrill
@ 2015-05-31  7:53                 ` Aldy Hernandez
  2015-05-31 22:14                   ` Jason Merrill
  0 siblings, 1 reply; 34+ messages in thread
From: Aldy Hernandez @ 2015-05-31  7:53 UTC (permalink / raw)
  To: Jason Merrill, Richard Biener, Jan Hubicka; +Cc: gcc-patches

On 05/29/2015 03:33 PM, Jason Merrill wrote:
> On 05/29/2015 03:26 PM, Richard Biener wrote:
>> ISTR I had to mark the gimple reg used for the bound as
>> non-DECL_IGNORED for the LTO stuff.
>
> Let's go with that, then.

Well, I did play around with that option originally, but temporaries do 
not end up in the symbol table, so we won't see them to feed them to 
late_global_decl.

We'd have to save them on the side to make them survive until late and 
then feed them to late_global_decl separately (which I'm sure Richi will 
hate), or we could drill down through the array type/domain to find the 
gimple register (which now has an early DIE) and call late_global_decl 
on it.  However, this last option sounds like a variant of my original 
idea-- fill the bound location later, with the unfortunate side-effect 
of having an additional DIE (the gimple register DIE).

I guess we could iterate through all the gimple registers late that have 
DECL_IGNORED_P == NULL and call late_global_decl on them, but I dislike 
this as well.  Actually, all ideas involving generating DIEs for 
temporaries involve an additional DIE we wouldn't otherwise get.

Can I clean up my original idea instead?

Aldy

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-31  7:53                 ` Aldy Hernandez
@ 2015-05-31 22:14                   ` Jason Merrill
  2015-06-01  8:03                     ` Richard Biener
  0 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2015-05-31 22:14 UTC (permalink / raw)
  To: Aldy Hernandez, Richard Biener, Jan Hubicka; +Cc: gcc-patches

On 05/30/2015 08:52 PM, Aldy Hernandez wrote:
> On 05/29/2015 03:33 PM, Jason Merrill wrote:
>> On 05/29/2015 03:26 PM, Richard Biener wrote:
>>> ISTR I had to mark the gimple reg used for the bound as
>>> non-DECL_IGNORED for the LTO stuff.
>>
>> Let's go with that, then.
>
> Well, I did play around with that option originally, but temporaries do
> not end up in the symbol table, so we won't see them to feed them to
> late_global_decl.

The temporary has function scope, so I don't see why that would be an issue.

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-05-31 22:14                   ` Jason Merrill
@ 2015-06-01  8:03                     ` Richard Biener
  2015-06-01  8:04                       ` Richard Biener
  0 siblings, 1 reply; 34+ messages in thread
From: Richard Biener @ 2015-06-01  8:03 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Aldy Hernandez, Jan Hubicka, gcc-patches

On Sun, May 31, 2015 at 10:38 PM, Jason Merrill <jason@redhat.com> wrote:
> On 05/30/2015 08:52 PM, Aldy Hernandez wrote:
>>
>> On 05/29/2015 03:33 PM, Jason Merrill wrote:
>>>
>>> On 05/29/2015 03:26 PM, Richard Biener wrote:
>>>>
>>>> ISTR I had to mark the gimple reg used for the bound as
>>>> non-DECL_IGNORED for the LTO stuff.
>>>
>>>
>>> Let's go with that, then.
>>
>>
>> Well, I did play around with that option originally, but temporaries do
>> not end up in the symbol table, so we won't see them to feed them to
>> late_global_decl.
>
>
> The temporary has function scope, so I don't see why that would be an issue.

Yeah, we should walk it via the function_decl hook on the containing function.

Richard.

> Jason
>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-06-01  8:03                     ` Richard Biener
@ 2015-06-01  8:04                       ` Richard Biener
  2015-06-01 15:43                         ` Aldy Hernandez
  0 siblings, 1 reply; 34+ messages in thread
From: Richard Biener @ 2015-06-01  8:04 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Aldy Hernandez, Jan Hubicka, gcc-patches

On Mon, Jun 1, 2015 at 10:03 AM, Richard Biener
<richard.guenther@gmail.com> wrote:
> On Sun, May 31, 2015 at 10:38 PM, Jason Merrill <jason@redhat.com> wrote:
>> On 05/30/2015 08:52 PM, Aldy Hernandez wrote:
>>>
>>> On 05/29/2015 03:33 PM, Jason Merrill wrote:
>>>>
>>>> On 05/29/2015 03:26 PM, Richard Biener wrote:
>>>>>
>>>>> ISTR I had to mark the gimple reg used for the bound as
>>>>> non-DECL_IGNORED for the LTO stuff.
>>>>
>>>>
>>>> Let's go with that, then.
>>>
>>>
>>> Well, I did play around with that option originally, but temporaries do
>>> not end up in the symbol table, so we won't see them to feed them to
>>> late_global_decl.
>>
>>
>> The temporary has function scope, so I don't see why that would be an issue.
>
> Yeah, we should walk it via the function_decl hook on the containing function.

Btw, the following was my gimplify.c hunk:

diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index d822913..10a9318 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -8994,6 +8994,12 @@ gimplify_one_sizepos (tree *expr_p, gimple_seq *stmt_p)
   *expr_p = unshare_expr (expr);

   gimplify_expr (expr_p, stmt_p, NULL, is_gimple_val, fb_rvalue);
+
+  /* The possibly generated temporary is interesting for debug information
+     to complete the VLA type sizes and bounds.  Clear DECL_IGNORED_P.  */
+  if (TREE_CODE (*expr_p) == VAR_DECL
+      && DECL_ARTIFICIAL (*expr_p))
+    DECL_IGNORED_P (*expr_p) = false;
 }

 /* Gimplify the body of statements of FNDECL and return a GIMPLE_BIND node


> Richard.
>
>> Jason
>>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-06-01  8:04                       ` Richard Biener
@ 2015-06-01 15:43                         ` Aldy Hernandez
  2015-06-01 17:01                           ` Richard Biener
  0 siblings, 1 reply; 34+ messages in thread
From: Aldy Hernandez @ 2015-06-01 15:43 UTC (permalink / raw)
  To: Richard Biener, Jason Merrill; +Cc: Jan Hubicka, gcc-patches

On 06/01/2015 04:04 AM, Richard Biener wrote:
> On Mon, Jun 1, 2015 at 10:03 AM, Richard Biener
> <richard.guenther@gmail.com> wrote:
>> On Sun, May 31, 2015 at 10:38 PM, Jason Merrill <jason@redhat.com> wrote:
>>> On 05/30/2015 08:52 PM, Aldy Hernandez wrote:
>>>>
>>>> On 05/29/2015 03:33 PM, Jason Merrill wrote:
>>>>>
>>>>> On 05/29/2015 03:26 PM, Richard Biener wrote:
>>>>>>
>>>>>> ISTR I had to mark the gimple reg used for the bound as
>>>>>> non-DECL_IGNORED for the LTO stuff.
>>>>>
>>>>>
>>>>> Let's go with that, then.
>>>>
>>>>
>>>> Well, I did play around with that option originally, but temporaries do
>>>> not end up in the symbol table, so we won't see them to feed them to
>>>> late_global_decl.
>>>
>>>
>>> The temporary has function scope, so I don't see why that would be an issue.
>>
>> Yeah, we should walk it via the function_decl hook on the containing function.
>
> Btw, the following was my gimplify.c hunk:
>
> diff --git a/gcc/gimplify.c b/gcc/gimplify.c
> index d822913..10a9318 100644
> --- a/gcc/gimplify.c
> +++ b/gcc/gimplify.c
> @@ -8994,6 +8994,12 @@ gimplify_one_sizepos (tree *expr_p, gimple_seq *stmt_p)
>     *expr_p = unshare_expr (expr);
>
>     gimplify_expr (expr_p, stmt_p, NULL, is_gimple_val, fb_rvalue);
> +
> +  /* The possibly generated temporary is interesting for debug information
> +     to complete the VLA type sizes and bounds.  Clear DECL_IGNORED_P.  */
> +  if (TREE_CODE (*expr_p) == VAR_DECL
> +      && DECL_ARTIFICIAL (*expr_p))
> +    DECL_IGNORED_P (*expr_p) = false;

We still have the problem that function locals in dwarf2out are seen in 
decls_for_scope by iterating through BLOCK_VARS, and temporaries do not 
live in BLOCK_VARS.

How did they get picked up and annotated in your approach?

Aldy

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-06-01 15:43                         ` Aldy Hernandez
@ 2015-06-01 17:01                           ` Richard Biener
  2015-06-01 17:42                             ` Aldy Hernandez
  0 siblings, 1 reply; 34+ messages in thread
From: Richard Biener @ 2015-06-01 17:01 UTC (permalink / raw)
  To: Aldy Hernandez, Jason Merrill; +Cc: Jan Hubicka, gcc-patches

On June 1, 2015 5:42:57 PM GMT+02:00, Aldy Hernandez <aldyh@redhat.com> wrote:
>On 06/01/2015 04:04 AM, Richard Biener wrote:
>> On Mon, Jun 1, 2015 at 10:03 AM, Richard Biener
>> <richard.guenther@gmail.com> wrote:
>>> On Sun, May 31, 2015 at 10:38 PM, Jason Merrill <jason@redhat.com>
>wrote:
>>>> On 05/30/2015 08:52 PM, Aldy Hernandez wrote:
>>>>>
>>>>> On 05/29/2015 03:33 PM, Jason Merrill wrote:
>>>>>>
>>>>>> On 05/29/2015 03:26 PM, Richard Biener wrote:
>>>>>>>
>>>>>>> ISTR I had to mark the gimple reg used for the bound as
>>>>>>> non-DECL_IGNORED for the LTO stuff.
>>>>>>
>>>>>>
>>>>>> Let's go with that, then.
>>>>>
>>>>>
>>>>> Well, I did play around with that option originally, but
>temporaries do
>>>>> not end up in the symbol table, so we won't see them to feed them
>to
>>>>> late_global_decl.
>>>>
>>>>
>>>> The temporary has function scope, so I don't see why that would be
>an issue.
>>>
>>> Yeah, we should walk it via the function_decl hook on the containing
>function.
>>
>> Btw, the following was my gimplify.c hunk:
>>
>> diff --git a/gcc/gimplify.c b/gcc/gimplify.c
>> index d822913..10a9318 100644
>> --- a/gcc/gimplify.c
>> +++ b/gcc/gimplify.c
>> @@ -8994,6 +8994,12 @@ gimplify_one_sizepos (tree *expr_p, gimple_seq
>*stmt_p)
>>     *expr_p = unshare_expr (expr);
>>
>>     gimplify_expr (expr_p, stmt_p, NULL, is_gimple_val, fb_rvalue);
>> +
>> +  /* The possibly generated temporary is interesting for debug
>information
>> +     to complete the VLA type sizes and bounds.  Clear
>DECL_IGNORED_P.  */
>> +  if (TREE_CODE (*expr_p) == VAR_DECL
>> +      && DECL_ARTIFICIAL (*expr_p))
>> +    DECL_IGNORED_P (*expr_p) = false;
>
>We still have the problem that function locals in dwarf2out are seen in
>
>decls_for_scope by iterating through BLOCK_VARS, and temporaries do not
>
>live in BLOCK_VARS.
>
>How did they get picked up and annotated in your approach?

The size type ones are in BLOCJ_VARS IIRC (or I have to check the last posted patch for other related hunks).

Richard.

>Aldy


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-06-01 17:01                           ` Richard Biener
@ 2015-06-01 17:42                             ` Aldy Hernandez
  2015-06-02  8:13                               ` Richard Biener
  0 siblings, 1 reply; 34+ messages in thread
From: Aldy Hernandez @ 2015-06-01 17:42 UTC (permalink / raw)
  To: Richard Biener, Jason Merrill; +Cc: Jan Hubicka, gcc-patches

On 06/01/2015 01:00 PM, Richard Biener wrote:
> On June 1, 2015 5:42:57 PM GMT+02:00, Aldy Hernandez <aldyh@redhat.com> wrote:
>> On 06/01/2015 04:04 AM, Richard Biener wrote:
>>> On Mon, Jun 1, 2015 at 10:03 AM, Richard Biener

>> We still have the problem that function locals in dwarf2out are seen in
>>
>> decls_for_scope by iterating through BLOCK_VARS, and temporaries do not
>>
>> live in BLOCK_VARS.
>>
>> How did they get picked up and annotated in your approach?
>
> The size type ones are in BLOCJ_VARS IIRC (or I have to check the last posted patch for other related hunks).

Hmmm, it doesn't seem so in my testcase:

$ cat a.c
unsigned int i=555;

int main()
{
   unsigned int array[i];
   __asm__ __volatile__ ("" : : "m" (array));
}

(gdb) print stmt
$108 = <block 0x7ffff02b0420>
(gdb) call debug_generic_stmt(stmt)
BLOCK #0
   SUPERCONTEXT: main
   VARS: array

The temporary has DECL_IGNORED_P appropriately.

It does show up in DECL_STRUCT_FUNCTION()->local_decls, but so do a few 
other temporaries and SSA variables which we're not interested in.

Aldy

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-06-01 17:42                             ` Aldy Hernandez
@ 2015-06-02  8:13                               ` Richard Biener
  2015-06-02 19:25                                 ` Aldy Hernandez
  0 siblings, 1 reply; 34+ messages in thread
From: Richard Biener @ 2015-06-02  8:13 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Jason Merrill, Jan Hubicka, gcc-patches

On Mon, Jun 1, 2015 at 7:42 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
> On 06/01/2015 01:00 PM, Richard Biener wrote:
>>
>> On June 1, 2015 5:42:57 PM GMT+02:00, Aldy Hernandez <aldyh@redhat.com>
>> wrote:
>>>
>>> On 06/01/2015 04:04 AM, Richard Biener wrote:
>>>>
>>>> On Mon, Jun 1, 2015 at 10:03 AM, Richard Biener
>
>
>>> We still have the problem that function locals in dwarf2out are seen in
>>>
>>> decls_for_scope by iterating through BLOCK_VARS, and temporaries do not
>>>
>>> live in BLOCK_VARS.
>>>
>>> How did they get picked up and annotated in your approach?
>>
>>
>> The size type ones are in BLOCJ_VARS IIRC (or I have to check the last
>> posted patch for other related hunks).
>
>
> Hmmm, it doesn't seem so in my testcase:
>
> $ cat a.c
> unsigned int i=555;
>
> int main()
> {
>   unsigned int array[i];
>   __asm__ __volatile__ ("" : : "m" (array));
> }
>
> (gdb) print stmt
> $108 = <block 0x7ffff02b0420>
> (gdb) call debug_generic_stmt(stmt)
> BLOCK #0
>   SUPERCONTEXT: main
>   VARS: array
>
> The temporary has DECL_IGNORED_P appropriately.
>
> It does show up in DECL_STRUCT_FUNCTION()->local_decls, but so do a few
> other temporaries and SSA variables which we're not interested in.

Ok, so I have the following in my LTO debug patch (ignore the first part of the
2nd hunk - just look at the variably_modified_type_p case), which means you
are correct.  The ??? comment in process_vla_type needs fixing of course,
either there or in walk_type_fields (to catch all cases that have gimplified
sizes, see callers of gimplify_one_sizepos/gimplify_type_sizes).

I suppose we can change things this way as a followup (as it needs some work)

@@ -21036,6 +21263,31 @@ gen_block_die (tree stmt, dw_die_ref context_die)
     decls_for_scope (stmt, context_die);
 }

+static tree
+process_vla_type (tree *tp, int *walk_subtrees, void *ctx)
+{
+  /* ???  walk_type_fields doesn't walk TYPE_SIZE and friends and
+     while it walks TYPE_DOMAIN for arrays it doesn't walk
+     TYPE_MIN/MAX_VALUE.  Just special-case the ARRAY_TYPE domain
+     type case here for now.  */
+  if (TREE_CODE (*tp) == INTEGER_TYPE)
+    {
+      if (TREE_CODE (TYPE_MIN_VALUE (*tp)) == VAR_DECL
+         && DECL_ARTIFICIAL (TYPE_MIN_VALUE (*tp))
+         && !DECL_IGNORED_P (TYPE_MIN_VALUE (*tp)))
+       gen_decl_die (TYPE_MIN_VALUE (*tp), NULL_TREE, (dw_die_ref) ctx);
+      if (TREE_CODE (TYPE_MAX_VALUE (*tp)) == VAR_DECL
+         && DECL_ARTIFICIAL (TYPE_MAX_VALUE (*tp))
+         && !DECL_IGNORED_P (TYPE_MAX_VALUE (*tp)))
+       gen_decl_die (TYPE_MAX_VALUE (*tp), NULL_TREE, (dw_die_ref) ctx);
+    }
+
+  if (!TYPE_P (*tp))
+    *walk_subtrees = 0;
+
+  return NULL_TREE;
+}
+
 /* Process variable DECL (or variable with origin ORIGIN) within
    block STMT and add it to CONTEXT_DIE.  */
 static void
@@ -21061,7 +21313,44 @@ process_scope_var (tree stmt, tree decl, tree
origin, dw_die_ref context_die)
                                             stmt, context_die);
     }
   else
-    gen_decl_die (decl, origin, context_die);
+    {
+      if (decl && DECL_P (decl))
+       die = lookup_decl_die (decl);
+
+      if (in_lto_p
+         && die && die->die_parent != context_die)
+       {
+         /* ???  For non-LTO operation we do not want to get here via
+            dwarf2out_abstract_function / set_decl_origin_self which
+            ends up modifying the tree rep in some odd way instead
+            of just playing with the DIEs.  */
+         /* We associate vars with their DECL_CONTEXT first which misses
+            their BLOCK association.  Move them.  */
+         gcc_assert (die->die_parent != NULL);
+         /* ???  Moving is expensive.  Better fix DECL_CONTEXT?  */
+         dw_die_ref prev = die->die_parent->die_child;
+         while (prev->die_sib != die)
+           prev = prev->die_sib;
+         remove_child_with_prev (die, prev);
+         add_child_die (context_die, die);
+       }
+
+      if (in_lto_p
+         && TREE_CODE (decl) == VAR_DECL
+         && variably_modified_type_p (TREE_TYPE (decl), cfun->decl))
+       {
+         /* We need to add location attributes to decls refered to
+            from the decls type but we don't have DIEs for the type
+            itself materialized.  The decls are also not part of the
+            functions BLOCK tree (because they are artificial).  */
+         walk_tree (&TREE_TYPE (decl), process_vla_type, NULL, NULL);
+       }
+
+      /* ???  The following gets stray type DIEs created even for decls
+        that were created early.  */
+
+      gen_decl_die (decl, origin, context_die);
+    }
 }

 /* Generate all of the decls declared within a given scope and (recursively)


> Aldy

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch 10/10] debug-early merge: compiler proper
  2015-06-02  8:13                               ` Richard Biener
@ 2015-06-02 19:25                                 ` Aldy Hernandez
  0 siblings, 0 replies; 34+ messages in thread
From: Aldy Hernandez @ 2015-06-02 19:25 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jason Merrill, Jan Hubicka, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 521 bytes --]

On 06/02/2015 04:11 AM, Richard Biener wrote:

> I suppose we can change things this way as a followup (as it needs some work)

Ok.

I cleaned things up using variably_modified_type_p() as you did, instead 
of the INTEGER_CST nonsense.  Attached are the latest dwarf2out.c 
changes against mainline.

Jason are you ok with the attached wrt VLAs?  If so, I'm putting this 
aside while I work on DECL_ABSTRACT and friends, and hopefully wrap 
things up.

Tested on x86-64 Linux, gcc and gdb testsuites.

Thanks guys.

Aldy

[-- Attachment #2: dearly-dwarf2out.patch --]
[-- Type: text/x-patch, Size: 63873 bytes --]

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 15c545e..62b06c4 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -1268,16 +1268,6 @@ struct GTY((for_user)) dwarf_file_data {
   int emitted_number;
 };
 
-typedef struct GTY(()) deferred_locations_struct
-{
-  tree variable;
-  dw_die_ref die;
-} deferred_locations;
-
-
-static GTY(()) vec<deferred_locations, va_gc> *deferred_locations_list;
-
-
 /* Describe an entry into the .debug_addr section.  */
 
 enum ate_kind {
@@ -2448,6 +2438,7 @@ build_cfa_aligned_loc (dw_cfa_location *cfa,
 
 static void dwarf2out_init (const char *);
 static void dwarf2out_finish (const char *);
+static void dwarf2out_early_finish (void);
 static void dwarf2out_assembly_start (void);
 static void dwarf2out_define (unsigned int, const char *);
 static void dwarf2out_undef (unsigned int, const char *);
@@ -2457,7 +2448,8 @@ static void dwarf2out_function_decl (tree);
 static void dwarf2out_begin_block (unsigned, unsigned);
 static void dwarf2out_end_block (unsigned, unsigned);
 static bool dwarf2out_ignore_block (const_tree);
-static void dwarf2out_global_decl (tree);
+static void dwarf2out_early_global_decl (tree);
+static void dwarf2out_late_global_decl (tree);
 static void dwarf2out_type_decl (tree, int);
 static void dwarf2out_imported_module_or_decl (tree, tree, tree, bool);
 static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree,
@@ -2474,6 +2466,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
 {
   dwarf2out_init,
   dwarf2out_finish,
+  dwarf2out_early_finish,
   dwarf2out_assembly_start,
   dwarf2out_define,
   dwarf2out_undef,
@@ -2495,7 +2488,8 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   dwarf2out_begin_function,
   dwarf2out_end_function,	/* end_function */
   dwarf2out_function_decl,	/* function_decl */
-  dwarf2out_global_decl,
+  dwarf2out_early_global_decl,
+  dwarf2out_late_global_decl,
   dwarf2out_type_decl,		/* type_decl */
   dwarf2out_imported_module_or_decl,
   debug_nothing_tree,		/* deferred_inline_function */
@@ -2636,10 +2630,20 @@ typedef struct GTY((chain_circular ("%h.die_sib"), for_user)) die_struct {
   /* Die is used and must not be pruned as unused.  */
   BOOL_BITFIELD die_perennial_p : 1;
   BOOL_BITFIELD comdat_type_p : 1; /* DIE has a type signature */
+  /* Die was generated early via dwarf2out_early_global_decl.  */
+  BOOL_BITFIELD dumped_early : 1;
   /* Lots of spare bits.  */
 }
 die_node;
 
+/* Set to TRUE while dwarf2out_early_global_decl is running.  */
+static bool early_dwarf;
+struct set_early_dwarf {
+  bool saved;
+  set_early_dwarf () : saved(early_dwarf) { early_dwarf = true; }
+  ~set_early_dwarf () { early_dwarf = saved; }
+};
+
 /* Evaluate 'expr' while 'c' is set to each child of DIE in order.  */
 #define FOR_EACH_CHILD(die, c, expr) do {	\
   c = die->die_child;				\
@@ -2690,9 +2694,13 @@ typedef struct GTY(()) comdat_type_struct
 }
 comdat_type_node;
 
-/* The limbo die list structure.  */
+/* A list of DIEs for which we can't determine ancestry (parent_die
+   field) just yet.  Later in dwarf2out_finish we will fill in the
+   missing bits.  */
 typedef struct GTY(()) limbo_die_struct {
   dw_die_ref die;
+  /* The tree for which this DIE was created for.  We use this to
+     determine ancestry later.  */
   tree created_for;
   struct limbo_die_struct *next;
 }
@@ -2939,7 +2947,7 @@ static GTY((length ("abbrev_die_table_allocated")))
 /* Number of elements currently allocated for abbrev_die_table.  */
 static GTY(()) unsigned abbrev_die_table_allocated;
 
-/* Number of elements in type_die_table currently in use.  */
+/* Number of elements in abbrev_die_table currently in use.  */
 static GTY(()) unsigned abbrev_die_table_in_use;
 
 /* Size (in elements) of increments by which we may expand the
@@ -3021,9 +3029,6 @@ static GTY(()) struct dwarf_file_data * last_emitted_file;
 /* Number of internal labels generated by gen_internal_sym().  */
 static GTY(()) int label_num;
 
-/* Cached result of previous call to lookup_filename.  */
-static GTY(()) struct dwarf_file_data * file_table_last_lookup;
-
 static GTY(()) vec<die_arg_entry, va_gc> *tmpl_value_parm_die_table;
 
 /* Instances of generic types for which we need to generate debug
@@ -3108,7 +3113,7 @@ static inline dw_die_ref get_AT_ref (dw_die_ref, enum dwarf_attribute);
 static bool is_cxx (void);
 static bool is_fortran (void);
 static bool is_ada (void);
-static void remove_AT (dw_die_ref, enum dwarf_attribute);
+static bool remove_AT (dw_die_ref, enum dwarf_attribute);
 static void remove_child_TAG (dw_die_ref, enum dwarf_tag);
 static void add_child_die (dw_die_ref, dw_die_ref);
 static dw_die_ref new_die (enum dwarf_tag, dw_die_ref, tree);
@@ -4748,16 +4753,17 @@ is_ada (void)
   return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83;
 }
 
-/* Remove the specified attribute if present.  */
+/* Remove the specified attribute if present.  Return TRUE if removal
+   was successful.  */
 
-static void
+static bool
 remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
 {
   dw_attr_ref a;
   unsigned ix;
 
   if (! die)
-    return;
+    return false;
 
   FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
     if (a->dw_attr == attr_kind)
@@ -4769,8 +4775,9 @@ remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
 	/* vec::ordered_remove should help reduce the number of abbrevs
 	   that are needed.  */
 	die->die_attr->ordered_remove (ix);
-	return;
+	return true;
       }
+  return false;
 }
 
 /* Remove CHILD from its parent.  PREV must have the property that
@@ -4844,6 +4851,7 @@ remove_child_TAG (dw_die_ref die, enum dwarf_tag tag)
     while (c->die_tag == tag)
       {
 	remove_child_with_prev (c, prev);
+	c->die_parent = NULL;
 	/* Might have removed every child.  */
 	if (c == c->die_sib)
 	  return;
@@ -4873,6 +4881,21 @@ add_child_die (dw_die_ref die, dw_die_ref child_die)
   die->die_child = child_die;
 }
 
+/* Unassociate CHILD from its parent, and make its parent be
+   NEW_PARENT.  */
+
+static void
+reparent_child (dw_die_ref child, dw_die_ref new_parent)
+{
+  for (dw_die_ref p = child->die_parent->die_child; ; p = p->die_sib)
+    if (p->die_sib == child)
+      {
+	remove_child_with_prev (child, p);
+	break;
+      }
+  add_child_die (new_parent, child);
+}
+
 /* Move CHILD, which must be a child of PARENT or the DIE for which PARENT
    is the specification, to the end of PARENT's list of children.
    This is done by removing and re-adding it.  */
@@ -4880,8 +4903,6 @@ add_child_die (dw_die_ref die, dw_die_ref child_die)
 static void
 splice_child_die (dw_die_ref parent, dw_die_ref child)
 {
-  dw_die_ref p;
-
   /* We want the declaration DIE from inside the class, not the
      specification DIE at toplevel.  */
   if (child->die_parent != parent)
@@ -4896,17 +4917,13 @@ splice_child_die (dw_die_ref parent, dw_die_ref child)
 	      || (child->die_parent
 		  == get_AT_ref (parent, DW_AT_specification)));
 
-  for (p = child->die_parent->die_child; ; p = p->die_sib)
-    if (p->die_sib == child)
-      {
-	remove_child_with_prev (child, p);
-	break;
-      }
-
-  add_child_die (parent, child);
+  reparent_child (child, parent);
 }
 
-/* Return a pointer to a newly created DIE node.  */
+/* Create and return a new die with a parent of PARENT_DIE.  If
+   PARENT_DIE is NULL, the new DIE is placed in limbo and an
+   associated tree T must be supplied to determine parenthood
+   later.  */
 
 static inline dw_die_ref
 new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
@@ -4915,12 +4932,44 @@ new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
 
   die->die_tag = tag_value;
 
+  if (early_dwarf)
+    die->dumped_early = true;
+
   if (parent_die != NULL)
     add_child_die (parent_die, die);
   else
     {
       limbo_die_node *limbo_node;
 
+      /* No DIEs created after early dwarf should end up in limbo,
+	 because the limbo list should not persist past LTO
+	 streaming.  */
+      if (tag_value != DW_TAG_compile_unit
+	  /* These are allowed because they're generated while
+	     breaking out COMDAT units late.  */
+	  && tag_value != DW_TAG_type_unit
+	  && !early_dwarf
+	  /* Allow nested functions to live in limbo because they will
+	     only temporarily live there, as decls_for_scope will fix
+	     them up.  */
+	  && (TREE_CODE (t) != FUNCTION_DECL
+	      || !decl_function_context (t))
+	  /* Same as nested functions above but for types.  Types that
+	     are local to a function will be fixed in
+	     decls_for_scope.  */
+	  && (!RECORD_OR_UNION_TYPE_P (t)
+	      || !TYPE_CONTEXT (t)
+	      || TREE_CODE (TYPE_CONTEXT (t)) != FUNCTION_DECL)
+	  /* FIXME debug-early: Allow late limbo DIE creation for LTO,
+	     especially in the ltrans stage, but once we implement LTO
+	     dwarf streaming, we should remove this exception.  */
+	  && !in_lto_p)
+	{
+	  fprintf (stderr, "symbol ended up in limbo too late:");
+	  debug_generic_stmt (t);
+	  gcc_unreachable ();
+	}
+
       limbo_node = ggc_cleared_alloc<limbo_die_node> ();
       limbo_node->die = die;
       limbo_node->created_for = t;
@@ -5576,9 +5625,18 @@ print_die (dw_die_ref die, FILE *outfile)
   unsigned ix;
 
   print_spaces (outfile);
-  fprintf (outfile, "DIE %4ld: %s (%p)\n",
+  fprintf (outfile, "DIE %4ld: %s (%p)",
 	   die->die_offset, dwarf_tag_name (die->die_tag),
 	   (void*) die);
+  if (die->dumped_early)
+    {
+      fprintf (outfile, " (DUMPED EARLY");
+      const char *name = get_AT_string (die, DW_AT_name);
+      if (name)
+	fprintf (outfile, ": %s", name);
+      fputc (')', outfile);
+    }
+  fputc ('\n', outfile);
   print_spaces (outfile);
   fprintf (outfile, "  abbrev id: %lu", die->die_abbrev);
   fprintf (outfile, " offset: %ld", die->die_offset);
@@ -5652,6 +5710,34 @@ debug_dwarf (void)
   print_indent = 0;
   print_die (comp_unit_die (), stderr);
 }
+
+/* Sanity checks on DIEs.  */
+
+static void
+check_die (dw_die_ref die)
+{
+  /* A debugging information entry that is a member of an abstract
+     instance tree [that has DW_AT_inline] should not contain any
+     attributes which describe aspects of the subroutine which vary
+     between distinct inlined expansions or distinct out-of-line
+     expansions.  */
+  unsigned ix;
+  dw_attr_ref a;
+  bool inline_found = false;
+  FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+    if (a->dw_attr == DW_AT_inline && a->dw_attr_val.v.val_unsigned)
+      inline_found = true;
+  if (inline_found)
+    {
+      /* Catch the most common mistakes.  */
+      FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+	gcc_assert (a->dw_attr != DW_AT_low_pc
+		    && a->dw_attr != DW_AT_high_pc
+		    && a->dw_attr != DW_AT_location
+		    && a->dw_attr != DW_AT_frame_base
+		    && a->dw_attr != DW_AT_GNU_all_call_sites);
+    }
+}
 \f
 /* Start a new compilation unit DIE for an include file.  OLD_UNIT is the CU
    for the enclosing include file, if any.  BINCL_DIE is the DW_TAG_GNU_BINCL
@@ -8799,9 +8885,10 @@ output_die (dw_die_ref die)
   if (! die->comdat_type_p && die->die_id.die_symbol)
     output_die_symbol (die);
 
-  dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)",
+  dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)%s",
 			       (unsigned long)die->die_offset,
-			       dwarf_tag_name (die->die_tag));
+			       dwarf_tag_name (die->die_tag),
+			       die->dumped_early ? " (early)" : "");
 
   FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
     {
@@ -16106,17 +16193,6 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, bool cache_p,
   return tree_add_const_value_attribute_for_decl (die, decl);
 }
 
-/* Add VARIABLE and DIE into deferred locations list.  */
-
-static void
-defer_location (tree variable, dw_die_ref die)
-{
-  deferred_locations entry;
-  entry.variable = variable;
-  entry.die = die;
-  vec_safe_push (deferred_locations_list, entry);
-}
-
 /* Helper function for tree_add_const_value_attribute.  Natively encode
    initializer INIT into an array.  Return true if successful.  */
 
@@ -16798,14 +16874,17 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr,
 /* Add subscript info to TYPE_DIE, describing an array TYPE, collapsing
    possibly nested array subscripts in a flat sequence if COLLAPSE_P is true.
    Note that the block of subscript information for an array type also
-   includes information about the element type of the given array type.  */
+   includes information about the element type of the given array type.
+
+   This function reuses previously set type and bound information if
+   available.  */
 
 static void
 add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
 {
   unsigned dimension_number;
   tree lower, upper;
-  dw_die_ref subrange_die;
+  dw_die_ref child = type_die->die_child;
 
   for (dimension_number = 0;
        TREE_CODE (type) == ARRAY_TYPE && (dimension_number == 0 || collapse_p);
@@ -16819,7 +16898,37 @@ add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
       /* Arrays come in three flavors: Unspecified bounds, fixed bounds,
 	 and (in GNU C only) variable bounds.  Handle all three forms
 	 here.  */
-      subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
+
+      /* Find and reuse a previously generated DW_TAG_subrange_type if
+	 available.
+
+         For multi-dimensional arrays, as we iterate through the
+         various dimensions in the enclosing for loop above, we also
+         iterate through the DIE children and pick at each
+         DW_TAG_subrange_type previously generated (if available).
+         Each child DW_TAG_subrange_type DIE describes the range of
+         the current dimension.  At this point we should have as many
+         DW_TAG_subrange_type's as we have dimensions in the
+         array.  */
+      dw_die_ref subrange_die = NULL;
+      if (child)
+	while (1)
+	  {
+	    child = child->die_sib;
+	    if (child->die_tag == DW_TAG_subrange_type)
+	      subrange_die = child;
+	    if (child == type_die->die_child)
+	      {
+		/* If we wrapped around, stop looking next time.  */
+		child = NULL;
+		break;
+	      }
+	    if (child->die_tag == DW_TAG_subrange_type)
+	      break;
+	  }
+      if (!subrange_die)
+	subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
+
       if (domain)
 	{
 	  /* We have an array type with specified bounds.  */
@@ -16827,7 +16936,8 @@ add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
 	  upper = TYPE_MAX_VALUE (domain);
 
 	  /* Define the index type.  */
-	  if (TREE_TYPE (domain))
+	  if (TREE_TYPE (domain)
+	      && !get_AT (subrange_die, DW_AT_type))
 	    {
 	      /* ??? This is probably an Ada unnamed subrange type.  Ignore the
 		 TREE_TYPE field.  We can't emit debug info for this
@@ -16849,8 +16959,9 @@ add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
 	     to produce useful results, go ahead and output the lower
 	     bound solo, and hope the debugger can cope.  */
 
-	  add_bound_info (subrange_die, DW_AT_lower_bound, lower, NULL);
-	  if (upper)
+	  if (!get_AT (subrange_die, DW_AT_lower_bound))
+	    add_bound_info (subrange_die, DW_AT_lower_bound, lower, NULL);
+	  if (upper && !get_AT (subrange_die, DW_AT_upper_bound))
 	    add_bound_info (subrange_die, DW_AT_upper_bound, upper, NULL);
 	}
 
@@ -17477,6 +17588,25 @@ decl_start_label (tree decl)
 }
 #endif
 \f
+/* For variable-length arrays that have been previously generated, but
+   may be incomplete due to missing subscript info, fill the subscript
+   info.  Return TRUE if this is one of those cases.  */
+static bool
+fill_variable_array_bounds (tree type)
+{
+  if (TREE_ASM_WRITTEN (type)
+      && TREE_CODE (type) == ARRAY_TYPE
+      && variably_modified_type_p (type, NULL))
+    {
+      dw_die_ref array_die = lookup_type_die (type);
+      if (!array_die)
+	return false;
+      add_subscript_info (array_die, type, !is_ada ());
+      return true;
+    }
+  return false;
+}
+
 /* These routines generate the internal representation of the DIE's for
    the compilation unit.  Debugging information is collected by walking
    the declaration trees passed in from dwarf2out_decl().  */
@@ -17484,7 +17614,6 @@ decl_start_label (tree decl)
 static void
 gen_array_type_die (tree type, dw_die_ref context_die)
 {
-  dw_die_ref scope_die = scope_die_for (type, context_die);
   dw_die_ref array_die;
 
   /* GNU compilers represent multidimensional array types as sequences of one
@@ -17498,6 +17627,11 @@ gen_array_type_die (tree type, dw_die_ref context_die)
      flexibilty wrt arrays of variable size.  */
 
   bool collapse_nested_arrays = !is_ada ();
+
+  if (fill_variable_array_bounds (type))
+    return;
+
+  dw_die_ref scope_die = scope_die_for (type, context_die);
   tree element_type;
 
   /* Emit DW_TAG_string_type for Fortran character types (with kind 1 only, as
@@ -17853,8 +17987,64 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
 {
   tree node_or_origin = node ? node : origin;
   tree ultimate_origin;
-  dw_die_ref parm_die
-    = new_die (DW_TAG_formal_parameter, context_die, node);
+  dw_die_ref parm_die = NULL;
+  
+  if (TREE_CODE_CLASS (TREE_CODE (node_or_origin)) == tcc_declaration)
+    {
+      parm_die = lookup_decl_die (node);
+
+      /* If the contexts differ, we may not be talking about the same
+	 thing.  */
+      if (parm_die && parm_die->die_parent != context_die)
+	{
+	  if (!DECL_ABSTRACT_P (node))
+	    {
+	      /* This can happen when creating an inlined instance, in
+		 which case we need to create a new DIE that will get
+		 annotated with DW_AT_abstract_origin.  */
+	      parm_die = NULL;
+	    }
+	  else
+	    {
+	      /* Reuse DIE even with a differing context.
+
+		 This happens when called through
+		 dwarf2out_abstract_function for formal parameter
+		 packs.  */
+	      gcc_assert (parm_die->die_parent->die_tag
+			  == DW_TAG_GNU_formal_parameter_pack);
+	    }
+	}
+
+      if (parm_die && parm_die->die_parent == NULL)
+	{
+	  /* Check that parm_die already has the right attributes that
+	     we would have added below.  If any attributes are
+	     missing, fall through to add them.  */
+	  if (! DECL_ABSTRACT_P (node_or_origin)
+	      && !get_AT (parm_die, DW_AT_location)
+	      && !get_AT (parm_die, DW_AT_const_value))
+	    /* We are missing  location info, and are about to add it.  */
+	    ;
+	  else
+	    {
+	      add_child_die (context_die, parm_die);
+	      return parm_die;
+	    }
+	}
+    }
+
+  /* If we have a previously generated DIE, use it, unless this is an
+     concrete instance (origin != NULL), in which case we need a new
+     DIE with a corresponding DW_AT_abstract_origin.  */
+  bool reusing_die;
+  if (parm_die && origin == NULL)
+    reusing_die = true;
+  else
+    {
+      parm_die = new_die (DW_TAG_formal_parameter, context_die, node);
+      reusing_die = false;
+    }
 
   switch (TREE_CODE_CLASS (TREE_CODE (node_or_origin)))
     {
@@ -17862,6 +18052,10 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
       ultimate_origin = decl_ultimate_origin (node_or_origin);
       if (node || ultimate_origin)
 	origin = ultimate_origin;
+
+      if (reusing_die)
+	goto add_location;
+
       if (origin != NULL)
 	add_abstract_origin_attribute (parm_die, origin);
       else if (emit_name_p)
@@ -17881,6 +18075,7 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
 				decl_quals (node_or_origin),
 				context_die);
 	}
+    add_location:
       if (origin == NULL && DECL_ARTIFICIAL (node))
 	add_AT_flag (parm_die, DW_AT_artificial, 1);
 
@@ -18394,26 +18589,94 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 {
   tree origin = decl_ultimate_origin (decl);
   dw_die_ref subr_die;
-  tree outer_scope;
   dw_die_ref old_die = lookup_decl_die (decl);
+
+  /* This function gets called multiple times for different stages of
+     the debug process.  For example, for func() in this code:
+
+	namespace S
+	{
+	  void func() { ... }
+	}
+
+     ...we get called 4 times.  Twice in early debug and twice in
+     late debug:
+
+     Early debug
+     -----------
+
+       1. Once while generating func() within the namespace.  This is
+          the declaration.  The declaration bit below is set, as the
+          context is the namespace.
+
+	  A new DIE will be generated with DW_AT_declaration set.
+
+       2. Once for func() itself.  This is the specification.  The
+          declaration bit below is clear as the context is the CU.
+
+	  We will use the cached DIE from (1) to create a new DIE with
+	  DW_AT_specification pointing to the declaration in (1).
+
+     Late debug via rest_of_handle_final()
+     -------------------------------------
+
+       3. Once generating func() within the namespace.  This is also the
+          declaration, as in (1), but this time we will early exit below
+          as we have a cached DIE and a declaration needs no additional
+          annotations (no locations), as the source declaration line
+          info is enough.
+
+       4. Once for func() itself.  As in (2), this is the specification,
+          but this time we will re-use the cached DIE, and just annotate
+          it with the location information that should now be available.
+
+     For something without namespaces, but with abstract instances, we
+     are also called a multiple times:
+
+        class Base
+	{
+	public:
+	  Base ();	  // constructor declaration (1)
+	};
+
+	Base::Base () { } // constructor specification (2)
+
+    Early debug
+    -----------
+
+       1. Once for the Base() constructor by virtue of it being a
+          member of the Base class.  This is done via
+          rest_of_type_compilation.
+
+	  This is a declaration, so a new DIE will be created with
+	  DW_AT_declaration.
+
+       2. Once for the Base() constructor definition, but this time
+          while generating the abstract instance of the base
+          constructor (__base_ctor) which is being generated via early
+          debug of reachable functions.
+
+	  Even though we have a cached version of the declaration (1),
+	  we will create a DW_AT_specification of the declaration DIE
+	  in (1).
+
+       3. Once for the __base_ctor itself, but this time, we generate
+          an DW_AT_abstract_origin version of the DW_AT_specification in
+	  (2).
+
+    Late debug via rest_of_handle_final
+    -----------------------------------
+
+       4. One final time for the __base_ctor (which will have a cached
+          DIE with DW_AT_abstract_origin created in (3).  This time,
+          we will just annotate the location information now
+          available.
+  */
   int declaration = (current_function_decl != decl
 		     || class_or_namespace_scope_p (context_die));
 
   premark_used_types (DECL_STRUCT_FUNCTION (decl));
 
-  /* It is possible to have both DECL_ABSTRACT_P and DECLARATION be true if we
-     started to generate the abstract instance of an inline, decided to output
-     its containing class, and proceeded to emit the declaration of the inline
-     from the member list for the class.  If so, DECLARATION takes priority;
-     we'll get back to the abstract instance when done with the class.  */
-
-  /* The class-scope declaration DIE must be the primary DIE.  */
-  if (origin && declaration && class_or_namespace_scope_p (context_die))
-    {
-      origin = NULL;
-      gcc_assert (!old_die);
-    }
-
   /* Now that the C++ front end lazily declares artificial member fns, we
      might need to retrofit the declaration into its class.  */
   if (!declaration && !origin && !old_die
@@ -18422,6 +18685,8 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       && debug_info_level > DINFO_LEVEL_TERSE)
     old_die = force_decl_die (decl);
 
+  bool dumped_early = false;
+  /* An inlined instance, tag a new DIE with DW_AT_abstract_origin.  */
   if (origin != NULL)
     {
       gcc_assert (!declaration || local_scope_p (context_die));
@@ -18431,19 +18696,34 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       if (old_die && old_die->die_parent == NULL)
 	add_child_die (context_die, old_die);
 
-      subr_die = new_die (DW_TAG_subprogram, context_die, decl);
-      add_abstract_origin_attribute (subr_die, origin);
-      /*  This is where the actual code for a cloned function is.
-	  Let's emit linkage name attribute for it.  This helps
-	  debuggers to e.g, set breakpoints into
-	  constructors/destructors when the user asks "break
-	  K::K".  */
-      add_linkage_name (subr_die, decl);
+      if (old_die && get_AT_ref (old_die, DW_AT_abstract_origin))
+	{
+	  /* If we have a DW_AT_abstract_origin we have a working
+	     cached version.  */
+	  subr_die = old_die;
+	}
+      else
+	{
+	  subr_die = new_die (DW_TAG_subprogram, context_die, decl);
+	  add_abstract_origin_attribute (subr_die, origin);
+	  /*  This is where the actual code for a cloned function is.
+	      Let's emit linkage name attribute for it.  This helps
+	      debuggers to e.g, set breakpoints into
+	      constructors/destructors when the user asks "break
+	      K::K".  */
+	  add_linkage_name (subr_die, decl);
+	}
     }
+  /* A cached copy, possibly from early dwarf generation.  Reuse as
+     much as possible.  */
   else if (old_die)
     {
-      expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
-      struct dwarf_file_data * file_index = lookup_filename (s.file);
+      /* A declaration that has been previously dumped needs no
+	 additional information.  */
+      if (declaration)
+	return;
+
+      dumped_early = old_die->dumped_early;
 
       if (!get_AT_flag (old_die, DW_AT_declaration)
 	  /* We can have a normal definition following an inline one in the
@@ -18453,7 +18733,13 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	{
 	  /* Detect and ignore this case, where we are trying to output
 	     something we have already output.  */
-	  return;
+	  if (get_AT (old_die, DW_AT_low_pc)
+	      || get_AT (old_die, DW_AT_ranges))
+	    return;
+
+	  /* If we have no location information, this must be a
+	     partially generated DIE from early dwarf generation.
+	     Fall through and generate it.  */
 	}
 
       /* If the definition comes from the same place as the declaration,
@@ -18463,23 +18749,43 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	 instances of inlines, since the spec requires the out-of-line copy
 	 to have the same parent.  For local class methods, this doesn't
 	 apply; we just use the old DIE.  */
-      if ((is_cu_die (old_die->die_parent) || context_die == NULL)
-	  && (DECL_ARTIFICIAL (decl)
-	      || (get_AT_file (old_die, DW_AT_decl_file) == file_index
-		  && (get_AT_unsigned (old_die, DW_AT_decl_line)
-		      == (unsigned) s.line))))
+      expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
+      struct dwarf_file_data * file_index = lookup_filename (s.file);
+      if ((is_cu_die (old_die->die_parent)
+	   /* This condition fixes the inconsistency/ICE with the
+	      following Fortran test (or some derivative thereof) while
+	      building libgfortran:
+
+		 module some_m
+		 contains
+		    logical function funky (FLAG)
+		      funky = .true.
+		   end function
+		 end module
+	   */
+	   || old_die->die_parent->die_tag == DW_TAG_module
+	   || context_die == NULL)
+	   && (DECL_ARTIFICIAL (decl)
+	       || (get_AT_file (old_die, DW_AT_decl_file) == file_index
+		   && (get_AT_unsigned (old_die, DW_AT_decl_line)
+		       == (unsigned) s.line))))
 	{
 	  subr_die = old_die;
 
-	  /* Clear out the declaration attribute and the formal parameters.
-	     Do not remove all children, because it is possible that this
-	     declaration die was forced using force_decl_die(). In such
-	     cases die that forced declaration die (e.g. TAG_imported_module)
-	     is one of the children that we do not want to remove.  */
-	  remove_AT (subr_die, DW_AT_declaration);
-	  remove_AT (subr_die, DW_AT_object_pointer);
-	  remove_child_TAG (subr_die, DW_TAG_formal_parameter);
+	  /* Clear out the declaration attribute, but leave the
+	     parameters so they can be augmented with location
+	     information later.  Unless this was a declaration, in
+	     which case, wipe out the nameless parameters and recreate
+	     them further down.  */
+	  if (remove_AT (subr_die, DW_AT_declaration))
+	    {
+
+	      remove_AT (subr_die, DW_AT_object_pointer);
+	      remove_child_TAG (subr_die, DW_TAG_formal_parameter);
+	    }
 	}
+      /* Make a specification pointing to the previously built
+	 declaration.  */
       else
 	{
 	  subr_die = new_die (DW_TAG_subprogram, context_die, decl);
@@ -18501,6 +18807,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	    }
 	}
     }
+  /* Create a fresh DIE for anything else.  */
   else
     {
       subr_die = new_die (DW_TAG_subprogram, context_die, decl);
@@ -18527,6 +18834,11 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       add_accessibility_attribute (subr_die, decl);
     }
 
+  /* Unless we have an existing non-declaration DIE, equate the new
+     DIE.  */
+  if (!old_die || is_declaration_die (old_die))
+    equate_decl_number_to_die (decl, subr_die);
+
   if (declaration)
     {
       if (!old_die || !get_AT (old_die, DW_AT_inline))
@@ -18544,17 +18856,9 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	  if (lang_hooks.decls.function_decl_deleted_p (decl)
 	      && (! dwarf_strict))
 	    add_AT_flag (subr_die, DW_AT_GNU_deleted, 1);
-
-	  /* The first time we see a member function, it is in the context of
-	     the class to which it belongs.  We make sure of this by emitting
-	     the class first.  The next time is the definition, which is
-	     handled above.  The two may come from the same source text.
-
-	     Note that force_decl_die() forces function declaration die. It is
-	     later reused to represent definition.  */
-	  equate_decl_number_to_die (decl, subr_die);
 	}
     }
+  /* Tag abstract instances with DW_AT_inline.  */
   else if (DECL_ABSTRACT_P (decl))
     {
       if (DECL_DECLARED_INLINE_P (decl))
@@ -18575,18 +18879,15 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       if (DECL_DECLARED_INLINE_P (decl)
 	  && lookup_attribute ("artificial", DECL_ATTRIBUTES (decl)))
 	add_AT_flag (subr_die, DW_AT_artificial, 1);
-
-      equate_decl_number_to_die (decl, subr_die);
     }
-  else if (!DECL_EXTERNAL (decl))
+  /* For non DECL_EXTERNALs, if range information is available, fill
+     the DIE with it.  */
+  else if (!DECL_EXTERNAL (decl) && !early_dwarf)
     {
       HOST_WIDE_INT cfa_fb_offset;
-      struct function *fun = DECL_STRUCT_FUNCTION (decl);
 
-      if (!old_die || !get_AT (old_die, DW_AT_inline))
-	equate_decl_number_to_die (decl, subr_die);
+      struct function *fun = DECL_STRUCT_FUNCTION (decl);
 
-      gcc_checking_assert (fun);
       if (!flag_reorder_blocks_and_partition)
 	{
 	  dw_fde_ref fde = fun->fde;
@@ -18740,12 +19041,13 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       compute_frame_pointer_to_fb_displacement (cfa_fb_offset);
 
       if (fun->static_chain_decl)
-	add_AT_location_description (subr_die, DW_AT_static_link,
-		 loc_list_from_tree (fun->static_chain_decl, 2, NULL));
+	add_AT_location_description
+	  (subr_die, DW_AT_static_link,
+	   loc_list_from_tree (fun->static_chain_decl, 2, NULL));
     }
 
   /* Generate child dies for template paramaters.  */
-  if (debug_info_level > DINFO_LEVEL_TERSE)
+  if (early_dwarf && debug_info_level > DINFO_LEVEL_TERSE)
     gen_generic_params_dies (decl);
 
   /* Now output descriptions of the arguments for this function. This gets
@@ -18764,12 +19066,17 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
   if (debug_info_level <= DINFO_LEVEL_TERSE)
     ;
   else if (declaration)
-    gen_formal_types_die (decl, subr_die);
+    {
+      /* Only generate a prototype's parameters once.  */
+      if (!dumped_early)
+	gen_formal_types_die (decl, subr_die);
+    }
   else
     {
       /* Generate DIEs to represent all known formal parameters.  */
       tree parm = DECL_ARGUMENTS (decl);
-      tree generic_decl = lang_hooks.decls.get_generic_function_decl (decl);
+      tree generic_decl = early_dwarf
+	? lang_hooks.decls.get_generic_function_decl (decl) : NULL;
       tree generic_decl_parm = generic_decl
 				? DECL_ARGUMENTS (generic_decl)
 				: NULL;
@@ -18834,11 +19141,14 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	gen_unspecified_parameters_die (decl, subr_die);
     }
 
+  if (subr_die != old_die)
+    /* Add the calling convention attribute if requested.  */
+    add_calling_convention_attribute (subr_die, decl);
+
   /* Output Dwarf info for all of the stuff within the body of the function
-     (if it has one - it may be just a declaration).  */
-  outer_scope = DECL_INITIAL (decl);
+     (if it has one - it may be just a declaration).
 
-  /* OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent
+     OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent
      a function.  This BLOCK actually represents the outermost binding contour
      for the function, i.e. the contour in which the function's formal
      parameters and labels get declared. Curiously, it appears that the front
@@ -18852,6 +19162,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
      a BLOCK node representing the function's outermost pair of curly braces,
      and any blocks used for the base and member initializers of a C++
      constructor function.  */
+  tree outer_scope = DECL_INITIAL (decl);
   if (! declaration && outer_scope && TREE_CODE (outer_scope) != ERROR_MARK)
     {
       int call_site_note_count = 0;
@@ -18861,6 +19172,9 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       if (DECL_NAME (DECL_RESULT (decl)))
 	gen_decl_die (DECL_RESULT (decl), NULL, subr_die);
 
+      /* The first time through decls_for_scope we will generate the
+	 DIEs for the locals.  The second time, we fill in the
+	 location info.  */
       decls_for_scope (outer_scope, subr_die);
 
       if (call_arg_locations && !dwarf_strict)
@@ -19012,10 +19326,6 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       call_site_count = -1;
       tail_call_site_count = -1;
     }
-
-  if (subr_die != old_die)
-    /* Add the calling convention attribute if requested.  */
-    add_calling_convention_attribute (subr_die, decl);
 }
 
 /* Returns a hash value for X (which really is a die_struct).  */
@@ -19035,6 +19345,33 @@ block_die_hasher::equal (die_struct *x, die_struct *y)
   return x->decl_id == y->decl_id && x->die_parent == y->die_parent;
 }
 
+/* Return TRUE if DECL, which may have been previously generated as
+   OLD_DIE, is a candidate for a DW_AT_specification.  DECLARATION is
+   true if decl (or its origin) is either an extern declaration or a
+   class/namespace scoped declaration.
+
+   The declare_in_namespace support causes us to get two DIEs for one
+   variable, both of which are declarations.  We want to avoid
+   considering one to be a specification, so we must test for
+   DECLARATION and DW_AT_declaration.  */
+static inline bool
+decl_will_get_specification_p (dw_die_ref old_die, tree decl, bool declaration)
+{
+  return (old_die && TREE_STATIC (decl) && !declaration
+	  && get_AT_flag (old_die, DW_AT_declaration) == 1);
+}
+
+/* Return true if DECL is a local static.  */
+
+static inline bool
+local_function_static (tree decl)
+{
+  gcc_assert (TREE_CODE (decl) == VAR_DECL);
+  return TREE_STATIC (decl)
+    && DECL_CONTEXT (decl)
+    && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL;
+}
+
 /* Generate a DIE to represent a declared data object.
    Either DECL or ORIGIN must be non-null.  */
 
@@ -19047,7 +19384,6 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
   tree ultimate_origin;
   dw_die_ref var_die;
   dw_die_ref old_die = decl ? lookup_decl_die (decl) : NULL;
-  dw_die_ref origin_die;
   bool declaration = (DECL_EXTERNAL (decl_or_origin)
 		      || class_or_namespace_scope_p (context_die));
   bool specialization_p = false;
@@ -19162,11 +19498,74 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
       return;
     }
 
+  dw_die_ref origin_die = NULL;
+
+  if (old_die && old_die->dumped_early)
+    {
+      if (decl_will_get_specification_p (old_die, decl, declaration))
+	{
+	  /* If we already have a DW_AT_specification, all we need is
+	     location info.  */
+	  if (get_AT (old_die, DW_AT_specification))
+	    {
+	      var_die = old_die;
+	      goto gen_variable_die_location;
+	    }
+	  /* Otherwise fall-thru so we can make a new variable die
+	     along with a DW_AT_specification.  */
+	}
+      else if (declaration)
+	{
+	  /* A declaration that has been previously dumped, needs no
+	     further annotations, since it doesn't need location on
+	     the second pass.  */
+	  return;
+	}
+      else if (old_die->die_parent != context_die)
+	{
+	  /* If the contexts differ, it means we _MAY_ not be talking
+	     about the same thing.  */
+	  if (origin)
+	    {
+	      /* If we will be creating an inlined instance, we need a
+		 new DIE that will get annotated with
+		 DW_AT_abstract_origin.  Clear things so we can get a
+		 new DIE.  */
+	      gcc_assert (!DECL_ABSTRACT_P (decl));
+	      old_die = NULL;
+	    }
+	  else
+	    {
+	      /* In some cases we end up with different contexts because
+		 the context_die is set to the context of the containing
+		 function, whereas the cached die is correctly set to the
+		 (possible) enclosing lexical scope (DW_TAG_lexical_block).
+		 In which case, special case it (hack).
+
+		 See dwarf2out_decl and its use of
+		 local_function_static to see how this can happened.
+		 In java, it can happen with non local statics, hence
+		 we do not check for TREE_STATIC here.  */
+	      gcc_assert (!DECL_CONTEXT (decl)
+			  || TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL);
+	      var_die = old_die;
+	      goto gen_variable_die_location;
+	    }
+	}
+      else
+	{
+	  /* If a DIE was dumped early, it still needs location info.
+	     Skip to where we fill the location bits.  */
+	  var_die = old_die;
+	  goto gen_variable_die_location;
+	}
+    }
+
   /* If the compiler emitted a definition for the DECL declaration
-     and if we already emitted a DIE for it, don't emit a second
+     and we already emitted a DIE for it, don't emit a second
      DIE for it again. Allow re-declarations of DECLs that are
      inside functions, though.  */
-  if (old_die && declaration && !local_scope_p (context_die))
+  else if (old_die && !declaration && !local_scope_p (context_die))
     return;
 
   /* For static data members, the declaration in the class is supposed
@@ -19177,7 +19576,6 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
   else
     var_die = new_die (DW_TAG_variable, context_die, decl);
 
-  origin_die = NULL;
   if (origin != NULL)
     origin_die = add_abstract_origin_attribute (var_die, origin);
 
@@ -19188,14 +19586,8 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
      copy decls and set the DECL_ABSTRACT_P flag on them instead of
      sharing them.
 
-     ??? Duplicated blocks have been rewritten to use .debug_ranges.
-
-     ??? The declare_in_namespace support causes us to get two DIEs for one
-     variable, both of which are declarations.  We want to avoid considering
-     one to be a specification, so we must test that this DIE is not a
-     declaration.  */
-  else if (old_die && TREE_STATIC (decl) && ! declaration
-	   && get_AT_flag (old_die, DW_AT_declaration) == 1)
+     ??? Duplicated blocks have been rewritten to use .debug_ranges.  */
+  else if (decl_will_get_specification_p (old_die, decl, declaration))
     {
       /* This is a definition of a C++ class level static.  */
       add_AT_specification (var_die, old_die);
@@ -19249,9 +19641,11 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
   if (declaration)
     add_AT_flag (var_die, DW_AT_declaration, 1);
 
-  if (decl && (DECL_ABSTRACT_P (decl) || declaration || old_die == NULL))
+  if (decl && (DECL_ABSTRACT_P (decl)
+	       || !old_die || is_declaration_die (old_die)))
     equate_decl_number_to_die (decl, var_die);
 
+ gen_variable_die_location:
   if (! declaration
       && (! DECL_ABSTRACT_P (decl_or_origin)
 	  /* Local static vars are shared between all clones/inlines,
@@ -19264,13 +19658,11 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
 	 to add it again.  */
       && (origin_die == NULL || get_AT (origin_die, DW_AT_location) == NULL))
     {
-      if (TREE_CODE (decl_or_origin) == VAR_DECL && TREE_STATIC (decl_or_origin)
-          && !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl_or_origin)))
-	defer_location (decl_or_origin, var_die);
+      if (early_dwarf)
+	add_pubname (decl_or_origin, var_die);
       else
-        add_location_or_const_value_attribute (var_die, decl_or_origin,
+	add_location_or_const_value_attribute (var_die, decl_or_origin,
 					       decl == NULL, DW_AT_location);
-      add_pubname (decl_or_origin, var_die);
     }
   else
     tree_add_const_value_attribute_for_decl (var_die, decl_or_origin);
@@ -19284,7 +19676,12 @@ gen_const_die (tree decl, dw_die_ref context_die)
   dw_die_ref const_die;
   tree type = TREE_TYPE (decl);
 
+  const_die = lookup_decl_die (decl);
+  if (const_die)
+    return;
+
   const_die = new_die (DW_TAG_constant, context_die, decl);
+  equate_decl_number_to_die (decl, const_die);
   add_name_and_src_coords_attributes (const_die, decl);
   add_type_attribute (const_die, type, TYPE_QUAL_CONST, context_die);
   if (TREE_PUBLIC (decl))
@@ -19300,14 +19697,20 @@ static void
 gen_label_die (tree decl, dw_die_ref context_die)
 {
   tree origin = decl_ultimate_origin (decl);
-  dw_die_ref lbl_die = new_die (DW_TAG_label, context_die, decl);
+  dw_die_ref lbl_die = lookup_decl_die (decl);
   rtx insn;
   char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
-  if (origin != NULL)
-    add_abstract_origin_attribute (lbl_die, origin);
-  else
-    add_name_and_src_coords_attributes (lbl_die, decl);
+  if (!lbl_die)
+    {
+      lbl_die = new_die (DW_TAG_label, context_die, decl);
+      equate_decl_number_to_die (decl, lbl_die);
+
+      if (origin != NULL)
+	add_abstract_origin_attribute (lbl_die, origin);
+      else
+	add_name_and_src_coords_attributes (lbl_die, decl);
+    }
 
   if (DECL_ABSTRACT_P (decl))
     equate_decl_number_to_die (decl, lbl_die);
@@ -19461,13 +19864,56 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
 static void
 gen_lexical_block_die (tree stmt, dw_die_ref context_die)
 {
-  dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+  dw_die_ref old_die = BLOCK_DIE (stmt);
+  dw_die_ref stmt_die;
+  if (!old_die)
+    {
+      stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+      BLOCK_DIE (stmt) = stmt_die;
+    }
 
-  if (call_arg_locations)
-    BLOCK_DIE (stmt) = stmt_die;
+  if (BLOCK_ABSTRACT (stmt))
+    {
+      if (old_die)
+	{
+#ifdef ENABLE_CHECKING
+	  /* This must have been generated early and it won't even
+	     need location information since it's a DW_AT_inline
+	     function.  */
+	  for (dw_die_ref c = context_die; c; c = c->die_parent)
+	    if (c->die_tag == DW_TAG_inlined_subroutine
+		|| c->die_tag == DW_TAG_subprogram)
+	      {
+		gcc_assert (get_AT (c, DW_AT_inline));
+		break;
+	      }
+#endif
+	  return;
+	}
+    }
+  else if (BLOCK_ABSTRACT_ORIGIN (stmt))
+    {
+      /* If this is an inlined instance, create a new lexical die for
+	 anything below to attach DW_AT_abstract_origin to.  */
+      if (old_die)
+	{
+	  stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+	  BLOCK_DIE (stmt) = stmt_die;
+	  old_die = NULL;
+	}
+    }
 
-  if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
-    add_high_low_attributes (stmt, stmt_die);
+  if (old_die)
+    stmt_die = old_die;
+
+  if (!early_dwarf)
+    {
+      /* A non abstract block whose blocks have already been reordered
+	 should have the instruction range for this block.  If so, set the
+	 high/low attributes.  */
+      if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
+	add_high_low_attributes (stmt, stmt_die);
+    }
 
   decls_for_scope (stmt, stmt_die);
 }
@@ -19962,6 +20408,18 @@ static void
 gen_struct_or_union_type_die (tree type, dw_die_ref context_die,
 				enum debug_info_usage usage)
 {
+  /* Fill in the bound of variable-length fields in late dwarf if
+     still incomplete.  */
+  if (TREE_ASM_WRITTEN (type)
+      && variably_modified_type_p (type, NULL)
+      && !early_dwarf)
+    {
+      tree member;
+      for (member = TYPE_FIELDS (type); member; member = DECL_CHAIN (member))
+	fill_variable_array_bounds (TREE_TYPE (member));
+      return;
+    }
+
   dw_die_ref type_die = lookup_type_die (type);
   dw_die_ref scope_die = 0;
   int nested = 0;
@@ -20081,7 +20539,11 @@ gen_typedef_die (tree decl, dw_die_ref context_die)
   tree origin;
 
   if (TREE_ASM_WRITTEN (decl))
-    return;
+    {
+      if (DECL_ORIGINAL_TYPE (decl))
+	fill_variable_array_bounds (DECL_ORIGINAL_TYPE (decl));
+      return;
+    }
 
   TREE_ASM_WRITTEN (decl) = 1;
   type_die = new_die (DW_TAG_typedef, context_die, decl);
@@ -20097,6 +20559,9 @@ gen_typedef_die (tree decl, dw_die_ref context_die)
 	{
 	  type = DECL_ORIGINAL_TYPE (decl);
 
+	  if (type == error_mark_node)
+	    return;
+
 	  gcc_assert (type != TREE_TYPE (decl));
 	  equate_type_number_to_die (TREE_TYPE (decl), type_die);
 	}
@@ -20104,6 +20569,9 @@ gen_typedef_die (tree decl, dw_die_ref context_die)
 	{
 	  type = TREE_TYPE (decl);
 
+	  if (type == error_mark_node)
+	    return;
+
 	  if (is_naming_typedef_decl (TYPE_NAME (type)))
 	    {
 	      /* Here, we are in the case of decl being a typedef naming
@@ -20164,13 +20632,15 @@ gen_tagged_type_die (tree type,
       || !is_tagged_type (type))
     return;
 
+  if (TREE_ASM_WRITTEN (type))
+    need_pop = 0;
   /* If this is a nested type whose containing class hasn't been written
      out yet, writing it out will cover this one, too.  This does not apply
      to instantiations of member class templates; they need to be added to
      the containing class as they are generated.  FIXME: This hurts the
      idea of combining type decls from multiple TUs, since we can't predict
      what set of template instantiations we'll get.  */
-  if (TYPE_CONTEXT (type)
+  else if (TYPE_CONTEXT (type)
       && AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
       && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
     {
@@ -20302,7 +20772,18 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
     }
 
   if (TREE_ASM_WRITTEN (type))
-    return;
+    {
+      /* Variable-length types may be incomplete even if
+	 TREE_ASM_WRITTEN.  For such types, fall through to
+	 gen_array_type_die() and possibly fill in
+	 DW_AT_{upper,lower}_bound attributes.  */
+      if ((TREE_CODE (type) != ARRAY_TYPE
+	   && TREE_CODE (type) != RECORD_TYPE
+	   && TREE_CODE (type) != UNION_TYPE
+	   && TREE_CODE (type) != QUAL_UNION_TYPE)
+	  || !variably_modified_type_p (type, NULL))
+	return;
+    }
 
   switch (TREE_CODE (type))
     {
@@ -20354,9 +20835,6 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
       break;
 
     case ARRAY_TYPE:
-      gen_array_type_die (type, context_die);
-      break;
-
     case VECTOR_TYPE:
       gen_array_type_die (type, context_die);
       break;
@@ -20527,8 +21005,11 @@ process_scope_var (tree stmt, tree decl, tree origin, dw_die_ref context_die)
   if (die != NULL && die->die_parent == NULL)
     add_child_die (context_die, die);
   else if (TREE_CODE (decl_or_origin) == IMPORTED_DECL)
-    dwarf2out_imported_module_or_decl_1 (decl_or_origin, DECL_NAME (decl_or_origin),
-					 stmt, context_die);
+    {
+      if (early_dwarf)
+	dwarf2out_imported_module_or_decl_1 (decl_or_origin, DECL_NAME (decl_or_origin),
+					     stmt, context_die);
+    }
   else
     gen_decl_die (decl, origin, context_die);
 }
@@ -20742,7 +21223,9 @@ setup_namespace_context (tree thing, dw_die_ref context_die)
    type) within its namespace, if appropriate.
 
    For compatibility with older debuggers, namespace DIEs only contain
-   declarations; all definitions are emitted at CU scope.  */
+   declarations; all definitions are emitted at CU scope, with
+   DW_AT_specification pointing to the declaration (like with class
+   members).  */
 
 static dw_die_ref
 declare_in_namespace (tree thing, dw_die_ref context_die)
@@ -21059,16 +21542,65 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
   return NULL;
 }
 \f
-/* Output debug information for global decl DECL.  Called from toplev.c after
-   compilation proper has finished.  */
+/* Output initial debug information for global DECL.  Called at the
+   end of the parsing process.
+
+   This is the initial debug generation process.  As such, the DIEs
+   generated may be incomplete.  A later debug generation pass
+   (dwarf2out_late_global_decl) will augment the information generated
+   in this pass (e.g., with complete location info).  */
 
 static void
-dwarf2out_global_decl (tree decl)
+dwarf2out_early_global_decl (tree decl)
 {
-  /* Output DWARF2 information for file-scope tentative data object
-     declarations, file-scope (extern) function declarations (which
-     had no corresponding body) and file-scope tagged type declarations
-     and definitions which have not yet been forced out.  */
+  set_early_dwarf s;
+
+  /* gen_decl_die() will set DECL_ABSTRACT because
+     cgraph_function_possibly_inlined_p() returns true.  This is in
+     turn will cause DW_AT_inline attributes to be set.
+
+     This happens because at early dwarf generation, there is no
+     cgraph information, causing cgraph_function_possibly_inlined_p()
+     to return true.  Trick cgraph_function_possibly_inlined_p()
+     while we generate dwarf early.  */
+  bool save = symtab->global_info_ready;
+  symtab->global_info_ready = true;
+
+  /* We don't handle TYPE_DECLs.  If required, they'll be reached via
+     other DECLs and they can point to template types or other things
+     that dwarf2out can't handle when done via dwarf2out_decl.  */
+  if (TREE_CODE (decl) != TYPE_DECL
+      && TREE_CODE (decl) != PARM_DECL)
+    {
+      tree save_fndecl = current_function_decl;
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+	{
+	  /* No cfun means the symbol has no body, so there's nothing
+	     to emit.  */
+	  if (!DECL_STRUCT_FUNCTION (decl))
+	    goto early_decl_exit;
+
+	  current_function_decl = decl;
+	}
+      dwarf2out_decl (decl);
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+	current_function_decl = save_fndecl;
+    }
+ early_decl_exit:
+  symtab->global_info_ready = save;
+}
+
+/* Output debug information for global decl DECL.  Called from
+   toplev.c after compilation proper has finished.  */
+
+static void
+dwarf2out_late_global_decl (tree decl)
+{
+  /* Output any global decls we missed or fill-in any location
+     information we were unable to determine on the first pass.
+
+     Skip over functions because they were handled by the
+     debug_hooks->function_decl() call in rest_of_handle_final.  */
   if ((TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl))
       && !POINTER_BOUNDS_P (decl))
     dwarf2out_decl (decl);
@@ -21080,7 +21612,10 @@ static void
 dwarf2out_type_decl (tree decl, int local)
 {
   if (!local)
-    dwarf2out_decl (decl);
+    {
+      set_early_dwarf s;
+      dwarf2out_decl (decl);
+    }
 }
 
 /* Output debug information for imported module or decl DECL.
@@ -21188,6 +21723,8 @@ dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
 
   gcc_assert (decl);
 
+  set_early_dwarf s;
+
   /* To emit DW_TAG_imported_module or DW_TAG_imported_decl, we need two DIEs.
      We need decl DIE for reference and scope die. First, get DIE for the decl
      itself.  */
@@ -21214,7 +21751,6 @@ dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
 
   /* OK, now we have DIEs for decl as well as scope. Emit imported die.  */
   dwarf2out_imported_module_or_decl_1 (decl, name, context, scope_die);
-
 }
 
 /* Output debug information for namelists.   */
@@ -21254,13 +21790,22 @@ gen_namelist_decl (tree name, dw_die_ref scope_die, tree item_decls)
 }
 
 
-/* Write the debugging output for DECL.  */
+/* Write the debugging output for DECL and return the DIE.  */
 
 static void
 dwarf2out_decl (tree decl)
 {
   dw_die_ref context_die = comp_unit_die ();
 
+#ifdef ENABLE_CHECKING
+  /* Save some info so we can later determine if we erroneously
+     created a DIE for something we had already created a DIE for.
+     We should always be reusing DIEs created early.  */
+  dw_die_ref early_die = NULL;
+  if (decl_die_table)
+    early_die = lookup_decl_die (decl);
+#endif
+
   switch (TREE_CODE (decl))
     {
     case ERROR_MARK:
@@ -21313,21 +21858,8 @@ dwarf2out_decl (tree decl)
       break;
 
     case VAR_DECL:
-      /* Ignore this VAR_DECL if it refers to a file-scope extern data object
-	 declaration and if the declaration was never even referenced from
-	 within this entire compilation unit.  We suppress these DIEs in
-	 order to save space in the .debug section (by eliminating entries
-	 which are probably useless).  Note that we must not suppress
-	 block-local extern declarations (whether used or not) because that
-	 would screw-up the debugger's name lookup mechanism and cause it to
-	 miss things which really ought to be in scope at a given point.  */
-      if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
-	return;
-
       /* For local statics lookup proper context die.  */
-      if (TREE_STATIC (decl)
-	  && DECL_CONTEXT (decl)
-	  && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
+      if (local_function_static (decl))
 	context_die = lookup_decl_die (DECL_CONTEXT (decl));
 
       /* If we are in terse mode, don't generate any DIEs to represent any
@@ -21382,6 +21914,19 @@ dwarf2out_decl (tree decl)
     }
 
   gen_decl_die (decl, NULL, context_die);
+
+  dw_die_ref die = lookup_decl_die (decl);
+  if (die)
+    check_die (die);
+#ifdef ENABLE_CHECKING
+  /* If we early created a DIE, make sure it didn't get re-created by
+     mistake.  */
+  if (early_die && early_die->dumped_early)
+    gcc_assert (early_die == die
+		/* We can have a differing DIE if and only if, the
+		   new one is a specification of the old one.  */
+		|| get_AT_ref (die, DW_AT_specification) == early_die);
+#endif
 }
 
 /* Write the debugging output for DECL.  */
@@ -21468,23 +22013,16 @@ dwarf_file_hasher::hash (dwarf_file_data *p)
    section) and references to those files numbers (in the .debug_srcinfo
    and.debug_macinfo sections).  If the filename given as an argument is not
    found in our current list, add it to the list and assign it the next
-   available unique index number.  In order to speed up searches, we remember
-   the index of the filename was looked up last.  This handles the majority of
-   all searches.  */
+   available unique index number.  */
 
 static struct dwarf_file_data *
 lookup_filename (const char *file_name)
 {
   struct dwarf_file_data * created;
 
-  /* Check to see if the file name that was searched on the previous
-     call matches this file name.  If so, return the index.  */
-  if (file_table_last_lookup
-      && (file_name == file_table_last_lookup->filename
-	  || filename_cmp (file_table_last_lookup->filename, file_name) == 0))
-    return file_table_last_lookup;
+  if (!file_name)
+    return NULL;
 
-  /* Didn't match the previous lookup, search the table.  */
   dwarf_file_data **slot
     = file_table->find_slot_with_hash (file_name, htab_hash_string (file_name),
 				       INSERT);
@@ -24523,11 +25061,20 @@ optimize_location_lists (dw_die_ref die)
 static void
 dwarf2out_finish (const char *filename)
 {
-  limbo_die_node *node, *next_node;
   comdat_type_node *ctnode;
-  unsigned int i;
   dw_die_ref main_comp_unit_die;
 
+  /* If the limbo list has anything, it should be things that were
+     created after the compilation proper.  Anything from the early
+     dwarf pass, should have parents and should never be in the limbo
+     list this late.  */
+  for (limbo_die_node *node = limbo_die_list; node; node = node->next)
+    gcc_assert (node->die->die_tag == DW_TAG_compile_unit
+		|| !node->die->dumped_early);
+
+  /* Flush out any latecomers to the limbo party.  */
+  dwarf2out_early_finish ();
+
   /* PCH might result in DW_AT_producer string being restored from the
      header compilation, so always fill it with empty string initially
      and overwrite only here.  */
@@ -24557,65 +25104,6 @@ dwarf2out_finish (const char *filename)
 	add_comp_dir_attribute (comp_unit_die ());
     }
 
-  if (deferred_locations_list)
-    for (i = 0; i < deferred_locations_list->length (); i++)
-      {
-	add_location_or_const_value_attribute (
-	    (*deferred_locations_list)[i].die,
-	    (*deferred_locations_list)[i].variable,
-	    false,
-	    DW_AT_location);
-      }
-
-  /* Traverse the limbo die list, and add parent/child links.  The only
-     dies without parents that should be here are concrete instances of
-     inline functions, and the comp_unit_die.  We can ignore the comp_unit_die.
-     For concrete instances, we can get the parent die from the abstract
-     instance.  */
-  for (node = limbo_die_list; node; node = next_node)
-    {
-      dw_die_ref die = node->die;
-      next_node = node->next;
-
-      if (die->die_parent == NULL)
-	{
-	  dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
-
-	  if (origin && origin->die_parent)
-	    add_child_die (origin->die_parent, die);
-	  else if (is_cu_die (die))
-	    ;
-	  else if (seen_error ())
-	    /* It's OK to be confused by errors in the input.  */
-	    add_child_die (comp_unit_die (), die);
-	  else
-	    {
-	      /* In certain situations, the lexical block containing a
-		 nested function can be optimized away, which results
-		 in the nested function die being orphaned.  Likewise
-		 with the return type of that nested function.  Force
-		 this to be a child of the containing function.
-
-		 It may happen that even the containing function got fully
-		 inlined and optimized out.  In that case we are lost and
-		 assign the empty child.  This should not be big issue as
-		 the function is likely unreachable too.  */
-	      gcc_assert (node->created_for);
-
-	      if (DECL_P (node->created_for))
-		origin = get_context_die (DECL_CONTEXT (node->created_for));
-	      else if (TYPE_P (node->created_for))
-		origin = scope_die_for (node->created_for, comp_unit_die ());
-	      else
-		origin = comp_unit_die ();
-
-	      add_child_die (origin, die);
-	    }
-	}
-    }
-
-  limbo_die_list = NULL;
-
 #if ENABLE_ASSERT_CHECKING
   {
     dw_die_ref die = comp_unit_die (), c;
@@ -24625,23 +25113,6 @@ dwarf2out_finish (const char *filename)
   resolve_addr (comp_unit_die ());
   move_marked_base_types ();
 
-  for (node = deferred_asm_name; node; node = node->next)
-    {
-      tree decl = node->created_for;
-      /* When generating LTO bytecode we can not generate new assembler
-         names at this point and all important decls got theirs via
-	 free-lang-data.  */
-      if (((!flag_generate_lto && !flag_generate_offload)
-	   || DECL_ASSEMBLER_NAME_SET_P (decl))
-	  && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
-	{
-	  add_linkage_attr (node->die, decl);
-	  move_linkage_attr (node->die);
-	}
-    }
-
-  deferred_asm_name = NULL;
-
   /* Walk through the list of incomplete types again, trying once more to
      emit full debugging info for them.  */
   retry_incomplete_types ();
@@ -24680,6 +25151,7 @@ dwarf2out_finish (const char *filename)
   /* Traverse the DIE's and add add sibling attributes to those DIE's
      that have children.  */
   add_sibling_attributes (comp_unit_die ());
+  limbo_die_node *node;
   for (node = limbo_die_list; node; node = node->next)
     add_sibling_attributes (node->die);
   for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
@@ -24941,6 +25413,83 @@ dwarf2out_finish (const char *filename)
     output_indirect_strings ();
 }
 
+/* Perform any cleanups needed after the early debug generation pass
+   has run.  */
+
+static void
+dwarf2out_early_finish (void)
+{
+  limbo_die_node *node, *next_node;
+
+  /* Add DW_AT_linkage_name for all deferred DIEs.  */
+  for (node = deferred_asm_name; node; node = node->next)
+    {
+      tree decl = node->created_for;
+      if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)
+	  /* A missing DECL_ASSEMBLER_NAME can be a constant DIE that
+	     ended up in in deferred_asm_name before we knew it was
+	     constant and never written to disk.  */
+	  && DECL_ASSEMBLER_NAME (decl))
+	{
+	  add_linkage_attr (node->die, decl);
+	  move_linkage_attr (node->die);
+	}
+    }
+  deferred_asm_name = NULL;
+
+  /* Traverse the limbo die list, and add parent/child links.  The only
+     dies without parents that should be here are concrete instances of
+     inline functions, and the comp_unit_die.  We can ignore the comp_unit_die.
+     For concrete instances, we can get the parent die from the abstract
+     instance.
+
+     The point here is to flush out the limbo list so that it is empty
+     and we don't need to stream it for LTO.  */
+  for (node = limbo_die_list; node; node = next_node)
+    {
+      dw_die_ref die = node->die;
+      next_node = node->next;
+
+      if (die->die_parent == NULL)
+	{
+	  dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
+
+	  if (origin && origin->die_parent)
+	    add_child_die (origin->die_parent, die);
+	  else if (is_cu_die (die))
+	    ;
+	  else if (seen_error ())
+	    /* It's OK to be confused by errors in the input.  */
+	    add_child_die (comp_unit_die (), die);
+	  else
+	    {
+	      /* In certain situations, the lexical block containing a
+		 nested function can be optimized away, which results
+		 in the nested function die being orphaned.  Likewise
+		 with the return type of that nested function.  Force
+		 this to be a child of the containing function.
+
+		 It may happen that even the containing function got fully
+		 inlined and optimized out.  In that case we are lost and
+		 assign the empty child.  This should not be big issue as
+		 the function is likely unreachable too.  */
+	      gcc_assert (node->created_for);
+
+	      if (DECL_P (node->created_for))
+		origin = get_context_die (DECL_CONTEXT (node->created_for));
+	      else if (TYPE_P (node->created_for))
+		origin = scope_die_for (node->created_for, comp_unit_die ());
+	      else
+		origin = comp_unit_die ();
+
+	      add_child_die (origin, die);
+	    }
+	}
+    }
+
+  limbo_die_list = NULL;
+}
+
 /* Reset all state within dwarf2out.c so that we can rerun the compiler
    within the same process.  For use by toplev::finalize.  */
 
@@ -24979,13 +25528,10 @@ dwarf2out_c_finalize (void)
   cold_text_section = NULL;
   current_unit_personality = NULL;
 
-  deferred_locations_list = NULL;
-
   next_die_offset = 0;
   single_comp_unit_die = NULL;
   comdat_type_list = NULL;
   limbo_die_list = NULL;
-  deferred_asm_name = NULL;
   file_table = NULL;
   decl_die_table = NULL;
   common_block_die_table = NULL;
@@ -25018,7 +25564,6 @@ dwarf2out_c_finalize (void)
   poc_label_num = 0;
   last_emitted_file = NULL;
   label_num = 0;
-  file_table_last_lookup = NULL;
   tmpl_value_parm_die_table = NULL;
   generic_type_instances = NULL;
   frame_pointer_fb_offset = 0;

^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2015-06-02 19:20 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-08  0:41 [patch 10/10] debug-early merge: compiler proper Aldy Hernandez
2015-05-18 11:06 ` Richard Biener
2015-05-18 14:47   ` Jan Hubicka
     [not found]   ` <555CAD35.5040304@redhat.com>
2015-05-20 21:03     ` Aldy Hernandez
2015-05-20 21:11       ` Jan Hubicka
2015-05-20 22:11         ` Aldy Hernandez
2015-05-22  9:00           ` Eric Botcazou
2015-05-22 11:45           ` Richard Biener
2015-05-22 13:41             ` Aldy Hernandez
2015-05-22 11:26     ` Richard Biener
2015-05-22 14:29       ` Aldy Hernandez
2015-05-27 13:18         ` Richard Biener
2015-05-27 12:50     ` Jason Merrill
2015-05-28 20:12       ` Aldy Hernandez
2015-05-28 20:54         ` Jason Merrill
2015-05-28 21:01           ` Jan Hubicka
2015-05-28 21:10             ` Jason Merrill
2015-05-28 21:16               ` Jan Hubicka
2015-05-29 12:07           ` Richard Biener
2015-05-29 19:33           ` Aldy Hernandez
2015-05-29 19:40             ` Richard Biener
2015-05-29 19:49               ` Jason Merrill
2015-05-31  7:53                 ` Aldy Hernandez
2015-05-31 22:14                   ` Jason Merrill
2015-06-01  8:03                     ` Richard Biener
2015-06-01  8:04                       ` Richard Biener
2015-06-01 15:43                         ` Aldy Hernandez
2015-06-01 17:01                           ` Richard Biener
2015-06-01 17:42                             ` Aldy Hernandez
2015-06-02  8:13                               ` Richard Biener
2015-06-02 19:25                                 ` Aldy Hernandez
2015-05-29 19:47             ` Jason Merrill
2015-05-28 21:31       ` Aldy Hernandez
2015-05-29  6:33         ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).