This is the mail archive of the gcc@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]

Re: Inliner parameters


> > And we should certainly get -funit-at-a-time
> > working for C++ in mainline.
> 
> That would be really cool, yes.
Really hope that I will be able to do somw work on it this week (once I
get past the bugreports that has accumulated).  I am attaching the WIP
patch in case someone wants to take a look.  It works for simple cases
but fails to build some functions when iostream.h is included.  not sure
where I miss them.

Honza

Index: cgraph.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.c,v
retrieving revision 1.9
diff -c -3 -p -r1.9 cgraph.c
*** cgraph.c	8 Mar 2003 18:24:22 -0000	1.9
--- cgraph.c	12 Mar 2003 17:56:11 -0000
*************** static htab_t cgraph_hash = 0;
*** 48,53 ****
--- 48,56 ----
  /* The linked list of cgraph nodes.  */
  struct cgraph_node *cgraph_nodes;
  
+ /* Queue of cgraph nodes scheduled to be lowered.  */
+ struct cgraph_node *cgraph_nodes_queue;
+ 
  /* Number of nodes in existence.  */
  int cgraph_n_nodes;
  
*************** eq_node (p1, p2)
*** 79,85 ****
       const PTR p2;
  {
    return ((DECL_ASSEMBLER_NAME (((struct cgraph_node *) p1)->decl)) ==
! 	  DECL_ASSEMBLER_NAME ((tree) p2));
  }
  
  /* Return cgraph node assigned to DECL.  Create new one when needed.  */
--- 82,88 ----
       const PTR p2;
  {
    return ((DECL_ASSEMBLER_NAME (((struct cgraph_node *) p1)->decl)) ==
! 	  (tree) p2);
  }
  
  /* Return cgraph node assigned to DECL.  Create new one when needed.  */
*************** cgraph_node (decl)
*** 100,106 ****
      }
  
    slot =
!     (struct cgraph_node **) htab_find_slot_with_hash (cgraph_hash, decl,
  						      htab_hash_pointer
  						      (DECL_ASSEMBLER_NAME
  						       (decl)), 1);
--- 103,110 ----
      }
  
    slot =
!     (struct cgraph_node **) htab_find_slot_with_hash (cgraph_hash,
! 						      DECL_ASSEMBLER_NAME (decl),
  						      htab_hash_pointer
  						      (DECL_ASSEMBLER_NAME
  						       (decl)), 1);
*************** cgraph_node (decl)
*** 125,130 ****
--- 129,158 ----
    return node;
  }
  
+ /* Try to find existing function for identifier ID.  */
+ struct cgraph_node *
+ cgraph_node_for_identifier (id)
+      tree id;
+ {
+   struct cgraph_node **slot;
+ 
+   if (TREE_CODE (id) != IDENTIFIER_NODE)
+     abort ();
+ 
+   if (!cgraph_hash)
+     {
+       cgraph_hash = htab_create (10, hash_node, eq_node, NULL);
+       VARRAY_TREE_INIT (known_fns, 32, "known_fns");
+     }
+ 
+   slot =
+     (struct cgraph_node **) htab_find_slot_with_hash (cgraph_hash, id,
+ 						      htab_hash_pointer (id), 0);
+   if (!slot)
+     return NULL;
+   return *slot;
+ }
+ 
  /* Create edge from CALLER to CALLEE in the cgraph.  */
  
  static struct cgraph_edge *
*************** cgraph_remove_node (node)
*** 192,197 ****
--- 220,249 ----
      node->next->previous = node->previous;
    DECL_SAVED_TREE (node->decl) = NULL;
    /* Do not free the structure itself so the walk over chain can continue.  */
+ }
+ 
+ /* Notify finalize_compilation_unit that given node is reachable
+    or needed.  */
+ void
+ cgraph_mark_needed_node (node, needed)
+      struct cgraph_node *node;
+      int needed;
+ {
+   if (needed)
+     {
+       if (DECL_SAVED_TREE (node->decl))
+         announce_function (node->decl);
+       node->needed = 1;
+     }
+   if (!node->reachable)
+     {
+       node->reachable = 1;
+       if (DECL_SAVED_TREE (node->decl))
+ 	{
+ 	  node->aux = cgraph_nodes_queue;
+ 	  cgraph_nodes_queue = node;
+         }
+     }
  }
  
  
