[debug-early] reuse variable DIEs and fix their context
diff mbox

Message ID 5409220E.6070100@redhat.com
State New
Headers show

Commit Message

Aldy Hernandez Sept. 5, 2014, 2:38 a.m. UTC
On 09/04/14 03:42, Richard Biener wrote:
> On Wed, Sep 3, 2014 at 7:54 PM, Aldy Hernandez <aldyh@redhat.com> wrote:

> Flow-wise I still want to move hand-off to the cgraph code to toplev.c,
> out from the FEs final_write_gloabals hook:
>
>    /* This must also call finalize_compilation_unit.  */
>    lang_hooks.decls.final_write_globals ();
>
> that would make clearer how control flows.

Neat.  I like it.

> I'd also rather split the hook into two ... (and call the 2nd non-early
> phase hook from where we output the code).  What does that phase
> output for global decls anyway?

This is also a very good idea, and it makes the intent clearer.

> Otherwise looks like a good incremental improvement to me.

Since we're pretty much on the same page, I've committed this revision 
you just looked at, so we can talk about the changes you mention above 
separately, namely:

a) Divorcing final_write_globals and finalize_compilation.
b) Splitting the global_decl hook into two.

So this is what I have in mind (patch attached).  I'd like to split
LANG_HOOKS_WRITE_GLOBALS in favor of 
LANG_HOOKS_{EARLY,LATE}_WRITE_GLOBALS, as well as splitting the 
global_decl debug hook into {early,late}_global_decl.  I've commented 
things throughout to make it very clear what we're getting at.

I chose to dispense with the old names to make it very clear what the 
hook should do, and to make sure I didn't miss any places.

Toplev will now look much cleaner:

+  /* Emit early debugging information as well as globals.  */
+  timevar_start (TV_PHASE_DEFERRED);
+  lang_hooks.decls.early_write_globals ();
+  timevar_stop (TV_PHASE_DEFERRED);
+
+  /* We're done parsing; proceed to optimize and emit assembly.  */
+  timevar_start (TV_PHASE_OPT_GEN);
+  symtab->finalize_compilation_unit ();
+  timevar_stop (TV_PHASE_OPT_GEN);
+
+  /* Amend any debugging information generated previously.  */
+  timevar_start (TV_PHASE_DBGINFO);
+  lang_hooks.decls.late_write_globals ();
+  timevar_stop (TV_PHASE_DBGINFO);

Preeeeety... if I do say so myself.

The attached patch is untested, and will fail miserably on anything but 
C (lto, c++, etc).  But it shows how I'd like to approach this.

Would you bless this approach, so I can continue with the other 
languages and LTO?

As usual, thanks for your feedback.
Aldy

Comments

Richard Biener Sept. 5, 2014, 9 a.m. UTC | #1
On Fri, Sep 5, 2014 at 4:38 AM, Aldy Hernandez <aldyh@redhat.com> wrote:
> On 09/04/14 03:42, Richard Biener wrote:
>>
>> On Wed, Sep 3, 2014 at 7:54 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
>
>
>> Flow-wise I still want to move hand-off to the cgraph code to toplev.c,
>> out from the FEs final_write_gloabals hook:
>>
>>    /* This must also call finalize_compilation_unit.  */
>>    lang_hooks.decls.final_write_globals ();
>>
>> that would make clearer how control flows.
>
>
> Neat.  I like it.
>
>> I'd also rather split the hook into two ... (and call the 2nd non-early
>> phase hook from where we output the code).  What does that phase
>> output for global decls anyway?
>
>
> This is also a very good idea, and it makes the intent clearer.
>
>> Otherwise looks like a good incremental improvement to me.
>
>
> Since we're pretty much on the same page, I've committed this revision you
> just looked at, so we can talk about the changes you mention above
> separately, namely:
>
> a) Divorcing final_write_globals and finalize_compilation.
> b) Splitting the global_decl hook into two.
>
> So this is what I have in mind (patch attached).  I'd like to split
> LANG_HOOKS_WRITE_GLOBALS in favor of LANG_HOOKS_{EARLY,LATE}_WRITE_GLOBALS,
> as well as splitting the global_decl debug hook into
> {early,late}_global_decl.  I've commented things throughout to make it very
> clear what we're getting at.

I meant that LATE_WRITE_GLOBALS shouldn't be a langhook
at all but instead the middle-end should be in control of that and
implement it in a language independent way.  After all this will be
called from LTO LTRANS phase.

