diff mbox

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

Message ID 5412438A.6030305@redhat.com
State New
Headers show

Commit Message

Aldy Hernandez Sept. 12, 2014, 12:51 a.m. UTC
On 09/09/14 02:16, Richard Biener wrote:
> On Tue, Sep 9, 2014 at 2:00 AM, Aldy Hernandez <aldyh@redhat.com> wrote:
>> On 09/05/14 02:00, Richard Biener wrote:

>> 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).

Done.

>>
>> 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.

Done.

>
> 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().

Done.

>
> 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.

Done.  For now I've called it 
LANG_HOOK_POST_COMPILATION_PARSING_CLEANUPS, and it is only applicable 
to C++, unless some other FE acts up in the process and needs similar 
massaging.

> Maybe Jason can help cleaning this up.

Jason's not much of a beer drinker AFAICT, so I'm trying to come up with 
a suitable bribe.

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

Done.

[Well... as DONE as a prototype can be :).  This is a work in progress, 
but I'd like y'all to peek at it, to make sure I'm not making obvious 
wrong turns that will have me rewriting code months from now, and hating 
you in the process.  And by you, I mean Jason *and* you.  I don't want 
anyone to feel left out by my frustration and anger.]

I drafted what I want Ada, Java, Fortran, and Go to look like (as well 
as the obvious C/C++ languages).

For C, guality.exp exhibits less failures than mainline.  I'm currently 
debugging inline virtual C++ destructors.  It seems the inliner can also 
call generate debugging info (debug_hooks->outlining_inline_function). 
The rest of the languages are tested as far as building jc1/f951/go1 
with no warnings :-))).

There are various cleanups and comments along the way.

Let me know if you're "mostly" OK with this, so I can push this to the 
branch and continue iterating with you incrementally.  It seems there 
will be no shortage of weird bugs in dwarf generation due to the fact 
that we stream early.  I'm hoping to start concentrating on those...

As usual, thanks.
Aldy

Comments

Richard Biener Sept. 12, 2014, 8:12 a.m. UTC | #1
On Fri, Sep 12, 2014 at 2:51 AM, Aldy Hernandez <aldyh@redhat.com> wrote:
> On 09/09/14 02:16, Richard Biener wrote:
>>
>> On Tue, Sep 9, 2014 at 2:00 AM, Aldy Hernandez <aldyh@redhat.com> wrote:
>>>
>>> On 09/05/14 02:00, Richard Biener wrote:
>
>
>>> 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).
>
>
> Done.
>
>>>
>>> 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.
>
>
> Done.
>
>>
>> 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().
>
>
> Done.
>
>>
>> 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.
>
>
> Done.  For now I've called it LANG_HOOK_POST_COMPILATION_PARSING_CLEANUPS,
> and it is only applicable to C++, unless some other FE acts up in the
> process and needs similar massaging.
>
>> Maybe Jason can help cleaning this up.
>
>
> Jason's not much of a beer drinker AFAICT, so I'm trying to come up with a
> suitable bribe.

I'm sure you can come up with something ;)

>>
>>> 4. FOR_EACH_DEFINED_SYMBOL (node)
>>>       debug_hooks->late_global_decl (node->decl)
>>>
>>>     as suggested.
>
>
> Done.
>
> [Well... as DONE as a prototype can be :).  This is a work in progress, but
> I'd like y'all to peek at it, to make sure I'm not making obvious wrong
> turns that will have me rewriting code months from now, and hating you in
> the process.  And by you, I mean Jason *and* you.  I don't want anyone to
> feel left out by my frustration and anger.]
>
> I drafted what I want Ada, Java, Fortran, and Go to look like (as well as
> the obvious C/C++ languages).
>
> For C, guality.exp exhibits less failures than mainline.  I'm currently
> debugging inline virtual C++ destructors.  It seems the inliner can also
> call generate debugging info (debug_hooks->outlining_inline_function). The
> rest of the languages are tested as far as building jc1/f951/go1 with no
> warnings :-))).
>
> There are various cleanups and comments along the way.
>
> Let me know if you're "mostly" OK with this, so I can push this to the
> branch and continue iterating with you incrementally.  It seems there will
> be no shortage of weird bugs in dwarf generation due to the fact that we
> stream early.  I'm hoping to start concentrating on those...

Yeah, it looks very good.  Let's cross fingers that it'll work ;)

Thanks,
Richard.

> As usual, thanks.
> Aldy
Jason Merrill Sept. 12, 2014, 3:15 p.m. UTC | #2
On 09/11/2014 08:51 PM, Aldy Hernandez wrote:
> -  timevar_start (TV_PHASE_DEFERRED);

> -  timevar_stop (TV_PHASE_DEFERRED);
> -  timevar_start (TV_PHASE_OPT_GEN);

Why?

>    /* Generate hidden aliases for Java.  */
> -  if (candidates)
> +  if (java_hidden_aliases)
>      {
> -      build_java_method_aliases (candidates);
> -      delete candidates;
> +      build_java_method_aliases (java_hidden_aliases);
> +      delete java_hidden_aliases;
>      }