Index: cgraph.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.h,v
retrieving revision 1.4
diff -c -3 -p -r1.4 cgraph.h
*** cgraph.h	8 Mar 2003 13:26:35 -0000	1.4
--- cgraph.h	12 Mar 2003 17:56:11 -0000
*************** struct cgraph_edge
*** 100,105 ****
--- 100,106 ----
  extern struct cgraph_node *cgraph_nodes;
  extern int cgraph_n_nodes;
  extern bool cgraph_global_info_ready;
+ extern struct cgraph_node *cgraph_nodes_queue;
  
  /* In cgraph.c  */
  void dump_cgraph			PARAMS ((FILE *));
*************** void cgraph_remove_call			PARAMS ((tree,
*** 107,112 ****
--- 108,114 ----
  void cgraph_remove_node			PARAMS ((struct cgraph_node *));
  struct cgraph_edge *cgraph_record_call	PARAMS ((tree, tree));
  struct cgraph_node *cgraph_node		PARAMS ((tree decl));
+ struct cgraph_node *cgraph_node_for_identifier	PARAMS ((tree id));
  bool cgraph_calls_p			PARAMS ((tree, tree));
  struct cgraph_local_info *cgraph_local_info PARAMS ((tree));
  struct cgraph_global_info *cgraph_global_info PARAMS ((tree));
Index: cgraphunit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraphunit.c,v
retrieving revision 1.3
diff -c -3 -p -r1.3 cgraphunit.c
*** cgraphunit.c	8 Mar 2003 13:26:35 -0000	1.3
--- cgraphunit.c	12 Mar 2003 17:56:11 -0000
*************** cgraph_finalize_function (decl, body)
*** 64,95 ****
    (*debug_hooks->deferred_inline_function) (decl);
  }
  
- static struct cgraph_node *queue = NULL;
- 
- /* Notify finalize_compilation_unit that given node is reachable
-    or needed.  */
- void
- cgraph_mark_needed_node (node, needed)
-      struct cgraph_node *node;
-      int needed;
- {
-   if (needed)
-     {
-       if (DECL_SAVED_TREE (node->decl))
-         announce_function (node->decl);
-       node->needed = 1;
-     }
-   if (!node->reachable)
-     {
-       node->reachable = 1;
-       if (DECL_SAVED_TREE (node->decl))
- 	{
- 	  node->aux = queue;
- 	  queue = node;
-         }
-     }
- }
- 
  /* Walk tree and record all calls.  Called via walk_tree.  */
  static tree
  record_call_1 (tp, walk_subtrees, data)
--- 64,69 ----
*************** cgraph_finalize_compilation_unit ()
*** 163,174 ****
        functions.  In the future, lowering will introduce new functions and
        new entry points on the way (by template instantiation and virtual
        method table generation for instance).  */
!   while (queue)
      {
!       tree decl = queue->decl;
  
!       node = queue;
!       queue = queue->aux;
        if (node->lowered || !node->reachable || !DECL_SAVED_TREE (decl))
  	abort ();
  
--- 137,148 ----
        functions.  In the future, lowering will introduce new functions and
        new entry points on the way (by template instantiation and virtual
        method table generation for instance).  */
!   while (cgraph_nodes_queue)
      {
!       tree decl = cgraph_nodes_queue->decl;
  
!       node = cgraph_nodes_queue;
!       cgraph_nodes_queue = cgraph_nodes_queue->aux;
        if (node->lowered || !node->reachable || !DECL_SAVED_TREE (decl))
  	abort ();
  
Index: varasm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/varasm.c,v
retrieving revision 1.333
diff -c -3 -p -r1.333 varasm.c
*** varasm.c	9 Mar 2003 20:41:30 -0000	1.333
--- varasm.c	12 Mar 2003 17:56:14 -0000
*************** Software Foundation, 59 Temple Place - S
*** 49,54 ****
--- 49,55 ----
  #include "tm_p.h"
  #include "debug.h"
  #include "target.h"
+ #include "cgraph.h"
  
  #ifdef XCOFF_DEBUGGING_INFO
  #include "xcoffout.h"		/* Needed for external data
*************** assemble_name (file, name)
*** 1734,1740 ****
  
    id = maybe_get_identifier (real_name);
    if (id)
!     TREE_SYMBOL_REFERENCED (id) = 1;
  
    if (name[0] == '*')
      fputs (&name[1], file);
--- 1735,1750 ----
  
    id = maybe_get_identifier (real_name);
    if (id)
!     {
!       if (!TREE_SYMBOL_REFERENCED (id)
! 	  && !cgraph_global_info_ready)
! 	{
! 	  struct cgraph_node *node = cgraph_node_for_identifier (id);
! 	  if (node)
! 	    cgraph_mark_needed_node (node, 1);
! 	}
!       TREE_SYMBOL_REFERENCED (id) = 1;
!     }
  
    if (name[0] == '*')
      fputs (&name[1], file);
Index: cp/cp-lang.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-lang.c,v
retrieving revision 1.48
diff -c -3 -p -r1.48 cp-lang.c
*** cp/cp-lang.c	10 Mar 2003 07:26:33 -0000	1.48
--- cp/cp-lang.c	12 Mar 2003 17:56:15 -0000
*************** static bool cp_var_mod_type_p (tree);
*** 142,147 ****
--- 142,152 ----
  #undef LANG_HOOKS_EXPR_SIZE
  #define LANG_HOOKS_EXPR_SIZE cp_expr_size
  
+ #undef LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION
+ #define LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION really_expand_body
+ #undef LANG_HOOKS_CALLGRAPH_LOWER_FUNCTION
+ #define LANG_HOOKS_CALLGRAPH_LOWER_FUNCTION lower_function
+ 
  #undef LANG_HOOKS_MAKE_TYPE
  #define LANG_HOOKS_MAKE_TYPE cxx_make_type
  #undef LANG_HOOKS_TYPE_FOR_MODE
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.824
diff -c -3 -p -r1.824 cp-tree.h
*** cp/cp-tree.h	11 Mar 2003 15:43:14 -0000	1.824
--- cp/cp-tree.h	12 Mar 2003 17:56:15 -0000
*************** extern tree build_artificial_parm (tree,
*** 3854,3859 ****
--- 3854,3860 ----
  extern tree get_guard (tree);
  extern tree get_guard_cond (tree);
  extern tree set_guard (tree);
+ extern void lower_function (tree);
  
  extern void cp_error_at		(const char *msgid, ...);
  extern void cp_warning_at	(const char *msgid, ...);
*************** extern void clear_out_block             
*** 4206,4211 ****
--- 4207,4213 ----
  extern tree begin_global_stmt_expr              (void);
  extern tree finish_global_stmt_expr             (tree);
  extern tree check_template_template_default_arg (tree);
+ extern void really_expand_body			(tree);
  
  /* in tree.c */
  extern void lang_check_failed			(const char *, int,
Index: cp/decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.604
diff -c -3 -p -r1.604 decl2.c
*** cp/decl2.c	11 Mar 2003 15:43:14 -0000	1.604
--- cp/decl2.c	12 Mar 2003 17:56:15 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 46,51 ****
--- 46,53 ----
  #include "cpplib.h"
  #include "target.h"
  #include "c-common.h"
+ #include "cgraph.h"
+ #include "tree-inline.h"
  extern cpp_reader *parse_in;
  
  /* This structure contains information about the initializations
*************** finish_objects (int method_type, int ini
*** 2018,2023 ****
--- 2020,2026 ----
    finish_compound_stmt (/*has_no_scope=*/0, body);
    fn = finish_function (0);
    expand_body (fn);
+   cgraph_mark_needed_node (cgraph_node (fn), 1);
  
    /* When only doing semantic analysis, and no RTL generation, we
       can't call functions that directly emit assembly code; there is
*************** start_static_storage_duration_function (
*** 2177,2182 ****
--- 2180,2186 ----
  static void
  finish_static_storage_duration_function (tree body)
  {
+   tree decl;
    /* Close out the function.  */
    finish_compound_stmt (/*has_no_scope=*/0, body);
    expand_body (finish_function (0));
*************** generate_ctor_and_dtor_functions_for_pri
*** 2544,2549 ****
--- 2548,2717 ----
    return 0;
  }
  
+ /* Mark all references to static declaration as used.  Called via walk_tree.  */
+ static tree
+ mark_used_decls (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
+ 		 void *data ATTRIBUTE_UNUSED)
+ {
+   if (DECL_P (*tp) && TREE_STATIC (*tp) && DECL_ASSEMBLER_NAME_SET_P (*tp)
+       && TREE_CODE (*tp) != FUNCTION_DECL)
+     TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (*tp)) = 1;
+   return 0;
+ }
+ 
+ /* Called via LANGHOOK_CALLGRAPH_LOWER_FUNCTION.  Make all calls to function explicit
+    and mark all data references by the function to be output.  */
+ void
+ lower_function (tree fn)
+ {
+   bool reconsider = true;
+   tree t;
+   tree vars;
+   unsigned int i;
+ 
+   import_export_decl (fn);
+   
+   /* Does it need synthesizing?  */
+   if (DECL_ARTIFICIAL (fn) && ! DECL_INITIAL (fn)
+       && TREE_USED (fn)
+       && (! DECL_REALLY_EXTERN (fn) || DECL_INLINE (fn)))
+     {
+       /* Even though we're already at the top-level, we push
+ 	 there again.  That way, when we pop back a few lines
+ 	 hence, all of our state is restored.  Otherwise,
+ 	 finish_function doesn't clean things up, and we end
+ 	 up with CURRENT_FUNCTION_DECL set.  */
+       push_to_top_level ();
+       synthesize_method (fn);
+       pop_from_top_level ();
+       reconsider = true;
+     }
+ 
+   /* Assume that all referenced static variables will actually be used.
+      This is overactive and will need to be improved using AST.  */
+   walk_tree (&DECL_SAVED_TREE (fn), mark_used_decls, NULL, NULL);
+ 
+   while (reconsider)
+     {
+       reconsider = false;
+ 
+       /* If there are templates that we've put off instantiating, do
+ 	 them now.  */
+       instantiate_pending_templates ();
+ 
+       /* Write out virtual tables as required.  Note that writing out
+   	 the virtual table for a template class may cause the
+  	 instantiation of members of that class.  If we write out
+  	 vtables then we remove the class from our list so we don't
+  	 have to look at it again. */
+  
+       while (keyed_classes != NULL_TREE
+  	     && maybe_emit_vtables (TREE_VALUE (keyed_classes)))
+  	{
+   	  reconsider = 1;
+  	  keyed_classes = TREE_CHAIN (keyed_classes);
+  	}
+  
+       t = keyed_classes;
+       if (t != NULL_TREE)
+  	{
+  	  tree next = TREE_CHAIN (t);
+  
+  	  while (next)
+  	    {
+  	      if (maybe_emit_vtables (TREE_VALUE (next)))
+  		{
+  		  reconsider = 1;
+  		  TREE_CHAIN (t) = TREE_CHAIN (next);
+  		}
+  	      else
+  		t = next;
+  
+  	      next = TREE_CHAIN (t);
+  	    }
+  	}
+        
+       /* Write out needed type info variables. Writing out one variable
+          might cause others to be needed.  */
+       if (walk_globals (unemitted_tinfo_decl_p, emit_tinfo_decl, /*data=*/0))
+ 	reconsider = true;
+ 
+       /* The list of objects with static storage duration is built up
+ 	 in reverse order.  We clear STATIC_AGGREGATES so that any new
+ 	 aggregates added during the initialization of these will be
+ 	 initialized in the correct order when we next come around the
+ 	 loop.  */
+       vars = prune_vars_needing_no_initialization (&static_aggregates);
+ 
+       if (vars)
+ 	{
+ 	  tree v;
+ 
+ 	  /* We need to start a new initialization function each time
+ 	     through the loop.  That's because we need to know which
+ 	     vtables have been referenced, and TREE_SYMBOL_REFERENCED
+ 	     isn't computed until a function is finished, and written
+ 	     out.  That's a deficiency in the back-end.  When this is
+ 	     fixed, these initialization functions could all become
+ 	     inline, with resulting performance improvements.  */
+ 	  tree ssdf_body = start_static_storage_duration_function ();
+ 
+ 	  /* Make sure the back end knows about all the variables.  */
+ 	  write_out_vars (vars);
+ 
+ 	  /* First generate code to do all the initializations.  */
+ 	  for (v = vars; v; v = TREE_CHAIN (v))
+ 	    do_static_initialization (TREE_VALUE (v),
+ 				      TREE_PURPOSE (v));
+ 
+ 	  /* Then, generate code to do all the destructions.  Do these
+ 	     in reverse order so that the most recently constructed
+ 	     variable is the first destroyed.  If we're using
+ 	     __cxa_atexit, then we don't need to do this; functions
+ 	     were registered at initialization time to destroy the
+ 	     local statics.  */
+ 	  if (!flag_use_cxa_atexit)
+ 	    {
+ 	      vars = nreverse (vars);
+ 	      for (v = vars; v; v = TREE_CHAIN (v))
+ 		do_static_destruction (TREE_VALUE (v));
+ 	    }
+ 	  else
+ 	    vars = NULL_TREE;
+ 
+ 	  /* Finish up the static storage duration function for this
+ 	     round.  */
+ 	  finish_static_storage_duration_function (ssdf_body);
+ 
+ 	  /* All those initializations and finalizations might cause
+ 	     us to need more inline functions, more template
+ 	     instantiations, etc.  */
+ 	  reconsider = true;
+ 	}
+       
+       if (deferred_fns_used
+ 	  && wrapup_global_declarations (&VARRAY_TREE (deferred_fns, 0),
+ 					 deferred_fns_used))
+ 	reconsider = true;
+       if (walk_namespaces (wrapup_globals_for_namespace, /*data= */ 0))
+ 	reconsider = true;
+       /* Static data members are just like namespace-scope globals.  */
+       for (i = 0; i < pending_statics_used; ++i)
+ 	{
+ 	  tree decl = VARRAY_TREE (pending_statics, i);
+ 	  if (TREE_ASM_WRITTEN (decl))
+ 	    continue;
+ 	  import_export_decl (decl);
+ 	  if (DECL_NOT_REALLY_EXTERN (decl) && !DECL_IN_AGGR_P (decl))
+ 	    DECL_EXTERNAL (decl) = 0;
+ 	}
+       if (pending_statics
+ 	  && wrapup_global_declarations (&VARRAY_TREE (pending_statics, 0),
+ 					 pending_statics_used))
+ 	reconsider = true;
+     }
+ }
+ 
  /* This routine is called from the last rule in yyparse ().
     Its job is to create all the code needed to initialize and
     destroy the global aggregates.  We do the destruction
*************** finish_file ()
*** 2736,2741 ****
--- 2904,2910 ----
  	  if (!DECL_EXTERNAL (decl)
  	      && DECL_NEEDED_P (decl)
  	      && DECL_SAVED_TREE (decl)
+ 	      && !flag_unit_at_a_time
  	      && !TREE_ASM_WRITTEN (decl))
  	    {
  	      int saved_not_really_extern;
*************** finish_file ()
*** 2783,2804 ****
      } 
    while (reconsider);
  
    /* All used inline functions must have a definition at this point. */
!   for (i = 0; i < deferred_fns_used; ++i)
!     {
!       tree decl = VARRAY_TREE (deferred_fns, i);
! 
!       if (TREE_USED (decl) && DECL_DECLARED_INLINE_P (decl)
! 	  && !(TREE_ASM_WRITTEN (decl) || DECL_SAVED_TREE (decl)))
! 	{
! 	  cp_warning_at ("inline function `%D' used but never defined", decl);
! 	  /* This symbol is effectively an "extern" declaration now.
! 	     This is not strictly necessary, but removes a duplicate
! 	     warning.  */
! 	  TREE_PUBLIC (decl) = 1;
! 	}
!       
!     }
    
    /* We give C linkage to static constructors and destructors.  */
    push_lang_context (lang_name_c);
--- 2952,2974 ----
      } 
    while (reconsider);
  
+   if (!flag_unit_at_a_time)
    /* All used inline functions must have a definition at this point. */
!     for (i = 0; i < deferred_fns_used; ++i)
!       {
! 	tree decl = VARRAY_TREE (deferred_fns, i);
! 
! 	if (TREE_USED (decl) && DECL_DECLARED_INLINE_P (decl)
! 	    && !(TREE_ASM_WRITTEN (decl) || DECL_SAVED_TREE (decl)))
! 	  {
! 	    cp_warning_at ("inline function `%D' used but never defined", decl);
! 	    /* This symbol is effectively an "extern" declaration now.
! 	       This is not strictly necessary, but removes a duplicate
! 	       warning.  */
! 	    TREE_PUBLIC (decl) = 1;
! 	  }
! 	
!       }
    
    /* We give C linkage to static constructors and destructors.  */
    push_lang_context (lang_name_c);
*************** finish_file ()
*** 2809,2814 ****
--- 2979,2989 ----
      splay_tree_foreach (priority_info_map, 
  			generate_ctor_and_dtor_functions_for_priority,
  			/*data=*/0);
+   if (flag_unit_at_a_time)
+     {
+       cgraph_finalize_compilation_unit ();
+       cgraph_optimize ();
+     }
  
    /* We're done with the splay-tree now.  */
    if (priority_info_map)
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.669
diff -c -3 -p -r1.669 pt.c
*** cp/pt.c	4 Mar 2003 01:13:38 -0000	1.669
--- cp/pt.c	12 Mar 2003 17:56:16 -0000
*************** instantiate_decl (d, defer_ok)
*** 10893,10899 ****
        local_specializations = saved_local_specializations;
  
        /* Finish the function.  */
!       expand_body (finish_function (0));
      }
  
    /* We're not deferring instantiation any more.  */