> I chose to dispense with the old names to make it very clear what the hook
> should do, and to make sure I didn't miss any places.
>
> Toplev will now look much cleaner:
>
> +  /* Emit early debugging information as well as globals.  */
> +  timevar_start (TV_PHASE_DEFERRED);
> +  lang_hooks.decls.early_write_globals ();
> +  timevar_stop (TV_PHASE_DEFERRED);
> +
> +  /* We're done parsing; proceed to optimize and emit assembly.  */
> +  timevar_start (TV_PHASE_OPT_GEN);
> +  symtab->finalize_compilation_unit ();
> +  timevar_stop (TV_PHASE_OPT_GEN);
> +
> +  /* Amend any debugging information generated previously.  */
> +  timevar_start (TV_PHASE_DBGINFO);
> +  lang_hooks.decls.late_write_globals ();
> +  timevar_stop (TV_PHASE_DBGINFO);
>
> Preeeeety... if I do say so myself.

Yeah - apart from that langhook issue for late_write_globals ;)

> The attached patch is untested, and will fail miserably on anything but C
> (lto, c++, etc).  But it shows how I'd like to approach this.
>
> Would you bless this approach, so I can continue with the other languages
> and LTO?

Be prepared to meet some fun with Java and moving finalize_compilation_unit
out (I remember trying that at some point).

Otherwise it would be nice if you can implement late_write_globals by
simply walking the symbol table with sth like

  FOR_EACH_DEFINED_SYMBOL (node)
     debug_hooks->late_global_decl (node->decl);

well - of course it will likely not be _that_ simple.  And eventually it's
better to do this from where we have done the output (in varasm.c
for variables and somewhere in final.c for functions), but let's try
that FOR_EACH as it looks so simple ;)

Richard.

> As usual, thanks for your feedback.
> Aldy
Aldy Hernandez Sept. 9, 2014, midnight UTC | #2
On 09/05/14 02:00, Richard Biener wrote:

[jason: C++ questions throughout.]

> On Fri, Sep 5, 2014 at 4:38 AM, Aldy Hernandez <aldyh@redhat.com> wrote:
>> On 09/04/14 03:42, Richard Biener wrote:
>>>
>>> On Wed, Sep 3, 2014 at 7:54 PM, Aldy Hernandez <aldyh@redhat.com> wrote:

> I meant that LATE_WRITE_GLOBALS shouldn't be a langhook
> at all but instead the middle-end should be in control of that and
> implement it in a language independent way.  After all this will be
> called from LTO LTRANS phase.

This looks like a rat's nest :(.

Interestingly, most non-C/C++ languages are well behaved, and use the 
generic write_global_declarations() function.  Ada even goes as far as 
calling debug_hooks->global_decl() before the compilation proper and 
then once again after the compilation has finished (like we're planning 
on doing).  Java, which you thought was horrible, mostly just calls the 
generic write_global_declarations().  C++ is a different story...

It seems to me that C++ is the most complicated of the FE's when it 
comes to LANG_HOOKS_WRITE_GLOBALS.  Most annoyingly, it does many things 
*after* it has called finalize_compilation_unit (creating VTV 
constructors, calling check_global_declarations on pending_statics, 
building Java method aliases, etc etc).  See 
cp_write_global_declarations() for everything after 
finalize_compilation_unit).

What I have in mind is:

1. Move the FE specific things that come before the call to 
finalize_compilation_unit currently in each LANG_HOOKS_WRITE_GLOBALS, 
into the FE proper (lang_hooks.parse_file).  This may or may not mean 
calling {wrapup,check}_global_declarations directly from the FEs since 
some FE's call these in a sufficiently different order to merit everyone 
doing their own thing (not sure though).

2. Generate debug information by gathering the list of globals with 
lang_hooks.decls.getdecls (??) and then doing 
debug_hooks->early_global_decl() as discussed.

2. Call finalize_compilation_unit() directly from compile_file().

3. Call some (new) hook for C++ stuff after finalize_compilation_unit (???).

4. FOR_EACH_DEFINED_SYMBOL (node)
      debug_hooks->late_global_decl (node->decl)

    as suggested.

The wildcard here is C++.  Shall we create a hook for post 
finalize_compilation_unit() but pre late debug dumping (item 3 above)? 
Or can we move most of the post finalize_compilation_unit() stuff in C++ 
before it, thus into the FE proper?  Also, disturbingly C++ calls 
check_global_declarations() after finalize_compilation_unit (a couple 
times actually).

I think if we can get C++ to work, everything else basically falls into 
place... even Ada and Go ;-).

