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


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

[PATCH] Fix PR47799 - debug info for early-inlining with LTO


This tries to emit proper debug information for early-inlined
functions from LTO LTRANS phase (thus, emit DW_TAG_inlined_subroutine
and allow gdb to set breakpoints).  We need to avoid confusing
LTO and dwarf2out with the full abstract block tree, so this
patch "flattens" the abstract block tree by always using the
ultimate origin for BLOCK_ABSTRACT_ORIGIN on blocks which are
inlined_function_outer_scope_p.  Thus, it tries to output the
minimal info dwarf2out.c needs to emit the desired debug information.

As with LTO all abstract inline instances get generated late for
early inlined functions I had to amend the "hack" for extern inline
functions to always output dies for decls that come their way
through dwarf2out_abstract_function.  And further down not crash
on a NULL DECL_INITIAL (when LTO decided to output the function
body in another LTRANS unit or if it does not get output at all).

Currently LTO-bootstrapping and testing on x86_64-unknown-linux-gnu.

Jason, are the dwarf2out bits ok with you?

I've sofar toyed with examples like

int x, y;
static inline int foo (int i) { y = i; return y; }
static inline int bar (int i) { x = i; return foo (x); }
int main ()
{
  int k = 0;
  int res = bar (k);
  return res;
}

and debug information with/without LTO is now reasonably the same
and I can set breakpoints on the inlined instances.

Thanks,
Richard.

2012-10-01  Richard Guenther  <rguenther@suse.de>

	PR lto/47788
	* tree-streamer-out.c (write_ts_block_tree_pointers): For
	inlined functions outer scopes write the ultimate origin
	as BLOCK_ABSTRACT_ORIGIN and BLOCK_SOURCE_LOCATION.
	Do not stream the fragment chains.
	(lto_input_ts_block_tree_pointers): Likewise.
	* dwarf2out.c (gen_subprogram_die): Handle NULL DECL_INITIAL.
	(dwarf2out_decl): Always output DECL_ABSTRACT function decls.
	
Index: gcc/tree-streamer-in.c
===================================================================
*** gcc/tree-streamer-in.c	(revision 191824)
--- gcc/tree-streamer-in.c	(working copy)
*************** static void
*** 789,810 ****
  lto_input_ts_block_tree_pointers (struct lto_input_block *ib,
  				  struct data_in *data_in, tree expr)
  {
-   /* Do not stream BLOCK_SOURCE_LOCATION.  We cannot handle debug information
-      for early inlining so drop it on the floor instead of ICEing in
-      dwarf2out.c.  */
    BLOCK_VARS (expr) = streamer_read_chain (ib, data_in);
  
-   /* Do not stream BLOCK_NONLOCALIZED_VARS.  We cannot handle debug information
-      for early inlining so drop it on the floor instead of ICEing in
-      dwarf2out.c.  */
- 
    BLOCK_SUPERCONTEXT (expr) = stream_read_tree (ib, data_in);
  
!   /* Do not stream BLOCK_ABSTRACT_ORIGIN.  We cannot handle debug information
!      for early inlining so drop it on the floor instead of ICEing in
       dwarf2out.c.  */
!   BLOCK_FRAGMENT_ORIGIN (expr) = stream_read_tree (ib, data_in);
!   BLOCK_FRAGMENT_CHAIN (expr) = stream_read_tree (ib, data_in);
  
    /* We re-compute BLOCK_SUBBLOCKS of our parent here instead
       of streaming it.  For non-BLOCK BLOCK_SUPERCONTEXTs we still
--- 789,810 ----
  lto_input_ts_block_tree_pointers (struct lto_input_block *ib,
  				  struct data_in *data_in, tree expr)
  {
    BLOCK_VARS (expr) = streamer_read_chain (ib, data_in);
  
    BLOCK_SUPERCONTEXT (expr) = stream_read_tree (ib, data_in);
  
!   /* Stream BLOCK_ABSTRACT_ORIGIN and BLOCK_SOURCE_LOCATION for
!      the limited cases we can handle - those that represent inlined
!      function scopes.  For the rest them on the floor instead of ICEing in
       dwarf2out.c.  */
!   BLOCK_ABSTRACT_ORIGIN (expr) = stream_read_tree (ib, data_in);
!   BLOCK_SOURCE_LOCATION (expr) = lto_input_location (ib, data_in);
!   /* Do not stream BLOCK_NONLOCALIZED_VARS.  We cannot handle debug information
!      for early inlined BLOCKs so drop it on the floor instead of ICEing in
!      dwarf2out.c.  */
! 
!   /* BLOCK_FRAGMENT_ORIGIN and BLOCK_FRAGMENT_CHAIN is not live at LTO
!      streaming time.  */
  
    /* We re-compute BLOCK_SUBBLOCKS of our parent here instead
       of streaming it.  For non-BLOCK BLOCK_SUPERCONTEXTs we still
Index: gcc/tree-streamer-out.c
===================================================================
*** gcc/tree-streamer-out.c	(revision 191824)
--- gcc/tree-streamer-out.c	(working copy)
*************** write_ts_exp_tree_pointers (struct outpu
*** 682,702 ****
  static void
  write_ts_block_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
  {
-   /* Do not stream BLOCK_SOURCE_LOCATION.  We cannot handle debug information
-      for early inlining so drop it on the floor instead of ICEing in
-      dwarf2out.c.  */
    streamer_write_chain (ob, BLOCK_VARS (expr), ref_p);
  
    /* Do not stream BLOCK_NONLOCALIZED_VARS.  We cannot handle debug information
!      for early inlining so drop it on the floor instead of ICEing in
       dwarf2out.c.  */
  
!   stream_write_tree (ob, BLOCK_SUPERCONTEXT (expr), ref_p);
!   /* Do not stream BLOCK_ABSTRACT_ORIGIN.  We cannot handle debug information
!      for early inlining so drop it on the floor instead of ICEing in
!      dwarf2out.c.  */
!   stream_write_tree (ob, BLOCK_FRAGMENT_ORIGIN (expr), ref_p);
!   stream_write_tree (ob, BLOCK_FRAGMENT_CHAIN (expr), ref_p);
    /* Do not output BLOCK_SUBBLOCKS.  Instead on streaming-in this
       list is re-constructed from BLOCK_SUPERCONTEXT.  */
  }