--- 10893,10899 ----
        local_specializations = saved_local_specializations;
  
        /* Finish the function.  */
!       really_expand_body (finish_function (0));
      }
  
    /* We're not deferring instantiation any more.  */
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.299
diff -c -3 -p -r1.299 semantics.c
*** cp/semantics.c	8 Mar 2003 18:47:41 -0000	1.299
--- cp/semantics.c	12 Mar 2003 17:56:17 -0000
***************
*** 41,46 ****
--- 41,47 ----
  #include "output.h"
  #include "timevar.h"
  #include "debug.h"
+ #include "cgraph.h"
  
  /* There routines provide a modular interface to perform many parsing
     operations.  They may therefore be used during actual parsing, or
*************** emit_associated_thunks (fn)
*** 2294,2372 ****
      }
  }
  
- /* Generate RTL for FN.  */
- 
  void
! expand_body (fn)
       tree fn;
  {
    int saved_lineno;
    const char *saved_input_filename;
    tree saved_function;
  
-   /* When the parser calls us after finishing the body of a template
-      function, we don't really want to expand the body.  When we're
-      processing an in-class definition of an inline function,
-      PROCESSING_TEMPLATE_DECL will no longer be set here, so we have
-      to look at the function itself.  */
-   if (processing_template_decl
-       || (DECL_LANG_SPECIFIC (fn) 
- 	  && DECL_TEMPLATE_INFO (fn)
- 	  && uses_template_parms (DECL_TI_ARGS (fn))))
-     {
-       /* Normally, collection only occurs in rest_of_compilation.  So,
- 	 if we don't collect here, we never collect junk generated
- 	 during the processing of templates until we hit a
- 	 non-template function.  */
-       ggc_collect ();
-       return;
-     }
- 
-   /* Replace AGGR_INIT_EXPRs with appropriate CALL_EXPRs.  */
-   walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
- 				simplify_aggr_init_exprs_r,
- 				NULL);
- 
-   /* If this is a constructor or destructor body, we have to clone
-      it.  */
-   if (maybe_clone_body (fn))
-     {
-       /* We don't want to process FN again, so pretend we've written
- 	 it out, even though we haven't.  */
-       TREE_ASM_WRITTEN (fn) = 1;
-       return;
-     }
- 
-   /* There's no reason to do any of the work here if we're only doing
-      semantic analysis; this code just generates RTL.  */
-   if (flag_syntax_only)
-     return;
- 
-   /* If possible, avoid generating RTL for this function.  Instead,
-      just record it as an inline function, and wait until end-of-file
-      to decide whether to write it out or not.  */
-   if (/* We have to generate RTL if it's not an inline function.  */
-       (DECL_INLINE (fn) || DECL_COMDAT (fn))
-       /* Or if we have to emit code for inline functions anyhow.  */
-       && !flag_keep_inline_functions
-       /* Or if we actually have a reference to the function.  */
-       && !DECL_NEEDED_P (fn))
-     {
-       /* Set DECL_EXTERNAL so that assemble_external will be called as
- 	 necessary.  We'll clear it again in finish_file.  */
-       if (!DECL_EXTERNAL (fn))
- 	{
- 	  DECL_NOT_REALLY_EXTERN (fn) = 1;
- 	  DECL_EXTERNAL (fn) = 1;
- 	}
-       /* Remember this function.  In finish_file we'll decide if
- 	 we actually need to write this function out.  */
-       defer_fn (fn);
-       /* Let the back-end know that this function exists.  */
-       (*debug_hooks->deferred_inline_function) (fn);
-       return;
-     }
- 
    /* Compute the appropriate object-file linkage for inline
       functions.  */
    if (DECL_DECLARED_INLINE_P (fn))