Comments highly welcome.
Aldy
Richard Biener Sept. 9, 2014, 9:16 a.m. UTC | #3
On Tue, Sep 9, 2014 at 2:00 AM, Aldy Hernandez <aldyh@redhat.com> wrote:
> On 09/05/14 02:00, Richard Biener wrote:
>
> [jason: C++ questions throughout.]
>
>> On Fri, Sep 5, 2014 at 4:38 AM, Aldy Hernandez <aldyh@redhat.com> wrote:
>>>
>>> On 09/04/14 03:42, Richard Biener wrote:
>>>>
>>>>
>>>> On Wed, Sep 3, 2014 at 7:54 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
>
>
>> I meant that LATE_WRITE_GLOBALS shouldn't be a langhook
>> at all but instead the middle-end should be in control of that and
>> implement it in a language independent way.  After all this will be
>> called from LTO LTRANS phase.
>
>
> This looks like a rat's nest :(.
>
> Interestingly, most non-C/C++ languages are well behaved, and use the
> generic write_global_declarations() function.  Ada even goes as far as
> calling debug_hooks->global_decl() before the compilation proper and then
> once again after the compilation has finished (like we're planning on
> doing).  Java, which you thought was horrible, mostly just calls the generic
> write_global_declarations().  C++ is a different story...
>
> It seems to me that C++ is the most complicated of the FE's when it comes to
> LANG_HOOKS_WRITE_GLOBALS.  Most annoyingly, it does many things *after* it
> has called finalize_compilation_unit (creating VTV constructors, calling
> check_global_declarations on pending_statics, building Java method aliases,
> etc etc).  See cp_write_global_declarations() for everything after
> finalize_compilation_unit).

Yeah, it was the Java method aliases building I remember (I tried before
VTV materialized) ;)   So I falsely blamed Java - it's only remotely Javas
fault ... ;)

> What I have in mind is:
>
> 1. Move the FE specific things that come before the call to
> finalize_compilation_unit currently in each LANG_HOOKS_WRITE_GLOBALS, into
> the FE proper (lang_hooks.parse_file).  This may or may not mean calling
> {wrapup,check}_global_declarations directly from the FEs since some FE's
> call these in a sufficiently different order to merit everyone doing their
> own thing (not sure though).
>
> 2. Generate debug information by gathering the list of globals with
> lang_hooks.decls.getdecls (??) and then doing
> debug_hooks->early_global_decl() as discussed.

Or move that also to lang_hooks.parse_file?  ISTR lang_hooks.decls.getdecls
is sort of an "alternative" hook to write_global_declarations that is only
used by the generic implementation of write_global_declarations.

So if we move everything else but calling debug_hooks->early_global_decl ()
out of the write_global_declarations langhook then we could indeed
remove that hook and implement getdecls everywhere.

I suppose one of the hooks should go in the end.

> 2. Call finalize_compilation_unit() directly from compile_file().

Great!

> 3. Call some (new) hook for C++ stuff after finalize_compilation_unit (???).

Or fix the C++ stuff to work properly in a symtab way?  I suppose as
an intermediate step adding a new langhook for this on the branch is ok
but I'd rather not get that merged into trunk.

Maybe Jason can help cleaning this up.

> 4. FOR_EACH_DEFINED_SYMBOL (node)
>      debug_hooks->late_global_decl (node->decl)
>
>    as suggested.
>
> The wildcard here is C++.  Shall we create a hook for post
> finalize_compilation_unit() but pre late debug dumping (item 3 above)? Or
> can we move most of the post finalize_compilation_unit() stuff in C++ before
> it, thus into the FE proper?  Also, disturbingly C++ calls
> check_global_declarations() after finalize_compilation_unit (a couple times
> actually).
>
> I think if we can get C++ to work, everything else basically falls into
> place... even Ada and Go ;-).

I hope that C++ can be "fixed" to do things in proper order and not
behind symtabs back.

For the branch to be able to move forward we can certainly add some
hooks temporarily.

Or disable the Java/VTV stuff for the time being.  I don't remember
running into the check_global_declarations () issue (or what that does).

Jason?

Tahnks,
Richard.

> Comments highly welcome.
> Aldy

Patch
diff mbox

diff --git a/gcc/ada/gcc-interface/misc.c b/gcc/ada/gcc-interface/misc.c
index 240ca44..fd88e44 100644
--- a/gcc/ada/gcc-interface/misc.c
+++ b/gcc/ada/gcc-interface/misc.c
@@ -894,8 +894,9 @@  gnat_init_ts (void)
 #define LANG_HOOKS_GETDECLS		lhd_return_null_tree_v
 #undef  LANG_HOOKS_PUSHDECL
 #define LANG_HOOKS_PUSHDECL		gnat_return_tree