Didn't it work to move this before finalize?  I think the VTV stuff is 
all that really needs to come after it, and that can move out of the 
front end if this hook is a problem (which I don't really think it is).

Jason
Aldy Hernandez Sept. 12, 2014, 5:10 p.m. UTC | #3
On 09/12/14 08:15, Jason Merrill wrote:
> On 09/11/2014 08:51 PM, Aldy Hernandez wrote:
>> -  timevar_start (TV_PHASE_DEFERRED);
>
>> -  timevar_stop (TV_PHASE_DEFERRED);
>> -  timevar_start (TV_PHASE_OPT_GEN);
>
> Why?

TV_PHASE_OPT_GEN is now in compile_file(), where we call 
finalize_compilation_unit directly.

TV_PHASE_DEFERRED, on the other hand, is a bit problematic because it 
was originally wrapping the code inside LANG_HOOKS_WRITE_GLOBALS, which 
will now reside inside the parser (and is thus included in 
TV_PHASE_PARSING now).  Originally it was mutually exclusive with 
TV_PHASE_PARSING, but now resides within the parser, so I decided to get 
rid of it since it's all technically in the parser.

There is code in timevar*.c that makes sure that TV_PHASE_* elapsed 
times add up to the total time.  So we either get rid of 
TV_PHASE_DEFERRED and include its time in TV_PHASE_PARSING (avoiding 
double counting), or we include a separate, non PHASE timer for it, with 
timevar_push(TV_blah) where "blah" is NOT "PHASE".

Up to you, but I'm highly in favor of getting rid of things ;-).

>
>>    /* Generate hidden aliases for Java.  */
>> -  if (candidates)
>> +  if (java_hidden_aliases)
>>      {
>> -      build_java_method_aliases (candidates);
>> -      delete candidates;
>> +      build_java_method_aliases (java_hidden_aliases);
>> +      delete java_hidden_aliases;
>>      }
>
> Didn't it work to move this before finalize?  I think the VTV stuff is
> all that really needs to come after it, and that can move out of the
> front end if this hook is a problem (which I don't really think it is).

I was too chicken to try.  I will do so as a follow up.

I am committing the patch to the branch, and will address both issues 
you speak of in followups.  Let me know what you prefer for the timevar 
issue.

Thanks.
Aldy
Jason Merrill Sept. 12, 2014, 5:33 p.m. UTC | #4
On 09/12/2014 01:10 PM, Aldy Hernandez wrote:
> TV_PHASE_DEFERRED, on the other hand, is a bit problematic because it
> was originally wrapping the code inside LANG_HOOKS_WRITE_GLOBALS, which
> will now reside inside the parser (and is thus included in
> TV_PHASE_PARSING now).  Originally it was mutually exclusive with
> TV_PHASE_PARSING, but now resides within the parser, so I decided to get
> rid of it since it's all technically in the parser.
>
> There is code in timevar*.c that makes sure that TV_PHASE_* elapsed
> times add up to the total time.  So we either get rid of
> TV_PHASE_DEFERRED and include its time in TV_PHASE_PARSING (avoiding
> double counting), or we include a separate, non PHASE timer for it, with
> timevar_push(TV_blah) where "blah" is NOT "PHASE".

Why can't it keep the same name and just timevar_push/pop instead of 
timevar_start/stop?

Jason
Aldy Hernandez Sept. 12, 2014, 5:48 p.m. UTC | #5
On 09/12/14 10:33, Jason Merrill wrote:
> On 09/12/2014 01:10 PM, Aldy Hernandez wrote:
>> TV_PHASE_DEFERRED, on the other hand, is a bit problematic because it
>> was originally wrapping the code inside LANG_HOOKS_WRITE_GLOBALS, which
>> will now reside inside the parser (and is thus included in
>> TV_PHASE_PARSING now).  Originally it was mutually exclusive with
>> TV_PHASE_PARSING, but now resides within the parser, so I decided to get
>> rid of it since it's all technically in the parser.
>>
>> There is code in timevar*.c that makes sure that TV_PHASE_* elapsed
>> times add up to the total time.  So we either get rid of
>> TV_PHASE_DEFERRED and include its time in TV_PHASE_PARSING (avoiding
>> double counting), or we include a separate, non PHASE timer for it, with
>> timevar_push(TV_blah) where "blah" is NOT "PHASE".
>
> Why can't it keep the same name and just timevar_push/pop instead of
> timevar_start/stop?

Unless I'm misunderstanding something, validate_phases() verifies that 
the numbers add up by looking at the actual string name of the phase, 
irregardless of if you timevar_push/pop'ed it:

	static char phase_prefix[] = "phase ";
	...
	if (strncmp (tv->name, phase_prefix, sizeof phase_prefix - 1)

I could timevar_push/pop it but we'd have to change the name:

DEFTIMEVAR (TV_PHASE_DEFERRED        , "phase lang. deferred")

Did I miss something?
Aldy
Jason Merrill Sept. 12, 2014, 5:56 p.m. UTC | #6
On 09/12/2014 01:48 PM, Aldy Hernandez wrote:
> Unless I'm misunderstanding something, validate_phases() verifies that
> the numbers add up by looking at the actual string name of the phase,
> irregardless of if you timevar_push/pop'ed it:

Yes, but why wouldn't the numbers add up?  The comment for 
timevar_push_1 says "No further elapsed time is attributed to the 
previous topmost timing variable on the stack; subsequent elapsed time 
is attributed to TIMEVAR, until it is popped or another element is 
pushed on top."

Jason
Richard Biener Sept. 15, 2014, 9:32 a.m. UTC | #7
On Fri, Sep 12, 2014 at 7:10 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
> On 09/12/14 08:15, Jason Merrill wrote:
>>
>> On 09/11/2014 08:51 PM, Aldy Hernandez wrote:
>>>
>>> -  timevar_start (TV_PHASE_DEFERRED);
>>
>>
>>> -  timevar_stop (TV_PHASE_DEFERRED);
>>> -  timevar_start (TV_PHASE_OPT_GEN);
>>
>>
>> Why?
>
>
> TV_PHASE_OPT_GEN is now in compile_file(), where we call
> finalize_compilation_unit directly.
>
> TV_PHASE_DEFERRED, on the other hand, is a bit problematic because it was
> originally wrapping the code inside LANG_HOOKS_WRITE_GLOBALS, which will now
> reside inside the parser (and is thus included in TV_PHASE_PARSING now).
> Originally it was mutually exclusive with TV_PHASE_PARSING, but now resides
> within the parser, so I decided to get rid of it since it's all technically
> in the parser.
>
> There is code in timevar*.c that makes sure that TV_PHASE_* elapsed times
> add up to the total time.  So we either get rid of TV_PHASE_DEFERRED and
> include its time in TV_PHASE_PARSING (avoiding double counting), or we
> include a separate, non PHASE timer for it, with timevar_push(TV_blah) where
> "blah" is NOT "PHASE".
>
> Up to you, but I'm highly in favor of getting rid of things ;-).
>
>>
>>>    /* Generate hidden aliases for Java.  */
>>> -  if (candidates)
>>> +  if (java_hidden_aliases)
>>>      {
>>> -      build_java_method_aliases (candidates);
>>> -      delete candidates;
>>> +      build_java_method_aliases (java_hidden_aliases);
>>> +      delete java_hidden_aliases;
>>>      }
>>
>>
>> Didn't it work to move this before finalize?  I think the VTV stuff is
>> all that really needs to come after it, and that can move out of the
>> front end if this hook is a problem (which I don't really think it is).
>
>
> I was too chicken to try.  I will do so as a follow up.

Didn't work in the past btw - I've tried it once or twice.

Btw, if the VTV stuff really needs to come afterwards how does VTV
work with LTO then?

Eventually the VTV stuff can be integrated with the cgraph instead.

Richard.

> I am committing the patch to the branch, and will address both issues you
> speak of in followups.  Let me know what you prefer for the timevar issue.
>
> Thanks.
> Aldy
>
Jason Merrill Sept. 15, 2014, 6:46 p.m. UTC | #8
On 09/15/2014 05:32 AM, Richard Biener wrote:
> Btw, if the VTV stuff really needs to come afterwards how does VTV
> work with LTO then?

It's conservatively correct: it emits information for all the vtables 
that are actually generated for the TU.  If LTO optimizes some of them 
away, the VTV information is not updated, but that only means a missed 
optimization.

> Eventually the VTV stuff can be integrated with the cgraph instead.

That would be ideal, yes.

Jason
Aldy Hernandez Dec. 18, 2014, 7:23 p.m. UTC | #9
Hi Jason.

It's embarrassing that I just got to this now.  I hope you don't repay 
the favor and take as long responding to me :(.

On 09/12/14 08:15, Jason Merrill wrote:
> On 09/11/2014 08:51 PM, Aldy Hernandez wrote:

>>    /* Generate hidden aliases for Java.  */
>> -  if (candidates)
>> +  if (java_hidden_aliases)
>>      {
>> -      build_java_method_aliases (candidates);
>> -      delete candidates;
>> +      build_java_method_aliases (java_hidden_aliases);
>> +      delete java_hidden_aliases;
>>      }
>
> Didn't it work to move this before finalize?  I think the VTV stuff is
> all that really needs to come after it, and that can move out of the
> front end if this hook is a problem (which I don't really think it is).

I can't move the call to build_java_method_aliases until the compilation 
proper has run because said function iterates through all the functions 
with FOR_EACH_FUNCTION, and the set of available functions at parse time 
and after the optimization passes are quite different, presumably 
because we've pruned all the unused functions.

If I move the call to build_java_method_aliases before the optimization 
passes, we end up emitting many more hidden aliases which cause 
handle_alias_pairs() in cgraphunit.c to bark with:

error: 'void _ZGAN8__JArrayC4Ev()' aliased to external symbol 
'_ZN8__JArrayC4Ev'

So we either leave building Java method aliases after the optimization 
passes, or we somehow tighten the candidate selection in 
collect_candidates_for_java_method_aliases():

       if (DECL_CLASS_SCOPE_P (fndecl)
	  && TYPE_FOR_JAVA (DECL_CONTEXT (fndecl))
	  && TARGET_USE_LOCAL_THUNK_ALIAS_P (fndecl))

What do you suggest?

I can, however, move all the other non-VTV stuff to the parser in a 
subsequent patch, while you respond to this query.

Thanks.
Aldy
Richard Biener Dec. 19, 2014, 11:11 a.m. UTC | #10
On Thu, Dec 18, 2014 at 8:23 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
> Hi Jason.
>
> It's embarrassing that I just got to this now.  I hope you don't repay the
> favor and take as long responding to me :(.
>
> On 09/12/14 08:15, Jason Merrill wrote:
>>
>> On 09/11/2014 08:51 PM, Aldy Hernandez wrote:
>
>
>>>    /* Generate hidden aliases for Java.  */
>>> -  if (candidates)
>>> +  if (java_hidden_aliases)
>>>      {
>>> -      build_java_method_aliases (candidates);
>>> -      delete candidates;
>>> +      build_java_method_aliases (java_hidden_aliases);
>>> +      delete java_hidden_aliases;
>>>      }
>>
>>
>> Didn't it work to move this before finalize?  I think the VTV stuff is
>> all that really needs to come after it, and that can move out of the
>> front end if this hook is a problem (which I don't really think it is).
>
>
> I can't move the call to build_java_method_aliases until the compilation
> proper has run because said function iterates through all the functions with
> FOR_EACH_FUNCTION, and the set of available functions at parse time and
> after the optimization passes are quite different, presumably because we've
> pruned all the unused functions.
>
> If I move the call to build_java_method_aliases before the optimization
> passes, we end up emitting many more hidden aliases which cause
> handle_alias_pairs() in cgraphunit.c to bark with:
>
> error: 'void _ZGAN8__JArrayC4Ev()' aliased to external symbol
> '_ZN8__JArrayC4Ev'
>
> So we either leave building Java method aliases after the optimization
> passes, or we somehow tighten the candidate selection in
> collect_candidates_for_java_method_aliases():
>
>       if (DECL_CLASS_SCOPE_P (fndecl)
>           && TYPE_FOR_JAVA (DECL_CONTEXT (fndecl))
>           && TARGET_USE_LOCAL_THUNK_ALIAS_P (fndecl))
>
> What do you suggest?

Yeah, I've told you that this is a major blocker I couldn't resolve the last
time I tried to move things.

IMHO this Java method aliases needs to be made cgraph-aware somehow,
thus we need to build the aliases as proper aliases during candidate
collection but somehow mark them reclaimable by the cgraph code
(builtding the aliases is only done if TREE_ASM_WRITTEN).

Honza may have an idea here?

Richard.

> I can, however, move all the other non-VTV stuff to the parser in a
> subsequent patch, while you respond to this query.
>
> Thanks.
> Aldy
Jan Hubicka Dec. 19, 2014, 6:53 p.m. UTC | #11
> 
> Yeah, I've told you that this is a major blocker I couldn't resolve the last
> time I tried to move things.
> 
> IMHO this Java method aliases needs to be made cgraph-aware somehow,
> thus we need to build the aliases as proper aliases during candidate
> collection but somehow mark them reclaimable by the cgraph code
> (builtding the aliases is only done if TREE_ASM_WRITTEN).
> 
> Honza may have an idea here?

Hmm, would you mind explain me what are Java method aliases?
Making alias removed when unused would probably require extra flag (as you can
not make comdat alias of non-comdat symbol) but should be easy to do.

honza
> 
> Richard.
> 
> > I can, however, move all the other non-VTV stuff to the parser in a
> > subsequent patch, while you respond to this query.
> >
> > Thanks.
> > Aldy
Jan Hubicka Dec. 19, 2014, 6:58 p.m. UTC | #12
> > 
> > Yeah, I've told you that this is a major blocker I couldn't resolve the last
> > time I tried to move things.
> > 
> > IMHO this Java method aliases needs to be made cgraph-aware somehow,
> > thus we need to build the aliases as proper aliases during candidate
> > collection but somehow mark them reclaimable by the cgraph code
> > (builtding the aliases is only done if TREE_ASM_WRITTEN).
> > 
> > Honza may have an idea here?
> 
> Hmm, would you mind explain me what are Java method aliases?
> Making alias removed when unused would probably require extra flag (as you can
> not make comdat alias of non-comdat symbol) but should be easy to do.

Looking at the code, making Java aliases to be output at the same time we output
thunks in C++ may just work....

Honza
> 
> honza
> > 
> > Richard.
> > 
> > > I can, however, move all the other non-VTV stuff to the parser in a
> > > subsequent patch, while you respond to this query.
> > >
> > > Thanks.
> > > Aldy
Aldy Hernandez Dec. 19, 2014, 7:01 p.m. UTC | #13
On 12/19/14 10:58, Jan Hubicka wrote:
>>>
>>> Yeah, I've told you that this is a major blocker I couldn't resolve the last
>>> time I tried to move things.
>>>
>>> IMHO this Java method aliases needs to be made cgraph-aware somehow,
>>> thus we need to build the aliases as proper aliases during candidate
>>> collection but somehow mark them reclaimable by the cgraph code
>>> (builtding the aliases is only done if TREE_ASM_WRITTEN).
>>>
>>> Honza may have an idea here?
>>
>> Hmm, would you mind explain me what are Java method aliases?
>> Making alias removed when unused would probably require extra flag (as you can
>> not make comdat alias of non-comdat symbol) but should be easy to do.
>
> Looking at the code, making Java aliases to be output at the same time we output
> thunks in C++ may just work....

Can you elaborate on this?  Sorry, this is an area I'm largely 
unfamiliar with.

Thanks.
Aldy
Aldy Hernandez Dec. 19, 2014, 7:02 p.m. UTC | #14
On 12/19/14 10:53, Jan Hubicka wrote:
>>
>> Yeah, I've told you that this is a major blocker I couldn't resolve the last
>> time I tried to move things.
>>
>> IMHO this Java method aliases needs to be made cgraph-aware somehow,
>> thus we need to build the aliases as proper aliases during candidate
>> collection but somehow mark them reclaimable by the cgraph code
>> (builtding the aliases is only done if TREE_ASM_WRITTEN).
>>
>> Honza may have an idea here?
>
> Hmm, would you mind explain me what are Java method aliases?
> Making alias removed when unused would probably require extra flag (as you can

Actually, this was my gut reaction solution.

Aldy
Jason Merrill Dec. 19, 2014, 7:03 p.m. UTC | #15
It looks like java aliases are still using assemble_alias directly; 
switching to using same_body aliases like thunks and such should handle 
the issue.

Jason
Jan Hubicka Dec. 19, 2014, 7:48 p.m. UTC | #16
> It looks like java aliases are still using assemble_alias directly;

assemble_alias dispatch to code adding alias pair to callgarph, so that should
be safe.  My understanding is that Aldys concern is that creating the aliases
early leads to undefined symbol because we produce aliases that never get their
function bodies output by FE.

> switching to using same_body aliases like thunks and such should
> handle the issue.

Yes, I think producing java alias at the same time we produce same_body alias should just work
(not that I would like the same body alias machinery - it is major pain to see these appearing
at random time from DECL_ASSEMBLER_NAME hook)

Honza
> 
> Jason
diff mbox

Patch

diff --git a/gcc/ada/gcc-interface/misc.c b/gcc/ada/gcc-interface/misc.c
index 240ca44..44af75f 100644
--- a/gcc/ada/gcc-interface/misc.c
+++ b/gcc/ada/gcc-interface/misc.c
@@ -105,6 +105,10 @@  gnat_parse_file (void)
 
   /* Call the front end.  */
   _ada_gnat1drv ();
+
+  /* Output global declarations and generate debug information for
+     them.  */
+  gnat_write_global_declarations ();
 }
 
 /* Return language mask for option processing.  */
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index 266a942..fb187a6 100644
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -5178,27 +5178,9 @@  gnat_write_global_declarations (void)
 	}
     }
 
-  /* Output debug information for all global type declarations first.  This
-     ensures that global types whose compilation hasn't been finalized yet,
-     for example pointers to Taft amendment types, have their compilation
-     finalized in the right context.  */
   FOR_EACH_VEC_SAFE_ELT (global_decls, i, iter)
     if (TREE_CODE (iter) == TYPE_DECL && !DECL_IGNORED_P (iter))
-      debug_hooks->global_decl (iter);
-
-  /* Proceed to optimize and emit assembly. */
-  symtab->finalize_compilation_unit ();
-
-  /* After cgraph has had a chance to emit everything that's going to
-     be emitted, output debug information for the rest of globals.  */
-  if (!seen_error ())
-    {
-      timevar_push (TV_SYMOUT);
-      FOR_EACH_VEC_SAFE_ELT (global_decls, i, iter)
-	if (TREE_CODE (iter) != TYPE_DECL && !DECL_IGNORED_P (iter))
-	  debug_hooks->global_decl (iter);
-      timevar_pop (TV_SYMOUT);
-    }
+      debug_hooks->early_global_decl (iter);
 }
 
 /* ************************************************************************
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 993a97b..1f5d557 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -847,6 +847,8 @@  extern HOST_WIDE_INT c_common_to_target_charset (HOST_WIDE_INT);
 /* This is the basic parsing function.  */
 extern void c_parse_file (void);
 
+extern void c_parse_final_cleanups (void);
+
 extern void warn_for_omitted_condop (location_t, tree);
 
 /* These macros provide convenient access to the various _STMT nodes.  */
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index 7486691..fac25cc 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -1070,6 +1070,9 @@  c_common_parse_file (void)
       if (!this_input_filename)
 	break;
     }
+
+  if (!flag_syntax_only)
+    c_parse_final_cleanups ();
 }
 
 /* Returns the appropriate dump file for PHASE to dump with FLAGS.  */
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 1e09404..a0a047f 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -10270,9 +10270,8 @@  finish_declspecs (struct c_declspecs *specs)
   return specs;
 }
 
-/* A subroutine of c_write_global_declarations.  Perform final processing
-   on one file scope's declarations (or the external scope's declarations),
-   GLOBALS.  */
+/* Perform final processing on one file scope's declarations (or the
+   external scope's declarations), GLOBALS.  */
 
 static void
 c_write_global_declarations_1 (tree globals)
@@ -10310,22 +10309,10 @@  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);
     }
 }
 