--- 2295,2308 ----
      }
  }
  
  void
! really_expand_body (fn)
       tree fn;
  {
    int saved_lineno;
    const char *saved_input_filename;
    tree saved_function;
  
    /* Compute the appropriate object-file linkage for inline
       functions.  */
    if (DECL_DECLARED_INLINE_P (fn))
*************** expand_body (fn)
*** 2438,2443 ****
--- 2374,2467 ----
  
    /* Emit any thunks that should be emitted at the same time as FN.  */
    emit_associated_thunks (fn);
+ }
+ 
+ /* Generate RTL for FN.  */
+ 
+ void
+ expand_body (fn)
+      tree fn;
+ {
+   /* When the parser calls us after finishing the body of a template
+      function, we don't really want to expand the body.  When we're
+      processing an in-class definition of an inline function,
+      PROCESSING_TEMPLATE_DECL will no longer be set here, so we have
+      to look at the function itself.  */
+   if (processing_template_decl
+       || (DECL_LANG_SPECIFIC (fn) 
+ 	  && DECL_TEMPLATE_INFO (fn)
+ 	  && uses_template_parms (DECL_TI_ARGS (fn))))
+     {
+       /* Normally, collection only occurs in rest_of_compilation.  So,
+ 	 if we don't collect here, we never collect junk generated
+ 	 during the processing of templates until we hit a
+ 	 non-template function.  */
+       ggc_collect ();
+       return;
+     }
+ 
+   /* Replace AGGR_INIT_EXPRs with appropriate CALL_EXPRs.  */
+   walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
+ 				simplify_aggr_init_exprs_r,
+ 				NULL);
+ 
+   /* If this is a constructor or destructor body, we have to clone
+      it.  */
+   if (maybe_clone_body (fn))
+     {
+       /* We don't want to process FN again, so pretend we've written
+ 	 it out, even though we haven't.  */
+       TREE_ASM_WRITTEN (fn) = 1;
+       return;
+     }
+ 
+   /* There's no reason to do any of the work here if we're only doing
+      semantic analysis; this code just generates RTL.  */
+   if (flag_syntax_only)
+     return;
+ 
+   if (flag_unit_at_a_time)
+     {
+ #if 0
+       /* Set DECL_EXTERNAL so that assemble_external will be called as
+ 	 necessary.  We'll clear it again in finish_file.  */
+       if (!DECL_EXTERNAL (fn))
+ 	{
+ 	  DECL_NOT_REALLY_EXTERN (fn) = 1;
+ 	  DECL_EXTERNAL (fn) = 1;
+ 	}
+ #endif
+       cgraph_finalize_function (fn, DECL_SAVED_TREE (fn));
+       current_function_decl = NULL;
+       return;
+     }
+ 
+   /* If possible, avoid generating RTL for this function.  Instead,
+      just record it as an inline function, and wait until end-of-file
+      to decide whether to write it out or not.  */
+   if (/* We have to generate RTL if it's not an inline function.  */
+       (DECL_INLINE (fn) || DECL_COMDAT (fn))
+       /* Or if we have to emit code for inline functions anyhow.  */
+       && !flag_keep_inline_functions
+       /* Or if we actually have a reference to the function.  */
+       && !DECL_NEEDED_P (fn))
+     {
+       /* Set DECL_EXTERNAL so that assemble_external will be called as
+ 	 necessary.  We'll clear it again in finish_file.  */
+       if (!DECL_EXTERNAL (fn))
+ 	{
+ 	  DECL_NOT_REALLY_EXTERN (fn) = 1;
+ 	  DECL_EXTERNAL (fn) = 1;
+ 	}
+       /* Remember this function.  In finish_file we'll decide if
+ 	 we actually need to write this function out.  */
+       defer_fn (fn);
+       /* Let the back-end know that this function exists.  */
+       (*debug_hooks->deferred_inline_function) (fn);
+       return;
+     }
+ 
+   really_expand_body (fn);
  }
  
  /* Helper function for walk_tree, used by finish_function to override all


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