-#undef  LANG_HOOKS_WRITE_GLOBALS
-#define LANG_HOOKS_WRITE_GLOBALS	gnat_write_global_declarations
+/* FIXME: Add Ada support.  */
+#undef  LANG_HOOKS_EARLY_WRITE_GLOBALS
+#define LANG_HOOKS_EARLY_WRITE_GLOBALS	gnat_write_global_declarations
 #undef  LANG_HOOKS_GET_ALIAS_SET
 #define LANG_HOOKS_GET_ALIAS_SET	gnat_get_alias_set
 #undef  LANG_HOOKS_PRINT_DECL
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 1e09404..79ea89c 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -10310,7 +10310,7 @@  c_write_global_declarations_1 (tree globals)
   for (decl = globals; decl; decl = DECL_CHAIN (decl))
     {
       check_global_declaration_1 (decl);
-      debug_hooks->global_decl (decl, /*early=*/true);
+      debug_hooks->early_global_decl (decl);
     }
 }
 
@@ -10322,8 +10322,10 @@  c_write_global_declarations_2 (tree globals)
 {
   tree decl;
 
+  /* FIXME: Rewrite to iterate through varpool/cgraph nodes, instead
+     of `globals'.  */
   for (decl = globals; decl ; decl = DECL_CHAIN (decl))
-    debug_hooks->global_decl (decl, /*early=*/false);
+    debug_hooks->late_global_decl (decl);
 }
 
 /* Callback to collect a source_ref from a DECL.  */
@@ -10374,17 +10376,12 @@  for_each_global_decl (void (*callback) (tree decl))
 }
 
 void
-c_write_global_declarations (void)
+c_early_write_global_declarations (void)
 {
-  tree t;
-  unsigned i;
-
   /* We don't want to do this if generating a PCH.  */
   if (pch_file)
     return;
 
-  timevar_start (TV_PHASE_DEFERRED);
-
   /* Do the Objective-C stuff.  This is where all the Objective-C
      module stuff gets generated (symtab, class/protocol/selector
      lists etc).  */
@@ -10422,24 +10419,24 @@  c_write_global_declarations (void)
 
   /* Process all file scopes in this compilation, and the external_scope,
      through wrapup_global_declarations and check_global_declarations.  */
+  tree t;
+  unsigned i;
   FOR_EACH_VEC_ELT (*all_translation_units, i, t)
     c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t)));
   c_write_global_declarations_1 (BLOCK_VARS (ext_block));
+}
 
-  timevar_stop (TV_PHASE_DEFERRED);
-  timevar_start (TV_PHASE_OPT_GEN);
-
-  /* We're done parsing; proceed to optimize and emit assembly.
-     FIXME: shouldn't be the front end's responsibility to call this.  */
-  symtab->finalize_compilation_unit ();
-
-  timevar_stop (TV_PHASE_OPT_GEN);
-  timevar_start (TV_PHASE_DBGINFO);
-
+void
+c_late_write_global_declarations (void)
+{
   /* After cgraph has had a chance to emit everything that's going to
-     be emitted, output debug information for globals.  */
+     be emitted, amend any debug information for globals with
+     appropriate location information.  */
   if (!seen_error ())
     {
+      unsigned int i;
+      tree t;
+
       timevar_push (TV_SYMOUT);
       FOR_EACH_VEC_ELT (*all_translation_units, i, t)
 	c_write_global_declarations_2 (BLOCK_VARS (DECL_INITIAL (t)));
@@ -10448,7 +10445,6 @@  c_write_global_declarations (void)
     }
 
   ext_block = NULL;
-  timevar_stop (TV_PHASE_DBGINFO);
 }
 
 /* Register reserved keyword WORD as qualifier for address space AS.  */
diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h
index 92cf60f..acabeec 100644
--- a/gcc/c/c-objc-common.h
+++ b/gcc/c/c-objc-common.h
@@ -92,8 +92,10 @@  along with GCC; see the file COPYING3.  If not see
 
 #undef LANG_HOOKS_GETDECLS
 #define LANG_HOOKS_GETDECLS lhd_return_null_tree_v
-#undef LANG_HOOKS_WRITE_GLOBALS
-#define LANG_HOOKS_WRITE_GLOBALS c_write_global_declarations
+#undef LANG_HOOKS_EARLY_WRITE_GLOBALS
+#define LANG_HOOKS_EARLY_WRITE_GLOBALS c_early_write_global_declarations
+#undef LANG_HOOKS_LATE_WRITE_GLOBALS
+#define LANG_HOOKS_LATE_WRITE_GLOBALS c_late_write_global_declarations
 
 /* Hooks for tree gimplification.  */
 #undef LANG_HOOKS_GIMPLIFY_EXPR
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 6004d50..9dada9c 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -669,7 +669,8 @@  extern enum machine_mode c_default_pointer_mode;
 
 /* In c-decl.c */
 extern void c_finish_incomplete_decl (tree);