-/* A subroutine of c_write_global_declarations Emit debug information for each
-   of the declarations in GLOBALS.  */
-
-static void
-c_write_global_declarations_2 (tree globals)
-{
-  tree decl;
-
-  for (decl = globals; decl ; decl = DECL_CHAIN (decl))
-    debug_hooks->global_decl (decl, /*early=*/false);
-}
-
 /* Callback to collect a source_ref from a DECL.  */
 
 static void
@@ -10373,8 +10360,11 @@  for_each_global_decl (void (*callback) (tree decl))
     callback (decl);
 }
 
+/* Perform any final parser cleanups and generate initial debugging
+   information.  */
+
 void
-c_write_global_declarations (void)
+c_parse_final_cleanups (void)
 {
   tree t;
   unsigned i;
@@ -10383,8 +10373,6 @@  c_write_global_declarations (void)
   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).  */
@@ -10426,29 +10414,7 @@  c_write_global_declarations (void)
     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);
-
-  /* After cgraph has had a chance to emit everything that's going to
-     be emitted, output debug information for globals.  */
-  if (!seen_error ())
-    {
-      timevar_push (TV_SYMOUT);
-      FOR_EACH_VEC_ELT (*all_translation_units, i, t)
-	c_write_global_declarations_2 (BLOCK_VARS (DECL_INITIAL (t)));
-      c_write_global_declarations_2 (BLOCK_VARS (ext_block));
-      timevar_pop (TV_SYMOUT);
-    }
-
   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..8ab4e67 100644