--- 682,713 ----
  static void
  write_ts_block_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
  {
    streamer_write_chain (ob, BLOCK_VARS (expr), ref_p);
  
+   stream_write_tree (ob, BLOCK_SUPERCONTEXT (expr), ref_p);
+ 
+   /* Stream BLOCK_ABSTRACT_ORIGIN and BLOCK_SOURCE_LOCATION for
+      the limited cases we can handle - those that represent inlined
+      function scopes.  For the rest them on the floor instead of ICEing in
+      dwarf2out.c.  */
+   if (inlined_function_outer_scope_p (expr))
+     {
+       tree ultimate_origin = block_ultimate_origin (expr);
+       stream_write_tree (ob, ultimate_origin, ref_p);
+       lto_output_location (ob, BLOCK_SOURCE_LOCATION (expr));
+     }
+   else
+     {
+       stream_write_tree (ob, NULL_TREE, ref_p);
+       lto_output_location (ob, UNKNOWN_LOCATION);
+     }
    /* Do not stream BLOCK_NONLOCALIZED_VARS.  We cannot handle debug information
!      for early inlined BLOCKs so drop it on the floor instead of ICEing in
       dwarf2out.c.  */
  
!   /* BLOCK_FRAGMENT_ORIGIN and BLOCK_FRAGMENT_CHAIN is not live at LTO
!      streaming time.  */
! 
    /* Do not output BLOCK_SUBBLOCKS.  Instead on streaming-in this
       list is re-constructed from BLOCK_SUPERCONTEXT.  */
  }
Index: gcc/dwarf2out.c
===================================================================
*** gcc/dwarf2out.c	(revision 191824)
--- gcc/dwarf2out.c	(working copy)
*************** gen_subprogram_die (tree decl, dw_die_re
*** 17327,17333 ****
       a BLOCK node representing the function's outermost pair of curly braces,
       and any blocks used for the base and member initializers of a C++
       constructor function.  */
!   if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK)
      {
        int call_site_note_count = 0;
        int tail_call_site_note_count = 0;
--- 17327,17333 ----
       a BLOCK node representing the function's outermost pair of curly braces,
       and any blocks used for the base and member initializers of a C++
       constructor function.  */
!   if (! declaration && outer_scope && TREE_CODE (outer_scope) != ERROR_MARK)
      {
        int call_site_note_count = 0;
        int tail_call_site_note_count = 0;
*************** dwarf2out_decl (tree decl)
*** 19620,19627 ****
  	 inline" functions as DECL_EXTERNAL, but we need to generate DWARF for
  	 them anyway. Note that the C++ front-end also plays some similar games
  	 for inline function definitions appearing within include files which
! 	 also contain `#pragma interface' pragmas.  */
!       if (DECL_INITIAL (decl) == NULL_TREE)
  	return;
  
        /* If we're a nested function, initially use a parent of NULL; if we're
--- 19620,19633 ----
  	 inline" functions as DECL_EXTERNAL, but we need to generate DWARF for
  	 them anyway. Note that the C++ front-end also plays some similar games
  	 for inline function definitions appearing within include files which
! 	 also contain `#pragma interface' pragmas.
! 
! 	 If we are called from dwarf2out_abstract_function output a DIE
! 	 anyway.  We can end up here this way with early inlining and LTO
! 	 where the inlined function is output in a different LTRANS unit
! 	 or not at all.  */
!       if (DECL_INITIAL (decl) == NULL_TREE
! 	  && ! DECL_ABSTRACT (decl))
  	return;
  
        /* If we're a nested function, initially use a parent of NULL; if we're


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