-extern void c_write_global_declarations (void);
+extern void c_early_write_global_declarations (void);
+extern void c_late_write_global_declarations (void);
 extern tree c_omp_reduction_id (enum tree_code, tree);
 extern tree c_omp_reduction_decl (tree);
 extern tree c_omp_reduction_lookup (tree, tree);
diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
index 246800e..2435e06 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -83,8 +83,9 @@  extern void cp_common_init_ts (void);
 #define LANG_HOOKS_PRINT_ERROR_FUNCTION	cxx_print_error_function
 #undef LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL
 #define LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL cxx_warn_unused_global_decl
-#undef LANG_HOOKS_WRITE_GLOBALS
-#define LANG_HOOKS_WRITE_GLOBALS cp_write_global_declarations
+/* FIXME: Add C++ support.  */
+#undef LANG_HOOKS_EARLY_WRITE_GLOBALS
+#define LANG_HOOKS_EARLY_WRITE_GLOBALS cp_write_global_declarations
 #undef  LANG_HOOKS_BUILTIN_FUNCTION
 #define LANG_HOOKS_BUILTIN_FUNCTION cxx_builtin_function
 #undef  LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE
diff --git a/gcc/dbxout.c b/gcc/dbxout.c
index 208cec9..e517311 100644
--- a/gcc/dbxout.c
+++ b/gcc/dbxout.c
@@ -325,7 +325,7 @@  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, bool);
+static void dbxout_global_decl (tree);
 static void dbxout_type_decl (tree, int);
 static void dbxout_handle_pch (unsigned);
 static void debug_free_queue (void);
@@ -366,7 +366,8 @@  const struct gcc_debug_hooks dbx_debug_hooks =
 #endif
   debug_nothing_int,		         /* end_function */
   dbxout_function_decl,
-  dbxout_global_decl,		         /* global_decl */
+  debug_nothing_tree,		         /* early_global_decl */
+  dbxout_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 */
@@ -402,7 +403,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 */
+  debug_nothing_tree,		         /* early_global_decl */
+  dbxout_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 */
@@ -1320,7 +1322,7 @@  dbxout_function_decl (tree decl)
 /* Debug information for a global DECL.  Called from toplev.c after
    compilation proper has finished.  */
 static void
-dbxout_global_decl (tree decl, bool early ATTRIBUTE_UNUSED)
+dbxout_global_decl (tree decl)
 {
   if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
     {
diff --git a/gcc/debug.c b/gcc/debug.c
index b5818de..2beb10f 100644
--- a/gcc/debug.c
+++ b/gcc/debug.c
@@ -43,7 +43,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_bool,	         /* 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 9440515..227618d 100644
--- a/gcc/debug.h
+++ b/gcc/debug.h
@@ -92,12 +92,22 @@  struct gcc_debug_hooks
      function.  */
   void (* function_decl) (tree decl);
 
-  /* Debug information for a global DECL.  Called from toplev.c after
-     compilation proper has finished.  EARLY is true if global_decl()
-     is being called early on in the compilation process (i.e., before
-     cgraph information is available and before code is
-     generated).  */
-  void (* global_decl) (tree decl, bool early);
+  /* Debug information for a global DECL.  Called before the
+     compilation proper has run (i.e., before cgraph information is
+     available, usually after parsing has completed).
+
+     This hooks gets called to emit initial debugging information
+     after parsing has happened, but before we have complete location
+     information.  When the compilation proper has finished,
+     late_global_decl (below) is called and the debugging information
+     generated by this hook is amended accordingly.  */
+  void (* early_global_decl) (tree decl);
+
+  /* This hook is called after the compilation proper has finished and
+     is used to ammend debugging information which was initially
+     generated by early_global_decl above (with location information
+     and such).  */
+  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
@@ -191,8 +201,6 @@  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 918f261..f3f8481 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2430,7 +2430,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, bool);
+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,
@@ -2468,7 +2469,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,	/* early_global_decl */
+  dwarf2out_late_global_decl,	/* late_global_decl */
   dwarf2out_type_decl,		/* type_decl */
   dwarf2out_imported_module_or_decl,
   debug_nothing_tree,		/* deferred_inline_function */
@@ -2609,7 +2611,7 @@  typedef struct GTY((chain_circular ("%h.die_sib"))) 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_decl.  */
+  /* Die was generated early via dwarf2out_early_global_decl.  */
   BOOL_BITFIELD dumped_early : 1;
   /* Lots of spare bits.  */
 }