--- a/gcc/c/c-objc-common.h
+++ b/gcc/c/c-objc-common.h
@@ -92,8 +92,6 @@  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
 
 /* 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..7586813 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -669,7 +669,6 @@  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 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..c78e808 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -83,8 +83,8 @@  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
+#undef LANG_HOOKS_POST_COMPILATION_PARSING_CLEANUPS
+#define LANG_HOOKS_POST_COMPILATION_PARSING_CLEANUPS cxx_post_compilation_parsing_cleanups
 #undef  LANG_HOOKS_BUILTIN_FUNCTION
 #define LANG_HOOKS_BUILTIN_FUNCTION cxx_builtin_function
 #undef  LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 19f5232..053058a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5370,7 +5370,7 @@  extern tree cp_reconstruct_complex_type		(tree, tree);
 extern bool attributes_naming_typedef_ok	(tree);
 extern void cplus_decl_attributes		(tree *, tree, int);
 extern void finish_anon_union			(tree);
-extern void cp_write_global_declarations	(void);
+extern void cxx_post_compilation_parsing_cleanups (void);
 extern tree coerce_new_type			(tree);
 extern tree coerce_delete_type			(tree);
 extern void comdat_linkage			(tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index d8fb35e..8d6913c 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -866,30 +866,19 @@  walk_namespaces (walk_namespaces_fn f, void* data)
   return walk_namespaces_r (global_namespace, f, data);
 }
 
-/* Call wrapup_globals_declarations for the globals in NAMESPACE.  If
-   DATA is non-NULL, this is the last time we will call
-   wrapup_global_declarations for this NAMESPACE.  */
+/* Call wrapup_globals_declarations for the globals in NAMESPACE.  */
 
 int
-wrapup_globals_for_namespace (tree name_space, void* data)
+wrapup_globals_for_namespace (tree name_space, void* data ATTRIBUTE_UNUSED)
 {
   cp_binding_level *level = NAMESPACE_LEVEL (name_space);
   vec<tree, va_gc> *statics = level->static_decls;
   tree *vec = statics->address ();
   int len = statics->length ();
-  int last_time = (data != 0);
-
-  if (last_time)
-    {
-      check_global_declarations (vec, len);
-      emit_debug_global_declarations (vec, len);
-      return 0;
-    }
 
   /* Write out any globals that need to be output.  */
   return wrapup_global_declarations (vec, len);
 }
-
 
 /* In C++, you don't have to write `struct S' to refer to `S'; you
    can just use `S'.  We accomplish this by creating a TYPE_DECL as
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 4be4847..28bf6e4 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -4286,24 +4286,43 @@  dump_tu (void)
     }
 }
 
+/* Issue warnings for globals in NAME_SPACE (unused statics, etc) and
+   generate debug information for said globals.  */
+
+static int
+emit_debug_for_namespace (tree name_space, void* data ATTRIBUTE_UNUSED)
+{
+  cp_binding_level *level = NAMESPACE_LEVEL (name_space);
+  vec<tree, va_gc> *statics = level->static_decls;
+  tree *vec = statics->address ();
+  int len = statics->length ();
+
+  check_global_declarations (vec, len);
+  emit_debug_global_declarations (vec, len, EMIT_DEBUG_EARLY);
+  return 0;
+}
+
+/* Candidates for Java hidden aliases.  */
+static hash_set<tree> *java_hidden_aliases;
+
+static location_t locus_at_end_of_parsing;
+
 /* This routine is called at the end of compilation.
    Its job is to create all the code needed to initialize and
    destroy the global aggregates.  We do the destruction
    first, since that way we only need to reverse the decls once.  */
 
 void
-cp_write_global_declarations (void)
+c_parse_final_cleanups (void)
 {
   tree vars;
   bool reconsider;
   size_t i;
-  location_t locus;
   unsigned ssdf_count = 0;
   int retries = 0;
   tree decl;
-  hash_set<tree> *candidates;
 
-  locus = input_location;
+  locus_at_end_of_parsing = input_location;
   at_eof = 1;
 
   /* Bad parse errors.  Just forget about it.  */
@@ -4335,8 +4354,6 @@  cp_write_global_declarations (void)
 
   /* FIXME - huh?  was  input_line -= 1;*/
 
-  timevar_start (TV_PHASE_DEFERRED);
-
   /* We now have to write out all the stuff we put off writing out.
      These include:
 
@@ -4432,7 +4449,7 @@  cp_write_global_declarations (void)
 
 	  /* Set the line and file, so that it is obviously not from
 	     the source file.  */
-	  input_location = locus;
+	  input_location = locus_at_end_of_parsing;
 	  ssdf_body = start_static_storage_duration_function (ssdf_count);
 
 	  /* Make sure the back end knows about all the variables.  */
@@ -4458,7 +4475,7 @@  cp_write_global_declarations (void)
 
 	  /* Finish up the static storage duration function for this
 	     round.  */
-	  input_location = locus;
+	  input_location = locus_at_end_of_parsing;
 	  finish_static_storage_duration_function (ssdf_body);
 
 	  /* All those initializations and finalizations might cause
@@ -4466,7 +4483,7 @@  cp_write_global_declarations (void)
 	     instantiations, etc.  */
 	  reconsider = true;
 	  ssdf_count++;
-	  /* ??? was:  locus.line++; */
+	  /* ??? was:  locus_at_end_of_parsing.line++; */
 	}
 
       /* Now do the same for thread_local variables.  */
@@ -4632,12 +4649,13 @@  cp_write_global_declarations (void)
   if (priority_info_map)
     splay_tree_foreach (priority_info_map,
 			generate_ctor_and_dtor_functions_for_priority,
-			/*data=*/&locus);
+			/*data=*/&locus_at_end_of_parsing);
   else if (c_dialect_objc () && objc_static_init_needed_p ())
     /* If this is obj-c++ and we need a static init, call
        generate_ctor_or_dtor_function.  */
     generate_ctor_or_dtor_function (/*constructor_p=*/true,
-				    DEFAULT_INIT_PRIORITY, &locus);
+				    DEFAULT_INIT_PRIORITY,
+				    &locus_at_end_of_parsing);
 
   /* We're done with the splay-tree now.  */
   if (priority_info_map)
