This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch 10/10] debug-early merge: compiler proper


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
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);
+    }
+}
 
 /* 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
 
+/* 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;
 }
 
-/* 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;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]