@@ -20817,29 +20819,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.
-
-   dwarf2out_decl() will be called twice on each global symbol: once
-   immediately after parsing (EARLY=true), and once after the full
-   compilation has finished (EARLY=false).  There are checks in
-   dwarf2out_decl() to make sure that if we have a DECL DIE upon
-   entry, that the previously created DIE is reused.  No new DECL DIEs
-   should be created when EARLY=false.
-
-   The second time dwarf2out_decl() is called (or for that matter, the
-   second time any DECL DIE is seen throughout dwarf2out), only
-   information not previously available (e.g. location) is tacked onto
-   the early dumped DIE.  That's the plan anyhow ;-).  */
+/* Output initial debug information for global decl DECL.  Called from
+   toplev.c after parsing has finished.  After the compilation proper
+   has finished, the debugging information generated here is amended
+   with location information and other things (see
+   dwarf2out_late_global_decl).  */
 
 static void
-dwarf2out_global_decl (tree decl, bool early)
+dwarf2out_early_global_decl (tree decl)
 {
-  if (early)
+  /* 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)
     {
-      dwarf2out_early_decl (decl);
-      return;
+      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;
+	}
+      dw_die_ref die = dwarf2out_decl (decl);
+      if (die)
+	die->dumped_early = true;
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+	{
+	  pop_cfun ();
+	  current_function_decl = NULL;
+	}
     }
+ early_decl_exit:
+  symtab->global_info_ready = save;
+  return;
+}
+
+/* After the compilation proper has finished, augment any debugging
+   information generated in dwarf2out_early_global_decl().  No new
+   DECL DIEs should be generated at this point.  Instead, DIEs
+   generated in dwarf2out_early_global_decl should be reused and
+   amended.  */
+
+static void
+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
@@ -21181,52 +21219,6 @@  dwarf2out_decl (tree decl)
   return die;
 }
 
-/* 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;
-	}
-      dw_die_ref die = dwarf2out_decl (decl);
-      if (die)
-	die->dumped_early = true;
-      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.  */
 
 static void
diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c
index da3a0d0..d435c07 100644
--- a/gcc/fortran/f95-lang.c
+++ b/gcc/fortran/f95-lang.c
@@ -108,7 +108,8 @@  static const struct attribute_spec gfc_attribute_table[] =
 #undef LANG_HOOKS_NAME
 #undef LANG_HOOKS_INIT
 #undef LANG_HOOKS_FINISH
-#undef LANG_HOOKS_WRITE_GLOBALS
+#undef LANG_HOOKS_EARLY_WRITE_GLOBALS
+#undef LANG_HOOKS_LATE_WRITE_GLOBALS
 #undef LANG_HOOKS_OPTION_LANG_MASK
 #undef LANG_HOOKS_INIT_OPTIONS_STRUCT
 #undef LANG_HOOKS_INIT_OPTIONS
@@ -142,7 +143,8 @@  static const struct attribute_spec gfc_attribute_table[] =
 #define LANG_HOOKS_NAME                 "GNU Fortran"
 #define LANG_HOOKS_INIT                 gfc_init
 #define LANG_HOOKS_FINISH               gfc_finish
-#define LANG_HOOKS_WRITE_GLOBALS	gfc_write_global_declarations
+/* FIXME: Add Fortran support.  */
+#define LANG_HOOKS_EARLY_WRITE_GLOBALS	gfc_write_global_declarations
 #define LANG_HOOKS_OPTION_LANG_MASK	gfc_option_lang_mask
 #define LANG_HOOKS_INIT_OPTIONS_STRUCT  gfc_init_options_struct
 #define LANG_HOOKS_INIT_OPTIONS         gfc_init_options
diff --git a/gcc/go/go-lang.c b/gcc/go/go-lang.c
index 24b6437..a2aec63 100644
--- a/gcc/go/go-lang.c
+++ b/gcc/go/go-lang.c
@@ -534,7 +534,8 @@  go_localize_identifier (const char *ident)
 #undef LANG_HOOKS_GLOBAL_BINDINGS_P
 #undef LANG_HOOKS_PUSHDECL
 #undef LANG_HOOKS_GETDECLS
-#undef LANG_HOOKS_WRITE_GLOBALS
+#undef LANG_HOOKS_EARLY_WRITE_GLOBALS
+#undef LANG_HOOKS_LATE_WRITE_GLOBALS
 #undef LANG_HOOKS_GIMPLIFY_EXPR
 #undef LANG_HOOKS_EH_PERSONALITY
 
@@ -551,7 +552,8 @@  go_localize_identifier (const char *ident)
 #define LANG_HOOKS_GLOBAL_BINDINGS_P	go_langhook_global_bindings_p
 #define LANG_HOOKS_PUSHDECL		go_langhook_pushdecl
 #define LANG_HOOKS_GETDECLS		go_langhook_getdecls