@@ -4651,10 +4669,7 @@  cp_write_global_declarations (void)
   pop_lang_context ();
 
   /* Collect candidates for Java hidden aliases.  */
-  candidates = collect_candidates_for_java_method_aliases ();
-
-  timevar_stop (TV_PHASE_DEFERRED);
-  timevar_start (TV_PHASE_OPT_GEN);
+  java_hidden_aliases = collect_candidates_for_java_method_aliases ();
 
   if (flag_vtable_verify)
     {
@@ -4663,7 +4678,28 @@  cp_write_global_declarations (void)
       vtv_build_vtable_verify_fndecl ();
     }
 
-  symtab->finalize_compilation_unit ();
+  /* Issue warnings about static, but not defined, functions, etc, and
+     generate initial debug information.  */
+  walk_namespaces (emit_debug_for_namespace, 0);
+  if (vec_safe_length (pending_statics) != 0)
+    {
+      check_global_declarations (pending_statics->address (),
+				 pending_statics->length ());
+      emit_debug_global_declarations (pending_statics->address (),
+				      pending_statics->length (),
+				      EMIT_DEBUG_EARLY);
+    }
+
+}
+
+/* Perform any post compilation-proper cleanups for the C++ front-end.
+   This should really go away.  No front-end should need to do
+   anything past the compilation process.  */
+
+void
+cxx_post_compilation_parsing_cleanups (void)
+{
+  timevar_start (TV_PHASE_LATE_PARSING_CLEANUPS);
 
   if (flag_vtable_verify)
     {
@@ -4675,27 +4711,13 @@  cp_write_global_declarations (void)
       vtv_generate_init_routine ();
     }
 
-  timevar_stop (TV_PHASE_OPT_GEN);
-  timevar_start (TV_PHASE_CHECK_DBGINFO);
-
-  /* Now, issue warnings about static, but not defined, functions,
-     etc., and emit debugging information.  */
-  walk_namespaces (wrapup_globals_for_namespace, /*data=*/&reconsider);
-  if (vec_safe_length (pending_statics) != 0)
-    {
-      check_global_declarations (pending_statics->address (),
-				 pending_statics->length ());
-      emit_debug_global_declarations (pending_statics->address (),
-				      pending_statics->length ());
-    }
-
   perform_deferred_noexcept_checks ();
 
   /* Generate hidden aliases for Java.  */
-  if (candidates)
+  if (java_hidden_aliases)
     {
-      build_java_method_aliases (candidates);
-      delete candidates;
+      build_java_method_aliases (java_hidden_aliases);
+      delete java_hidden_aliases;
     }
 
   finish_repo ();
@@ -4709,13 +4731,13 @@  cp_write_global_declarations (void)
       dump_tree_statistics ();
       dump_time_statistics ();
     }
-  input_location = locus;
+  input_location = locus_at_end_of_parsing;
 
 #ifdef ENABLE_CHECKING
   validate_conversion_obstack ();
 #endif /* ENABLE_CHECKING */
 
-  timevar_stop (TV_PHASE_CHECK_DBGINFO);
+  timevar_stop (TV_PHASE_LATE_PARSING_CLEANUPS);
 }
 
 /* FN is an OFFSET_REF, DOTSTAR_EXPR or MEMBER_REF indicating the
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 45b3b99..92c218f 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -3859,7 +3859,7 @@  do_namespace_alias (tree alias, tree name_space)
 
   /* Emit debug info for namespace alias.  */
   if (!building_stmt_list_p ())
-    (*debug_hooks->global_decl) (alias, /*early=*/false);
+    (*debug_hooks->early_global_decl) (alias);
 }
 
 /* Like pushdecl, only it places X in the current namespace,
diff --git a/gcc/dbxout.c b/gcc/dbxout.c
index 208cec9..3cba2dd 100644
--- a/gcc/dbxout.c
+++ b/gcc/dbxout.c
@@ -325,7 +325,8 @@  static int dbxout_symbol_location (tree, tree, const char *, rtx);
 static void dbxout_symbol_name (tree, const char *, int);
 static void dbxout_common_name (tree, const char *, stab_code_type);
 static const char *dbxout_common_check (tree, int *);
-static void dbxout_global_decl (tree, bool);
+static void dbxout_early_global_decl (tree);
+static void dbxout_late_global_decl (tree);
 static void dbxout_type_decl (tree, int);
 static void dbxout_handle_pch (unsigned);
 static void debug_free_queue (void);
@@ -366,7 +367,8 @@  const struct gcc_debug_hooks dbx_debug_hooks =
 #endif
   debug_nothing_int,		         /* end_function */
   dbxout_function_decl,
-  dbxout_global_decl,		         /* global_decl */
+  dbxout_early_global_decl,		 /* early_global_decl */
+  dbxout_late_global_decl,		 /* late_global_decl */
   dbxout_type_decl,			 /* type_decl */
   debug_nothing_tree_tree_tree_bool,	 /* imported_module_or_decl */
   debug_nothing_tree,		         /* deferred_inline_function */
@@ -402,7 +404,8 @@  const struct gcc_debug_hooks xcoff_debug_hooks =
   debug_nothing_tree,		         /* begin_function */
   xcoffout_end_function,
   debug_nothing_tree,		         /* function_decl */
-  dbxout_global_decl,		         /* global_decl */
+  dbxout_early_global_decl,		 /* early_global_decl */
+  dbxout_late_global_decl,		 /* late_global_decl */
   dbxout_type_decl,			 /* type_decl */
   debug_nothing_tree_tree_tree_bool,	 /* imported_module_or_decl */
   debug_nothing_tree,		         /* deferred_inline_function */
@@ -1317,10 +1320,16 @@  dbxout_function_decl (tree decl)
 
 #endif /* DBX_DEBUGGING_INFO  */
 
+static void
+dbxout_early_global_decl (tree decl ATTRIBUTE_UNUSED)
+{
+  /* NYI for non-dwarf.  */
+}
+
 /* Debug information for a global DECL.  Called from toplev.c after
    compilation proper has finished.  */
 static void
-dbxout_global_decl (tree decl, bool early ATTRIBUTE_UNUSED)
+dbxout_late_global_decl (tree decl)
 {
   if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
     {
diff --git a/gcc/debug.c b/gcc/debug.c
index b5818de..449d3a1 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 */
@@ -71,12 +72,6 @@  debug_nothing_tree (tree decl ATTRIBUTE_UNUSED)
 }
 
 void
-debug_nothing_tree_bool (tree decl ATTRIBUTE_UNUSED,
-			 bool early ATTRIBUTE_UNUSED)
-{
-}
-
-void
 debug_nothing_tree_tree (tree t1 ATTRIBUTE_UNUSED,
 			 tree t2 ATTRIBUTE_UNUSED)
 {
diff --git a/gcc/debug.h b/gcc/debug.h
index 9440515..ec387ca 100644
--- a/gcc/debug.h
+++ b/gcc/debug.h
@@ -92,12 +92,15 @@  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 from the parser after
+     the parsing process has finished.  */
+  void (* early_global_decl) (tree decl);
+
+  /* Augment debug information generated by early_global_decl with
+     more complete debug info (if applicable).  Called from toplev.c
+     after the compilation proper has finished and cgraph information
+     is available.  */
+  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
@@ -159,7 +162,6 @@  extern void debug_nothing_int_charstar_int_bool (unsigned int, const char *,
 extern void debug_nothing_int (unsigned int);
 extern void debug_nothing_int_int (unsigned int, unsigned int);
 extern void debug_nothing_tree (tree);
-extern void debug_nothing_tree_bool (tree, bool);
 extern void debug_nothing_tree_tree (tree, tree);
 extern void debug_nothing_tree_int (tree, int);
 extern void debug_nothing_tree_tree_tree_bool (tree, tree, tree, bool);
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index ddc44f4..0ad8b5d 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,
+  dwarf2out_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.  */
 }
@@ -17721,12 +17723,12 @@  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);
 
       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);
