diff --git a/gcc/debug.h b/gcc/debug.h
index 3ac7976..28bc210 100644
--- a/gcc/debug.h
+++ b/gcc/debug.h
@@ -187,6 +187,8 @@ extern void dwarf2out_switch_text_section (void);
 const char *remap_debug_filename (const char *);
 void add_debug_prefix_map (const char *);
 
+extern void dwarf2out_early_decl (tree);
+
 /* For -fdump-go-spec.  */
 
 extern const struct gcc_debug_hooks *
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 1a9e50a..1ee5c26 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -3677,7 +3677,7 @@ decl_ultimate_origin (const_tree decl)
   /* output_inline_function sets DECL_ABSTRACT_ORIGIN for all the
      nodes in the function to point to themselves; ignore that if
      we're trying to output the abstract instance of this function.  */
-  if (DECL_ABSTRACT (decl) && DECL_ABSTRACT_ORIGIN (decl) == decl)
+  if (/*DECL_ABSTRACT (decl) &&*/ DECL_ABSTRACT_ORIGIN (decl) == decl)
     return NULL_TREE;
 
   /* Since the DECL_ABSTRACT_ORIGIN for a DECL is supposed to be the
@@ -4777,6 +4777,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;
@@ -5515,6 +5516,49 @@ debug_dwarf (void)
   print_indent = 0;
   print_die (comp_unit_die (), stderr);
 }
+
+/* Perform some sanity checks on DIEs after they have been generated
+   earlier in the compilation process.  */
+
+static void
+check_die (dw_die_ref die, unsigned level)
+{
+  static unsigned long mark = 1;
+  dw_die_ref c, p;
+  /* Check that all our childs have their parent set to us.  */
+  c = die->die_child;
+  if (c) do {
+      c = c->die_sib;
+      gcc_assert (c->die_parent == die);
+    } while (c != die->die_child);
+
+  /* Check the we are part of our parent's child list.  */
+  mark++;
+  p = die->die_parent;
+  if (p)
+    {
+      c = p->die_child;
+      gcc_assert (c);
+      do {
+	c = c->die_sib;
+	/* Found it.  */
+	if (c == die)
+	  break;
+	/* If we're at start --> not found.  */
+	gcc_assert (c != p->die_child);
+	/* If we've seen this node already the circular list doesn't
+	   even go back to start.  */
+	gcc_assert (c->die_abbrev != mark);
+	c->die_abbrev = mark;
+      } while (1);
+    }
+
+  if (!level)
+    return;
+
+  FOR_EACH_CHILD (die, c, check_die (c, level - 1));
+}
+
 
 /* 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
@@ -8657,9 +8701,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 (parent DIE=%#lx))",
 			       (unsigned long)die->die_offset,
-			       dwarf_tag_name (die->die_tag));
+			       dwarf_tag_name (die->die_tag),
+			       die->die_parent ? die->die_parent->die_offset : 0);
 
   FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
     {
@@ -17598,8 +17643,40 @@ 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 (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.
+
+	     ?? Add more checks here.  */
+	  if (! DECL_ABSTRACT (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;
+	    }
+	}
+    }
+
+  bool reusing_die;
+  if (parm_die)
+    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)))
     {
@@ -17607,7 +17684,11 @@ 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 (origin != NULL)
+
+      if (reusing_die)
+	goto add_location;
+
+      if (origin != NULL && node != origin)
 	add_abstract_origin_attribute (parm_die, origin);
       else if (emit_name_p)
 	add_name_and_src_coords_attributes (parm_die, node);
@@ -17631,6 +17712,7 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
 
       if (node && node != origin)
         equate_decl_number_to_die (node, parm_die);
+    add_location:
       if (! DECL_ABSTRACT (node_or_origin))
 	add_location_or_const_value_attribute (parm_die, node_or_origin,
 					       node == NULL, DW_AT_location);
@@ -18147,7 +18229,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       && debug_info_level > DINFO_LEVEL_TERSE)
     old_die = force_decl_die (decl);
 
-  if (origin != NULL)
+  if (origin != NULL && origin != decl)
     {
       gcc_assert (!declaration || local_scope_p (context_die));
 
@@ -18177,7 +18259,13 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	  && !get_AT (old_die, DW_AT_inline))
 	{
 	  /* Detect and ignore this case, where we are trying to output
-	     something we have already output.  */
+	     something we have already output.
+
+	     If we have no location information, this must be a
+	     partially generated DIE from early dwarf generation.
+	     Fall through and generate it.  */
+	  if (get_AT (old_die, DW_AT_low_pc)
+	      || get_AT (old_die, DW_AT_ranges))
 	  return;
 	}
 