-#define LANG_HOOKS_WRITE_GLOBALS	go_langhook_write_globals
+/* FIXME: Add Go support.  */
+#define LANG_HOOKS_EARLY_WRITE_GLOBALS	go_langhook_write_globals
 #define LANG_HOOKS_GIMPLIFY_EXPR	go_langhook_gimplify_expr
 #define LANG_HOOKS_EH_PERSONALITY	go_langhook_eh_personality
 
diff --git a/gcc/godump.c b/gcc/godump.c
index 01f8410..888dcb0 100644
--- a/gcc/godump.c
+++ b/gcc/godump.c
@@ -496,9 +496,9 @@  go_function_decl (tree decl)
 /* A global variable decl.  */
 
 static void
-go_global_decl (tree decl, bool early)
+go_global_decl (tree decl)
 {
-  real_debug_hooks->global_decl (decl, early);
+  real_debug_hooks->late_global_decl (decl);
   go_decl (decl);
 }
 
@@ -1240,7 +1240,7 @@  dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
   go_debug_hooks.define = go_define;
   go_debug_hooks.undef = go_undef;
   go_debug_hooks.function_decl = go_function_decl;
-  go_debug_hooks.global_decl = go_global_decl;
+  go_debug_hooks.late_global_decl = go_global_decl;
   go_debug_hooks.type_decl = go_type_decl;
 
   macro_hash = htab_create (100, macro_hash_hashval, macro_hash_eq,
diff --git a/gcc/java/lang.c b/gcc/java/lang.c
index 8a68691..5cdaa15 100644
--- a/gcc/java/lang.c
+++ b/gcc/java/lang.c
@@ -142,8 +142,9 @@  struct GTY(()) language_function {
 #define LANG_HOOKS_DECL_PRINTABLE_NAME lang_printable_name
 #undef LANG_HOOKS_PRINT_ERROR_FUNCTION
 #define LANG_HOOKS_PRINT_ERROR_FUNCTION	java_print_error_function
-#undef LANG_HOOKS_WRITE_GLOBALS
-#define LANG_HOOKS_WRITE_GLOBALS java_write_globals
+/* FIXME: Add Java support.  */
+#undef LANG_HOOKS_EARLY_WRITE_GLOBALS
+#define LANG_HOOKS_EARLY_WRITE_GLOBALS java_write_globals
 
 #undef LANG_HOOKS_TYPE_FOR_MODE
 #define LANG_HOOKS_TYPE_FOR_MODE java_type_for_mode
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index e77d2d9..410690b 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -204,7 +204,8 @@  extern tree lhd_make_node (enum tree_code);
 #define LANG_HOOKS_GETDECLS	getdecls
 #define LANG_HOOKS_FUNCTION_DECL_EXPLICIT_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_EARLY_WRITE_GLOBALS early_write_global_declarations
+#define LANG_HOOKS_LATE_WRITE_GLOBALS late_write_global_declarations
 #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
@@ -228,7 +229,8 @@  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_EARLY_WRITE_GLOBALS, \
+  LANG_HOOKS_LATE_WRITE_GLOBALS, \
   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 8ff91ba..c0d7459 100644
--- a/gcc/langhooks.c
+++ b/gcc/langhooks.c
@@ -290,45 +290,48 @@  lhd_decl_ok_for_sibcall (const_tree decl ATTRIBUTE_UNUSED)
   return true;
 }
 
-/* lang_hooks.decls.final_write_globals: perform final processing on
+/* FIXME: Rewrite this to use <vec>.  Remove this eventually (see note
+   in late_write_global_declarations).  */
+static tree *globals_vec;
+static int globals_vec_len;
+
+/* lang_hooks.decls.early_write_globals: perform final processing on
    global variables.  */
 void
-write_global_declarations (void)
+early_write_global_declarations (void)
 {
-  tree globals, decl, *vec;
-  int len, i;
+  tree globals, decl;
 
-  timevar_start (TV_PHASE_DEFERRED);
   /* Really define vars that have had only a tentative definition.
      Really output inline functions that must actually be callable
      and have not been output so far.  */
 
   globals = lang_hooks.decls.getdecls ();
-  len = list_length (globals);
-  vec = XNEWVEC (tree, len);
+  globals_vec_len = list_length (globals);
+  globals_vec = XNEWVEC (tree, globals_vec_len);
 
   /* Process the decls in reverse order--earliest first.
      Put them into VEC from back to front, then take out from front.  */
+  int i;
+  for (i = 0, decl = globals; i < globals_vec_len;
+       i++, decl = DECL_CHAIN (decl))
+    globals_vec[globals_vec_len - i - 1] = decl;
 
-  for (i = 0, decl = globals; i < len; i++, decl = DECL_CHAIN (decl))
-    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);
+  wrapup_global_declarations (globals_vec, globals_vec_len);
+  check_global_declarations (globals_vec, globals_vec_len);
+}
 