@@ -20817,29 +20819,64 @@  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 from the
+   end of the parsing process.
 
-   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 ;-).  */
+   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, 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;
+}
+
+/* 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 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
@@ -21041,11 +21078,7 @@  dwarf2out_decl (tree decl)
      We should always be reusing DIEs created early.  */
   dw_die_ref early_die = NULL;
   if (decl_die_table)
-    {
-      early_die = lookup_decl_die (decl);
-      if (early_die && !early_die->dumped_early)
-	early_die = NULL;
-    }
+    early_die = lookup_decl_die (decl);
 #endif
 
   switch (TREE_CODE (decl))
@@ -21176,57 +21209,12 @@  dwarf2out_decl (tree decl)
 #ifdef ENABLE_CHECKING
   /* If we early created a DIE, make sure it didn't get re-created by
      mistake.  */
-  gcc_assert (!early_die || early_die == die);
+  if (early_die && early_die->dumped_early)
+    gcc_assert (early_die == die);
 #endif
   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..ef0faac 100644
--- a/gcc/fortran/f95-lang.c
+++ b/gcc/fortran/f95-lang.c
@@ -81,7 +81,6 @@  static bool global_bindings_p (void);
 /* Each front end provides its own.  */
 static bool gfc_init (void);
 static void gfc_finish (void);
-static void gfc_write_global_declarations (void);
 static void gfc_be_parse_file (void);
 static alias_set_type gfc_get_alias_set (tree);
 static void gfc_init_ts (void);
@@ -108,7 +107,6 @@  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_OPTION_LANG_MASK
 #undef LANG_HOOKS_INIT_OPTIONS_STRUCT
 #undef LANG_HOOKS_INIT_OPTIONS
@@ -142,7 +140,6 @@  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
 #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
@@ -220,6 +217,19 @@  gfc_be_parse_file (void)
   /* Clear the binding level stack.  */
   while (!global_bindings_p ())
     poplevel (0, 0);
+
+  /* Finalize all of the globals.
+
+     Emulated tls lowering needs to see all TLS variables before we
+     call finalize_compilation_unit.  The C/C++ front ends manage this
+     by calling decl_rest_of_compilation on each global and static
+     variable as they are seen.  The Fortran front end waits until
+     here.  */
+  for (tree decl = getdecls (); decl ; decl = DECL_CHAIN (decl))
+    rest_of_decl_compilation (decl, true, true);
+
+  /* Do the debug dance.  */
+  global_decl_processing_and_early_debug ();
 }
 
 
@@ -263,32 +273,6 @@  gfc_finish (void)
   return;
 }
 
-/* ??? This is something of a hack.
-
-   Emulated tls lowering needs to see all TLS variables before we call
-   finalize_compilation_unit.  The C/C++ front ends manage this
-   by calling decl_rest_of_compilation on each global and static variable
-   as they are seen.  The Fortran front end waits until this hook.
-
-   A Correct solution is for finalize_compilation_unit not to be
-   called during the WRITE_GLOBALS langhook, and have that hook only do what
-   its name suggests and write out globals.  But the C++ and Java front ends
-   have (unspecified) problems with aliases that gets in the way.  It has
-   been suggested that these problems would be solved by completing the
-   conversion to cgraph-based aliases.  */
-
-static void
-gfc_write_global_declarations (void)
-{
-  tree decl;
-
-  /* Finalize all of the globals.  */
-  for (decl = getdecls(); decl ; decl = DECL_CHAIN (decl))
-    rest_of_decl_compilation (decl, true, true);
-
-  write_global_declarations ();
-}
-
 /* These functions and variables deal with binding contours.  We only
    need these functions for the list of PARM_DECLs, but we leave the
    functions more general; these are a simplified version of the
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index 38e6f99..0c7f50e 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -4693,7 +4693,7 @@  gfc_emit_parameter_debug_info (gfc_symbol *sym)
 					      TREE_TYPE (decl),
 					      sym->attr.dimension,
 					      false, false);
-  debug_hooks->global_decl (decl, /*early=*/false);
+  debug_hooks->early_global_decl (decl);
 }
 
 
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index 6bac84f..6d65e92 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -2915,7 +2915,8 @@  Gcc_backend::lookup_builtin(const std::string& name)
 }
 
 // Write the definitions for all TYPE_DECLS, CONSTANT_DECLS,
-// FUNCTION_DECLS, and VARIABLE_DECLS declared globally.
+// FUNCTION_DECLS, and VARIABLE_DECLS declared globally, as well as
+// emit early debugging information.
 
 void
 Gcc_backend::write_global_definitions(
@@ -2988,10 +2989,15 @@  Gcc_backend::write_global_definitions(
 
   wrapup_global_declarations(defs, i);
 
-  symtab->finalize_compilation_unit();
+  emit_debug_global_declarations (defs, i, EMIT_DEBUG_EARLY);
 
+  /* ?? Can we leave this call here, thus getting called before
+     finalize_compilation_unit?
+
+     Originally this was called *AFTER* finalize_compilation_unit.  If
+     `go' really needs this call after finalize_compilation_unit, we
+     can use LANG_HOOKS_POST_COMPILATION_PARSING_CLEANUPS (yuck).  */
   check_global_declarations(defs, i);
-  emit_debug_global_declarations(defs, i);
 
   delete[] defs;
 }
diff --git a/gcc/go/go-lang.c b/gcc/go/go-lang.c
index 24b6437..e8412ac 100644
--- a/gcc/go/go-lang.c
+++ b/gcc/go/go-lang.c
@@ -284,6 +284,9 @@  go_langhook_parse_file (void)
 {
   go_parse_input_files (in_fnames, num_in_fnames, flag_syntax_only,
 			go_require_return_statement);
+
+  /* Final processing of globals and early debug info generation.  */
+  go_write_globals ();
 }
 
 static tree
@@ -429,14 +432,6 @@  go_langhook_getdecls (void)
   return NULL;
 }
 
-/* Write out globals.  */
-
-static void
-go_langhook_write_globals (void)
-{
-  go_write_globals ();
-}
-
 /* Go specific gimplification.  We need to gimplify
    CALL_EXPR_STATIC_CHAIN, because the gimplifier doesn't handle
    it.  */
@@ -534,7 +529,6 @@  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_GIMPLIFY_EXPR
 #undef LANG_HOOKS_EH_PERSONALITY
 
@@ -551,7 +545,6 @@  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
 #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..ea89ed6 100644
--- a/gcc/godump.c
+++ b/gcc/godump.c
@@ -493,12 +493,18 @@  go_function_decl (tree decl)
   go_decl (decl);
 }
 
+static void
+go_early_global_decl (tree decl)
+{
+  real_debug_hooks->early_global_decl (decl);
+}
+
 /* A global variable decl.  */
 
 static void
-go_global_decl (tree decl, bool early)
+go_late_global_decl (tree decl)
 {
-  real_debug_hooks->global_decl (decl, early);
+  real_debug_hooks->late_global_decl (decl);
   go_decl (decl);
 }
 
@@ -1240,7 +1246,8 @@  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.early_global_decl = go_early_global_decl;
+  go_debug_hooks.late_global_decl = go_late_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/class.c b/gcc/java/class.c
index 0d51165..dd1d53d 100644
--- a/gcc/java/class.c
+++ b/gcc/java/class.c
@@ -3267,17 +3267,4 @@  in_same_package (tree name1, tree name2)
   return (pkg1 == pkg2);
 }
 
-/* lang_hooks.decls.final_write_globals: perform final processing on
-   global variables.  */
-
-void
-java_write_globals (void)
-{
-  tree *vec = vec_safe_address (pending_static_fields);
-  int len = vec_safe_length (pending_static_fields);
-  write_global_declarations ();
-  emit_debug_global_declarations (vec, len);
-  vec_free (pending_static_fields);
-}
-
 #include "gt-java-class.h"
diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h
index e832f44..cca5f70 100644
--- a/gcc/java/java-tree.h
+++ b/gcc/java/java-tree.h
@@ -1176,8 +1176,6 @@  int cxx_keyword_p (const char *name, int length);
 
 extern GTY(()) vec<tree, va_gc> *pending_static_fields;
 
-extern void java_write_globals (void);   
-
 #define DECL_FINAL(DECL) DECL_LANG_FLAG_3 (DECL)
 
 /* Access flags etc for a method (a FUNCTION_DECL): */
diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c
index 9c4a9cf..0abfff7 100644
--- a/gcc/java/jcf-parse.c
+++ b/gcc/java/jcf-parse.c
@@ -42,6 +42,7 @@  The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 #include "bitmap.h"
 #include "target.h"
 #include "wide-int.h"
+#include "toplev.h"
 
 #ifdef HAVE_LOCALE_H
 #include <locale.h>
@@ -1980,6 +1981,13 @@  java_parse_file (void)
   /* Arrange for any necessary initialization to happen.  */
   java_emit_static_constructor ();
   gcc_assert (global_bindings_p ());
+
+  /* Do final processing on globals and emit early debug information.  */
+  tree *vec = vec_safe_address (pending_static_fields);
+  int len = vec_safe_length (pending_static_fields);
+  global_decl_processing_and_early_debug ();
+  emit_debug_global_declarations (vec, len, EMIT_DEBUG_EARLY);
+  vec_free (pending_static_fields);
 }
 
 
diff --git a/gcc/java/lang.c b/gcc/java/lang.c
index 8a68691..be6c4c7 100644
--- a/gcc/java/lang.c
+++ b/gcc/java/lang.c
@@ -142,8 +142,6 @@  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
 
 #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..7d3903f 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -204,7 +204,7 @@  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_POST_COMPILATION_PARSING_CLEANUPS NULL
 #define LANG_HOOKS_DECL_OK_FOR_SIBCALL	lhd_decl_ok_for_sibcall
 #define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE hook_bool_const_tree_false
 #define LANG_HOOKS_OMP_PREDETERMINED_SHARING lhd_omp_predetermined_sharing
@@ -228,7 +228,7 @@  extern tree lhd_make_node (enum tree_code);
   LANG_HOOKS_FUNCTION_PARM_EXPANDED_FROM_PACK_P, \
   LANG_HOOKS_GET_GENERIC_FUNCTION_DECL, \
   LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL, \
-  LANG_HOOKS_WRITE_GLOBALS, \
+  LANG_HOOKS_POST_COMPILATION_PARSING_CLEANUPS, \
   LANG_HOOKS_DECL_OK_FOR_SIBCALL, \
   LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE, \
   LANG_HOOKS_OMP_PREDETERMINED_SHARING, \
diff --git a/gcc/langhooks.c b/gcc/langhooks.c
index 8ff91ba..dfc3ab6 100644
--- a/gcc/langhooks.c
+++ b/gcc/langhooks.c
@@ -290,15 +290,16 @@  lhd_decl_ok_for_sibcall (const_tree decl ATTRIBUTE_UNUSED)
   return true;
 }
 
-/* lang_hooks.decls.final_write_globals: perform final processing on
-   global variables.  */
+/* Generic global declaration processing and early debug generation.
+   This is meant to be called by the front-ends at the end of parsing.
+   C/C++ do their own thing, but other front-ends may call this.  */
+
 void
-write_global_declarations (void)
+global_decl_processing_and_early_debug (void)
 {
   tree globals, decl, *vec;
   int len, i;
 
-  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.  */
@@ -315,19 +316,9 @@  write_global_declarations (void)
 
   wrapup_global_declarations (vec, len);
   check_global_declarations (vec, len);
-  timevar_stop (TV_PHASE_DEFERRED);
-
-  timevar_start (TV_PHASE_OPT_GEN);
-  /* This lang hook is dual-purposed, and also finalizes the
-     compilation unit.  */
-  symtab->finalize_compilation_unit ();
-  timevar_stop (TV_PHASE_OPT_GEN);
 
-  timevar_start (TV_PHASE_DBGINFO);
-  emit_debug_global_declarations (vec, len);
-  timevar_stop (TV_PHASE_DBGINFO);
+  emit_debug_global_declarations (vec, len, EMIT_DEBUG_EARLY);
 
-  /* Clean up.  */
   free (vec);
 }
 
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index 72fa85e..40cfdbc 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -181,9 +181,11 @@  struct lang_hooks_for_decls
      We will already have checked that it has static binding.  */
   bool (*warn_unused_global) (const_tree);
 
-  /* Obtain a list of globals and do final output on them at end
-     of compilation */
-  void (*final_write_globals) (void);
+  /* Perform any post compilation-proper parser cleanups and
+     processing.  This is currently only needed for the C++ parser,
+     which hopefully can be cleaned up so this hook is no longer
+     necessary.  */
+  void (*post_compilation_parsing_cleanups) (void);
 
   /* True if this decl may be called via a sibcall.  */
   bool (*ok_for_sibcall) (const_tree);
diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c
index 1f39949..88fd46c 100644
--- a/gcc/lto/lto-lang.c
+++ b/gcc/lto/lto-lang.c
@@ -1083,19 +1083,6 @@  lto_getdecls (void)
   return NULL_TREE;
 }
 
-static void
-lto_write_globals (void)
-{
-  if (flag_wpa)
-    return;
-
-  /* Output debug info for global variables.  */  
-  varpool_node *vnode;
-  FOR_EACH_DEFINED_VARIABLE (vnode)
-    if (!decl_function_context (vnode->decl))
-      debug_hooks->global_decl (vnode->decl, /*early=*/false);
-}
-
 static tree
 lto_builtin_function (tree decl)
 {
@@ -1275,8 +1262,6 @@  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_REGISTER_BUILTIN_TYPE
 #define LANG_HOOKS_REGISTER_BUILTIN_TYPE lto_register_builtin_type
 #undef LANG_HOOKS_BUILTIN_FUNCTION
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index df59981..f79a1ce 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -417,8 +417,7 @@  objc_init (void)
   return true;
 }
 
-/* This is called automatically (at the very end of compilation) by
-   c_write_global_declarations and cp_write_global_declarations.  */
+/* This is called at the end of parsing by the C/C++ parsers.  */
 void
 objc_write_global_declarations (void)
 {
diff --git a/gcc/sdbout.c b/gcc/sdbout.c
index d81b184..a7d2f67 100644
--- a/gcc/sdbout.c
+++ b/gcc/sdbout.c
@@ -119,7 +119,8 @@  static void sdbout_begin_block		(unsigned int, unsigned int);
 static void sdbout_end_block		(unsigned int, unsigned int);
 static void sdbout_source_line		(unsigned int, const char *, int, bool);
 static void sdbout_end_epilogue		(unsigned int, const char *);
-static void sdbout_global_decl		(tree, bool);
+static void sdbout_early_global_decl	(tree);
+static void sdbout_late_global_decl	(tree);
 static void sdbout_begin_prologue	(unsigned int, const char *);
 static void sdbout_end_prologue		(unsigned int, const char *);
 static void sdbout_begin_function	(tree);
@@ -294,7 +295,8 @@  const struct gcc_debug_hooks sdb_debug_hooks =
   sdbout_begin_function,	         /* begin_function */
   sdbout_end_function,		         /* end_function */
   debug_nothing_tree,		         /* function_decl */
-  sdbout_global_decl,		         /* global_decl */
+  sdbout_early_global_decl,		 /* early_global_decl */
+  sdbout_late_global_decl,		 /* late_global_decl */
   sdbout_symbol,			 /* type_decl */
   debug_nothing_tree_tree_tree_bool,	 /* imported_module_or_decl */
   debug_nothing_tree,		         /* deferred_inline_function */
@@ -1417,11 +1419,17 @@  sdbout_reg_parms (tree parms)
       }
 }
 
+static void
+sdbout_early_global_decl (tree decl ATTRIBUTE_UNUSED)
+{
+  /* NYI for non-dwarf.  */
+}
+
 /* Output debug information for a global DECL.  Called from toplev.c
    after compilation proper has finished.  */
 
 static void
