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]

DWARF2 PATCH for inlining problems


This fixes problems with a couple of C testcases:

  gcc.c-torture/compile/20000120-2.c
  gcc.c-torture/unsorted/loop386.c

with dwarf2 debugging and -O2; the block structure was being mangled by the
optimizer, so the debugging information for the abstract instance of the
inline was messed up.  The solution is to emit that info before running the
optimizer.

The first testcase will still have trouble with -O3, as dwarf2out expects
that there will only be one inline instance of a function, and if we
automatically inline the redefinition of bar, this is violated.  I would
like to suppress automatic inlining in this case, but there isn't currently
a mechanism to do so.

Would it makes sense to move DECL_UNINLINABLE from the C++ frontend into
the backend?  Or should I just set DECL_SAVED_INSNS to some invalid value?
(it will never be examined if DECL_INLINE isn't set).

The last couple of changes are small fixes for other issues I noticed while
looking at this.

2001-02-16  Jason Merrill  <jason@redhat.com>

	* dwarf2out.c (dwarf2out_abstract_function): Rename from
	gen_abstract_function.
	* dwarf2out.h: Declare it.
	* toplev.c (note_outlining_of_inline_function): New fn.
	* toplev.h: Declare it.
	* integrate.c (output_inline_function): Call it.
	* c-decl.c (duplicate_decls): Call it when redefining an extern
	inline.  Don't inline the new defn.

	* dwarf2out.c (add_bound_info): Don't crash if SAVE_EXPR_RTL is
	NULL.
	(gen_subprogram_die): Don't abort on seeing a second definition if 
	the previous one was abstract.  Don't replace an abstract instance
	in the lookup table.

Index: dwarf2out.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/dwarf2out.c,v
retrieving revision 1.242
diff -c -p -r1.242 dwarf2out.c
*** dwarf2out.c	2001/02/09 02:00:44	1.242
--- dwarf2out.c	2001/02/16 12:56:33
*************** static void init_file_table		PARAMS ((st
*** 3760,3766 ****
  static void add_incomplete_type		PARAMS ((tree));
  static void retry_incomplete_types	PARAMS ((void));
  static void gen_type_die_for_member	PARAMS ((tree, tree, dw_die_ref));
- static void gen_abstract_function	PARAMS ((tree));
  static rtx save_rtx			PARAMS ((rtx));
  static void splice_child_die		PARAMS ((dw_die_ref, dw_die_ref));
  static int file_info_cmp		PARAMS ((const void *, const void *));
--- 3760,3765 ----
*************** add_bound_info (subrange_die, bound_attr
*** 9014,9021 ****
  	 We assume that a MEM rtx is safe because gcc wouldn't put the
  	 value there unless it was going to be used repeatedly in the
  	 function, i.e. for cleanups.  */
!       if (! optimize || (SAVE_EXPR_RTL (bound)
! 			 && GET_CODE (SAVE_EXPR_RTL (bound)) == MEM))
  	{
  	  register dw_die_ref ctx = lookup_decl_die (current_function_decl);
  	  register dw_die_ref decl_die = new_die (DW_TAG_variable, ctx);
--- 9013,9020 ----
  	 We assume that a MEM rtx is safe because gcc wouldn't put the
  	 value there unless it was going to be used repeatedly in the
  	 function, i.e. for cleanups.  */
!       if (SAVE_EXPR_RTL (bound)
! 	  && (! optimize || GET_CODE (SAVE_EXPR_RTL (bound)) == MEM))
  	{
  	  register dw_die_ref ctx = lookup_decl_die (current_function_decl);
  	  register dw_die_ref decl_die = new_die (DW_TAG_variable, ctx);
*************** add_abstract_origin_attribute (die, orig
*** 9320,9326 ****
  	fn = TYPE_STUB_DECL (fn);
        fn = decl_function_context (fn);
        if (fn)
! 	gen_abstract_function (fn);
      }
  
    if (DECL_P (origin))
--- 9319,9325 ----
  	fn = TYPE_STUB_DECL (fn);
        fn = decl_function_context (fn);
        if (fn)
! 	dwarf2out_abstract_function (fn);
      }
  
    if (DECL_P (origin))
*************** gen_type_die_for_member (type, member, c
*** 10022,10029 ****
     of a function which we may later generate inlined and/or
     out-of-line instances of.  */
  
! static void
! gen_abstract_function (decl)
       tree decl;
  {
    register dw_die_ref old_die = lookup_decl_die (decl);
--- 10021,10028 ----
     of a function which we may later generate inlined and/or
     out-of-line instances of.  */
  
! void
! dwarf2out_abstract_function (decl)
       tree decl;
  {
    register dw_die_ref old_die = lookup_decl_die (decl);
*************** gen_subprogram_die (decl, context_die)
*** 10105,10111 ****
        register unsigned file_index
  	= lookup_filename (&decl_file_table, DECL_SOURCE_FILE (decl));
  
!       if (get_AT_flag (old_die, DW_AT_declaration) != 1)
  	{
  	  /* ??? This can happen if there is a bug in the program, for
  	     instance, if it has duplicate function definitions.  Ideally,
--- 10104,10114 ----
        register unsigned file_index
  	= lookup_filename (&decl_file_table, DECL_SOURCE_FILE (decl));
  
!       if (!get_AT_flag (old_die, DW_AT_declaration)
! 	  /* We can have a normal definition following an inline one in the
! 	     case of redefinition of GNU C extern inlines.
! 	     It seems reasonable to use AT_specification in this case.  */
! 	  && !get_AT_unsigned (old_die, DW_AT_inline))
  	{
  	  /* ??? This can happen if there is a bug in the program, for
  	     instance, if it has duplicate function definitions.  Ideally,
*************** gen_subprogram_die (decl, context_die)
*** 10175,10189 ****
  
    if (declaration)
      {
!       if (! origin)
! 	add_AT_flag (subr_die, DW_AT_declaration, 1);
  
!       /* The first time we see a member function, it is in the context of
!          the class to which it belongs.  We make sure of this by emitting
!          the class first.  The next time is the definition, which is
!          handled above.  The two may come from the same source text.  */
!       if (DECL_CONTEXT (decl) || DECL_ABSTRACT (decl))
! 	equate_decl_number_to_die (decl, subr_die);
      }
    else if (DECL_ABSTRACT (decl))
      {
--- 10178,10194 ----
  
    if (declaration)
      {
!       if (!(old_die && get_AT_unsigned (old_die, DW_AT_inline)))
! 	{
! 	  add_AT_flag (subr_die, DW_AT_declaration, 1);
  
! 	  /* The first time we see a member function, it is in the context of
! 	     the class to which it belongs.  We make sure of this by emitting
! 	     the class first.  The next time is the definition, which is
! 	     handled above.  The two may come from the same source text.  */
! 	  if (DECL_CONTEXT (decl) || DECL_ABSTRACT (decl))
! 	    equate_decl_number_to_die (decl, subr_die);
! 	}
      }
    else if (DECL_ABSTRACT (decl))
      {
*************** gen_subprogram_die (decl, context_die)
*** 10206,10212 ****
      }
    else if (!DECL_EXTERNAL (decl))
      {
!       if (origin == NULL_TREE)
  	equate_decl_number_to_die (decl, subr_die);
  
        ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
--- 10211,10217 ----
      }
    else if (!DECL_EXTERNAL (decl))
      {
!       if (!(old_die && get_AT_unsigned (old_die, DW_AT_inline)))
  	equate_decl_number_to_die (decl, subr_die);
  
        ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
*************** gen_inlined_subroutine_die (stmt, contex
*** 10490,10496 ****
        char label[MAX_ARTIFICIAL_LABEL_BYTES];
  
        /* Emit info for the abstract instance first, if we haven't yet.  */
!       gen_abstract_function (decl);
  
        add_abstract_origin_attribute (subr_die, decl);
        ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
--- 10495,10501 ----
        char label[MAX_ARTIFICIAL_LABEL_BYTES];
  
        /* Emit info for the abstract instance first, if we haven't yet.  */
!       dwarf2out_abstract_function (decl);
  
        add_abstract_origin_attribute (subr_die, decl);
        ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
*************** gen_decl_die (decl, context_die)
*** 11265,11276 ****
  	 emit info for the abstract instance and set up to refer to it.  */
        if (DECL_INLINE (decl) && ! DECL_ABSTRACT (decl)
  	  && ! class_scope_p (context_die)
! 	  /* gen_abstract_function won't emit a die if this is just a
  	     declaration.  We must avoid setting DECL_ABSTRACT_ORIGIN in
  	     that case, because that works only if we have a die.  */
  	  && DECL_INITIAL (decl) != NULL_TREE)
  	{
! 	  gen_abstract_function (decl);
  	  set_decl_origin_self (decl);
  	}
  
--- 11270,11281 ----
  	 emit info for the abstract instance and set up to refer to it.  */
        if (DECL_INLINE (decl) && ! DECL_ABSTRACT (decl)
  	  && ! class_scope_p (context_die)
! 	  /* dwarf2out_abstract_function won't emit a die if this is just a
  	     declaration.  We must avoid setting DECL_ABSTRACT_ORIGIN in
  	     that case, because that works only if we have a die.  */
  	  && DECL_INITIAL (decl) != NULL_TREE)
  	{
! 	  dwarf2out_abstract_function (decl);
  	  set_decl_origin_self (decl);
  	}
  
Index: dwarf2out.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/dwarf2out.h,v
retrieving revision 1.10
diff -c -p -r1.10 dwarf2out.h
*** dwarf2out.h	2000/11/08 02:18:00	1.10
--- dwarf2out.h	2001/02/16 12:56:33
*************** extern void debug_dwarf			PARAMS ((void)
*** 39,42 ****
--- 39,43 ----
  struct die_struct;
  extern void debug_dwarf_die		PARAMS ((struct die_struct *));
  extern void dwarf2out_set_demangle_name_func PARAMS ((const char *(*) (const char *)));
+ extern void dwarf2out_abstract_function PARAMS ((tree));
  extern void dwarf2out_add_library_unit_info PARAMS ((const char *, const char *));
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/toplev.c,v
retrieving revision 1.423
diff -c -p -r1.423 toplev.c
*** toplev.c	2001/02/14 22:38:58	1.423
--- toplev.c	2001/02/16 12:56:36
*************** note_deferral_of_defined_inline_function
*** 2681,2686 ****
--- 2681,2704 ----
  #endif
  }
  
+ /* FNDECL is an inline function which is about to be emitted out of line.
+    Do any preparation, such as emitting abstract debug info for the inline
+    before it gets mangled by optimization.  */
+ 
+ void
+ note_outlining_of_inline_function (fndecl)
+      tree fndecl;
+ {
+ #ifdef DWARF2_DEBUGGING_INFO
+   /* The DWARF 2 backend tries to reduce debugging bloat by not emitting
+      the abstract description of inline functions until something tries to
+      reference them.  Force it out now, before optimizations mangle the
+      block tree.  */
+   if (write_symbols == DWARF2_DEBUG)
+     dwarf2out_abstract_function (fndecl);
+ #endif
+ }
+ 
  /* This is called from finish_function (within yyparse)
     after each top-level definition is parsed.
     It is supposed to compile that function or variable
Index: toplev.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/toplev.h,v
retrieving revision 1.53
diff -c -p -r1.53 toplev.h
*** toplev.h	2001/02/12 12:32:56	1.53
--- toplev.h	2001/02/16 12:56:36
*************** extern int wrapup_global_declarations   
*** 128,133 ****
--- 128,135 ----
  extern void check_global_declarations   PARAMS ((union tree_node **, int));
  extern void note_deferral_of_defined_inline_function
  					PARAMS ((union tree_node *));
+ extern void note_outlining_of_inline_function
+ 					PARAMS ((union tree_node *));
  extern int errorcount;
  extern int warningcount;
  extern int sorrycount;
Index: integrate.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/integrate.c,v
retrieving revision 1.127
diff -c -p -r1.127 integrate.c
*** integrate.c	2001/02/14 16:24:45	1.127
--- integrate.c	2001/02/16 12:56:40
*************** output_inline_function (fndecl)
*** 2846,2851 ****
--- 2846,2855 ----
    if (f->no_debugging_symbols)
      write_symbols = NO_DEBUG;
  
+   /* Do any preparation, such as emitting abstract debug info for the inline
+      before it gets mangled by optimization.  */
+   note_outlining_of_inline_function (fndecl);
+ 
    /* Compile this function all the way down to assembly code.  */
    rest_of_compilation (fndecl);
  
Index: c-decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-decl.c,v
retrieving revision 1.208
diff -c -p -r1.208 c-decl.c
*** c-decl.c	2001/02/12 17:31:39	1.208
--- c-decl.c	2001/02/16 12:56:43
*************** duplicate_decls (newdecl, olddecl, diffe
*** 1928,1933 ****
--- 1928,1946 ----
    /* For functions, static overrides non-static.  */
    if (TREE_CODE (newdecl) == FUNCTION_DECL)
      {
+       /* If we're redefining a function previously defined as extern
+ 	 inline, make sure we emit debug info for the inline before we
+ 	 throw it away, in case it was inlined into a function that hasn't
+ 	 been written out yet.  */
+       if (new_is_definition && DECL_INITIAL (olddecl) && TREE_USED (olddecl))
+ 	{
+ 	  note_outlining_of_inline_function (olddecl);
+ 
+ 	  /* The new defn must not be inline.
+ 	     FIXME what about -finline-functions? */
+ 	  DECL_INLINE (newdecl) = 0;
+ 	}
+ 
        TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl);
        /* This is since we don't automatically
  	 copy the attributes of NEWDECL into OLDDECL.  */

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