-  timevar_start (TV_PHASE_DBGINFO);
-  emit_debug_global_declarations (vec, len);
-  timevar_stop (TV_PHASE_DBGINFO);
+/* lang_hooks.decls.late_write_globals: perform final processing on
+   global variables.  */
+void
+late_write_global_declarations (void)
+{
+  /* FIXME: Rewrite this to use the cgraph/varpool iterators instead
+     of globals_vec.  */
+  emit_debug_global_declarations (globals_vec, globals_vec_len);
 
   /* Clean up.  */
-  free (vec);
+  free (globals_vec);
 }
 
 /* Called to perform language-specific initialization of CTX.  */
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index 72fa85e..7e33f3a 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -181,9 +181,16 @@  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);
+  /* Obtain a list of globals and do final output on them after
+     parsing (before compilation).  This also involves outputting
+     initial debugging information after parsing.  */
+  void (*early_write_globals) (void);
+
+  /* Perform any final output of globals after compilation (cgraph
+     information is available).  This usually involves amending any
+     debugging information originally outputted by the
+     early_write_globals hook above.  */
+  void (*late_write_globals) (void);
 
   /* True if this decl may be called via a sibcall.  */
   bool (*ok_for_sibcall) (const_tree);
diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c
index 1f39949..de65854 100644
--- a/gcc/lto/lto-lang.c
+++ b/gcc/lto/lto-lang.c
@@ -1093,7 +1093,7 @@  lto_write_globals (void)
   varpool_node *vnode;
   FOR_EACH_DEFINED_VARIABLE (vnode)
     if (!decl_function_context (vnode->decl))
-      debug_hooks->global_decl (vnode->decl, /*early=*/false);
+      debug_hooks->late_global_decl (vnode->decl);
 }
 
 static tree
@@ -1275,8 +1275,10 @@  static void lto_init_ts (void)
 #define LANG_HOOKS_PUSHDECL lto_pushdecl
 #undef LANG_HOOKS_GETDECLS
 #define LANG_HOOKS_GETDECLS lto_getdecls
-#undef LANG_HOOKS_WRITE_GLOBALS
-#define LANG_HOOKS_WRITE_GLOBALS lto_write_globals
+#undef LANG_HOOKS_EARLY_WRITE_GLOBALS
+#define LANG_HOOKS_EARLY_WRITE_GLOBALS debug_nothing_void
+#undef LANG_HOOKS_LATE_WRITE_GLOBALS
+#define LANG_HOOKS_LATE_WRITE_GLOBALS lto_write_globals
 #undef LANG_HOOKS_REGISTER_BUILTIN_TYPE
 #define LANG_HOOKS_REGISTER_BUILTIN_TYPE lto_register_builtin_type
 #undef LANG_HOOKS_BUILTIN_FUNCTION
diff --git a/gcc/toplev.c b/gcc/toplev.c
index ceefa1b..151bc04 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -532,7 +532,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], /*early=*/false);
+    debug_hooks->late_global_decl (vec[i]);
   timevar_pop (TV_SYMOUT);
 }
 
@@ -560,8 +560,20 @@  compile_file (void)
 
   ggc_protect_identifiers = false;
 
-  /* This must also call finalize_compilation_unit.  */
-  lang_hooks.decls.final_write_globals ();
+  /* Emit early debugging information as well as globals.  */
+  timevar_start (TV_PHASE_DEFERRED);
+  lang_hooks.decls.early_write_globals ();
+  timevar_stop (TV_PHASE_DEFERRED);
+
+  /* We're done parsing; proceed to optimize and emit assembly.  */
+  timevar_start (TV_PHASE_OPT_GEN);
+  symtab->finalize_compilation_unit ();
+  timevar_stop (TV_PHASE_OPT_GEN);
+
+  /* Amend any debugging information generated previously.  */
+  timevar_start (TV_PHASE_DBGINFO);
+  lang_hooks.decls.late_write_globals ();
+  timevar_stop (TV_PHASE_DBGINFO);
 
   if (seen_error ())
     return;
diff --git a/gcc/toplev.h b/gcc/toplev.h
index 1b54578..807b3f1 100644
--- a/gcc/toplev.h
+++ b/gcc/toplev.h
@@ -43,7 +43,6 @@  extern bool wrapup_global_declarations (tree *, int);
 extern void check_global_declaration_1 (tree);
 extern void check_global_declarations (tree *, int);
 extern void emit_debug_global_declarations (tree *, int);
-extern void write_global_declarations (void);
 
 extern void dump_memory_report (bool);
 extern void dump_profile_report (void);