-sdbout_global_decl (tree decl, bool early ATTRIBUTE_UNUSED)
+sdbout_late_global_decl (tree decl)
 {
   if (TREE_CODE (decl) == VAR_DECL
       && !DECL_EXTERNAL (decl)
diff --git a/gcc/timevar.def b/gcc/timevar.def
index a04d05c..d9d95de 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -31,11 +31,16 @@ 
 
 /* The total execution time.  */
 DEFTIMEVAR (TV_TOTAL                 , "total time")
-/* The compiler phases.  These must be mutually exclusive.
-   Ideally, they would sum to near the total time.  */
+/* The compiler phases.
+
+   These must be mutually exclusive, and the NAME field must begin
+   with "phase".
+
+   Also, their sum must be within a millionth of the total time (see
+   validate_phases).  */
 DEFTIMEVAR (TV_PHASE_SETUP           , "phase setup")
 DEFTIMEVAR (TV_PHASE_PARSING         , "phase parsing")
-DEFTIMEVAR (TV_PHASE_DEFERRED        , "phase lang. deferred")
+DEFTIMEVAR (TV_PHASE_LATE_PARSING_CLEANUPS, "phase late parsing cleanups")
 DEFTIMEVAR (TV_PHASE_OPT_GEN         , "phase opt and generate")
 DEFTIMEVAR (TV_PHASE_DBGINFO         , "phase debug info")
 DEFTIMEVAR (TV_PHASE_CHECK_DBGINFO   , "phase check & debug info")
diff --git a/gcc/toplev.c b/gcc/toplev.c
index ceefa1b..2347d6c 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -519,10 +519,13 @@  check_global_declarations (tree *v, int len)
     check_global_declaration_1 (v[i]);
 }
 
-/* Emit debugging information for all global declarations in VEC.  */
+/* Emit debugging information for all global declarations in VEC.
+   WHEN is either EMIT_DEBUG_EARLY or EMIT_DEBUG_LATE depending on if
+   we are generating early debug (at the end of parsing), or the late
+   (post compilation) version.  */
 
 void
-emit_debug_global_declarations (tree *vec, int len)
+emit_debug_global_declarations (tree *vec, int len, enum emit_debug when)
 {
   int i;
 
@@ -532,7 +535,14 @@  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);
+    {
+      if (when == EMIT_DEBUG_EARLY)
+	debug_hooks->early_global_decl (vec[i]);
+      else if (when == EMIT_DEBUG_LATE)
+	debug_hooks->late_global_decl (vec[i]);
+      else
+	gcc_unreachable ();
+    }
   timevar_pop (TV_SYMOUT);
 }
 
@@ -545,8 +555,7 @@  compile_file (void)
   timevar_start (TV_PHASE_PARSING);
   timevar_push (TV_PARSE_GLOBAL);
 
-  /* Call the parser, which parses the entire file (calling
-     rest_of_compilation for each function).  */
+  /* Parse entire file and generate initial debug information.  */
   lang_hooks.parse_file ();
 
   timevar_pop (TV_PARSE_GLOBAL);
@@ -560,12 +569,33 @@  compile_file (void)
 
   ggc_protect_identifiers = false;
 
-  /* This must also call finalize_compilation_unit.  */
-  lang_hooks.decls.final_write_globals ();
+  /* Run the actual compilation process.  */
+  if (!in_lto_p)
+    {
+      timevar_start (TV_PHASE_OPT_GEN);
+      symtab->finalize_compilation_unit ();
+      timevar_stop (TV_PHASE_OPT_GEN);
+    }
+
+  /* Perform any post compilation-proper parser cleanups and
+     processing.  This is currently only needed for the C++ parser,
+     which can be hopefully cleaned up so this hook is no longer
+     necessary.  */
+  if (lang_hooks.decls.post_compilation_parsing_cleanups)
+    lang_hooks.decls.post_compilation_parsing_cleanups ();
 
   if (seen_error ())
     return;
 
+  /* After the parser has generated debugging information, augment
+     this information with any new location/etc information that may
+     have become available after the compilation proper.  */
+  timevar_start (TV_PHASE_DBGINFO);
+  symtab_node *node;
+  FOR_EACH_DEFINED_SYMBOL (node)
+    debug_hooks->late_global_decl (node->decl);
+  timevar_stop (TV_PHASE_DBGINFO);
+
   timevar_start (TV_PHASE_LATE_ASM);
 
   /* Compilation unit is finalized.  When producing non-fat LTO object, we are
diff --git a/gcc/toplev.h b/gcc/toplev.h
index 1b54578..ff1fd9d 100644
--- a/gcc/toplev.h
+++ b/gcc/toplev.h
@@ -42,8 +42,14 @@  extern bool wrapup_global_declaration_2 (tree);
 extern bool wrapup_global_declarations (tree *, int);
 extern void check_global_declaration_1 (tree);
 extern void check_global_declarations (tree *, int);
-extern void emit_debug_global_declarations (tree *, int);
-extern void write_global_declarations (void);
+
+enum emit_debug {
+  EMIT_DEBUG_EARLY,
+  EMIT_DEBUG_LATE
+};
+extern void emit_debug_global_declarations (tree *, int, enum emit_debug);
+
+extern void global_decl_processing_and_early_debug (void);
 
 extern void dump_memory_report (bool);
 extern void dump_profile_report (void);
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index ad474a5..9100cd1 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -4494,9 +4494,7 @@  expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
   return successfully_inlined;
 }
 
-/* Expand call statements reachable from STMT_P.
-   We can only have CALL_EXPRs as the "toplevel" tree code or nested
-   in a MODIFY_EXPR.  */
+/* Expand call statements in BB when profitable.  */
 
 static bool
 gimple_expand_calls_inline (basic_block bb, copy_body_data *id)
diff --git a/gcc/tree.c b/gcc/tree.c
index 8e9876e..9c7251c 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -5089,6 +5089,8 @@  free_lang_data_in_decl (tree decl)
 	 At this point, it is not needed anymore.  */
       DECL_SAVED_TREE (decl) = NULL_TREE;
 
+      /* ?? This should be OK to remove now that we are generating dwarf
+	 early.  */
       /* Clear the abstract origin if it refers to a method.  Otherwise
          dwarf2out.c will ICE as we clear TYPE_METHODS and thus the
 	 origin will not be output correctly.  */
@@ -5630,7 +5632,11 @@  free_lang_data (void)
   unsigned i;
 
   /* If we are the LTO frontend we have freed lang-specific data already.  */
-  if (in_lto_p)
+  if (in_lto_p
+      /* FIXME: Eventually we need to remove this so the function
+	 proceeds and we can be sure there is no language specific
+	 data past cgraph.  */
+      || !flag_generate_lto)
     return 0;
 
   /* Allocate and assign alias sets to the standard integer types
diff --git a/gcc/vmsdbgout.c b/gcc/vmsdbgout.c
index 2ad9e9b..b0c305f 100644
--- a/gcc/vmsdbgout.c
+++ b/gcc/vmsdbgout.c
@@ -163,7 +163,8 @@  static void vmsdbgout_begin_epilogue (unsigned int, const char *);
 static void vmsdbgout_end_epilogue (unsigned int, const char *);
 static void vmsdbgout_begin_function (tree);
 static void vmsdbgout_decl (tree);
-static void vmsdbgout_global_decl (tree, bool);
+static void vmsdbgout_early_global_decl (tree);
+static void vmsdbgout_late_global_decl (tree);
 static void vmsdbgout_type_decl (tree, int);
 static void vmsdbgout_abstract_function (tree);
 
@@ -188,7 +189,8 @@  const struct gcc_debug_hooks vmsdbg_debug_hooks
    vmsdbgout_begin_function,
    vmsdbgout_end_function,
    vmsdbgout_decl,
-   vmsdbgout_global_decl,
+   vmsdbgout_early_global_decl,
+   vmsdbgout_late_global_decl,
    vmsdbgout_type_decl,		  /* type_decl */
    debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
    debug_nothing_tree,		  /* deferred_inline_function */
@@ -1510,10 +1512,18 @@  vmsdbgout_decl (tree decl)
 /* Not implemented in VMS Debug.  */
 
 static void
-vmsdbgout_global_decl (tree decl, bool early)
+vmsdbgout_early_global_decl (tree decl)
+{
+  /* NYI for non-dwarf.  */
+}
+
+/* Not implemented in VMS Debug.  */
+
+static void
+vmsdbgout_late_global_decl (tree decl)
 {
   if (write_symbols == VMS_AND_DWARF2_DEBUG)
-    (*dwarf2_debug_hooks.global_decl) (decl, early);
+    (*dwarf2_debug_hooks.late_global_decl) (decl);
 }
 
 /* Not implemented in VMS Debug.  */