@@ -18196,6 +18284,10 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	{
 	  subr_die = old_die;
 
+	  /* ??? Hmmm, early dwarf generation happened earlier, so no
+	     sense in removing the parameters.  Let's keep them and
+	     augment them with location information later.  */
+	  if (0) {
 	  /* 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
@@ -18204,6 +18296,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	  remove_AT (subr_die, DW_AT_declaration);
 	  remove_AT (subr_die, DW_AT_object_pointer);
 	  remove_child_TAG (subr_die, DW_TAG_formal_parameter);
+	  }
 	}
       else
 	{
@@ -18294,9 +18387,12 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 
       equate_decl_number_to_die (decl, subr_die);
     }
-  else if (!DECL_EXTERNAL (decl))
+  else if (!DECL_EXTERNAL (decl)
+	   && (!DECL_STRUCT_FUNCTION (decl)
+	       || DECL_STRUCT_FUNCTION (decl)->gimple_df))
     {
       HOST_WIDE_INT cfa_fb_offset;
+
       struct function *fun = DECL_STRUCT_FUNCTION (decl);
 
       if (!old_die || !get_AT (old_die, DW_AT_inline))
@@ -18459,10 +18555,20 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	add_AT_location_description (subr_die, DW_AT_static_link,
 		 loc_list_from_tree (fun->static_chain_decl, 2));
     }
+  else if (!DECL_EXTERNAL (decl))
+    {
+      if (!old_die || !get_AT (old_die, DW_AT_inline))
+	equate_decl_number_to_die (decl, subr_die);
+    }
 
   /* Generate child dies for template paramaters.  */
   if (debug_info_level > DINFO_LEVEL_TERSE)
-    gen_generic_params_dies (decl);
+    {
+      /* XXX */
+      if (!lookup_decl_die (decl))
+	equate_decl_number_to_die (decl, subr_die);
+      gen_generic_params_dies (decl);
+    }
 
   /* Now output descriptions of the arguments for this function. This gets
      (unnecessarily?) complex because of the fact that the DECL_ARGUMENT list
@@ -18566,7 +18672,9 @@ 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.  */
-  if (! declaration && outer_scope && TREE_CODE (outer_scope) != ERROR_MARK)
+  if (! declaration && outer_scope && TREE_CODE (outer_scope) != ERROR_MARK
+      && (!DECL_STRUCT_FUNCTION (decl)
+	  || DECL_STRUCT_FUNCTION (decl)->gimple_df))
     {
       int call_site_note_count = 0;
       int tail_call_site_note_count = 0;
@@ -18886,7 +18994,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
      and if 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))
+  if (old_die && !declaration && !local_scope_p (context_die))
     return;
 
   /* For static data members, the declaration in the class is supposed
@@ -21007,6 +21115,54 @@ dwarf2out_decl (tree decl)
     }
 
   gen_decl_die (decl, NULL, context_die);
+
+  dw_die_ref die = lookup_decl_die (decl);
+  if (die)
+    check_die (die, 0);
+}
+
+/* Early dumping of DECLs before we lose language data.  */
+
+void
+dwarf2out_early_decl (tree decl)
+{
+  /* 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)
+    {
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+	{
+	  /* A missing cfun means the symbol is unused and was removed
+	     from the callgraph.  */
+	  if (!DECL_STRUCT_FUNCTION (decl))
+	    goto early_decl_exit;
+
+	  push_cfun (DECL_STRUCT_FUNCTION (decl));
+	  current_function_decl = decl;
+	}
+      dwarf2out_decl (decl);
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+	{
+	  pop_cfun ();
+	  current_function_decl = NULL;
+	}
+    }
+ early_decl_exit:
+  symtab->global_info_ready = save;
+  return;
 }
 
 /* Write the debugging output for DECL.  */
diff --git a/gcc/tree.c b/gcc/tree.c
index 33922a0..ce46191 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -5030,6 +5030,10 @@ free_lang_data_in_decl (tree decl)
 {
   gcc_assert (DECL_P (decl));
 
+  /* Early dumping of DECLs before we lose language data.  */
+  if (debug_info_level > DINFO_LEVEL_NONE)
+    dwarf2out_early_decl (decl);
+
   /* Give the FE a chance to remove its own data first.  */
   lang_hooks.free_lang_data (decl);
 
@@ -5628,8 +5632,7 @@ free_lang_data (void)
   unsigned i;
 
   /* If we are the LTO frontend we have freed lang-specific data already.  */
-  if (in_lto_p
-      || !flag_generate_lto)
+  if (in_lto_p)
     return 0;
 
   /* Allocate and assign alias sets to the standard integer types
