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]

Re: [C++ patch] final? unit-at-a-time patch


> On Sat, 2003-06-21 at 15:31, Jan Hubicka wrote:
> > Hi,
> > this patch finally implements unit-at-a-time mode in C++.  I
> > regtested/bootstrapped it in both unit-at-a-time and non-unit-at-a-time mode.
> > In unit-at-a-time mode it still fails with testcase pretty1.c/pretty2.c, but I
> > can trigger same failure by deferring the functions via inline keyword, so it
> > is latent bug I will try to fix shortly too.
> 
> That needs to get fixed *before* we put in the unit-at-a-time stuff.
> 
> really_expand_body needs a better name. :-)  Probably "expand_body"
> should be renamed to expand_or_defer_fn and "really_expand_body" should
> be renamed to "expand_body".
> 
> Other than that, this patch looks OK to me.

Mark,
since the dust of varpool patch (darwin regressions) has finally settled
down, I would like to proceed on C++ unit-at-a-time. 
Here is updated patch.  It uses renamed varpool functions as
Richard requested, renames really_expand_body as you did and adds
lower_function hook to mention member pointer references as these are
not visible to cgraph code.

The patch depends on the deffering versus flag mangling patch:
http://gcc.gnu.org/ml/gcc-patches/2003-06/msg02495.html

It would be truly great if you were able to take on these before stage2
:)

Regtested bootstrapped i386, x86-64 (after reverting Eric's patch that
prevents bootstrap).  The pretty1/pretty2 failures are actually in the
current tree too, I just imported them with a merge into my tree and
started to count them as regressions, so there are no new regressions
now.
OK?

Sun Jun 22 02:21:27 CEST 2003  Jan Hubicka  <jh@suse.cz>

	* cp-tree.h (DECL_NEEDED_P): Support unit-at-a-time
	(expand_or_defer_fn): Declare.
	(lower_function): Declare.
	* decl.c (start_cleanup_fn): Use expand_or_defer_fn.
	* decl2.c: Include cgraph.h and varpool.h
	(comdat_linkage):  Make explicit instantations as needed.
	(mark_member_pointers, lower_function): New functions.
	(finish_file): Do unit-at-a-time.
	* method.c (synthesize_method): Use expand_or_defer_fn.
	* optimize.c (maybe_clone_body): Use expand_or_defer_fn.
	* parser.c (cp_parser_function_definition_after_decl): Use
	expand_or_defer_fn.
	* pt.c (instantiate_decl): Likewise.
	* semantics.c: Include cgraph.h
	(expand_or_defer_fn): Break out from ...
	(expand_body): ... here; deal with unit-at-a-time.
	* cp-lang.c (LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION,
	LANG_HOOKS_CALLGRAPH_LOWER_FUNCTION): Define.
Index: Make-lang.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/Make-lang.in,v
retrieving revision 1.154
diff -c -3 -p -r1.154 Make-lang.in
*** Make-lang.in	23 Jun 2003 20:52:12 -0000	1.154
--- Make-lang.in	27 Jun 2003 21:23:29 -0000
*************** cp/decl.o: cp/decl.c $(CXX_TREE_H) $(TM_
*** 241,247 ****
    cp/operators.def $(TM_P_H) tree-inline.h diagnostic.h c-pragma.h \
    debug.h gt-cp-decl.h gtype-cp.h timevar.h
  cp/decl2.o: cp/decl2.c $(CXX_TREE_H) $(TM_H) flags.h cp/lex.h cp/decl.h $(EXPR_H) \
!   output.h except.h toplev.h $(RTL_H) c-common.h gt-cp-decl2.h
  cp/typeck2.o: cp/typeck2.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h output.h $(TM_P_H) \
     diagnostic.h
  cp/typeck.o: cp/typeck.c $(CXX_TREE_H) $(TM_H) flags.h $(RTL_H) $(EXPR_H) toplev.h \
--- 241,247 ----
    cp/operators.def $(TM_P_H) tree-inline.h diagnostic.h c-pragma.h \
    debug.h gt-cp-decl.h gtype-cp.h timevar.h
  cp/decl2.o: cp/decl2.c $(CXX_TREE_H) $(TM_H) flags.h cp/lex.h cp/decl.h $(EXPR_H) \
!   output.h except.h toplev.h $(RTL_H) c-common.h gt-cp-decl2.h cgraph.h
  cp/typeck2.o: cp/typeck2.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h output.h $(TM_P_H) \
     diagnostic.h
  cp/typeck.o: cp/typeck.c $(CXX_TREE_H) $(TM_H) flags.h $(RTL_H) $(EXPR_H) toplev.h \
*************** cp/repo.o: cp/repo.c $(CXX_TREE_H) $(TM_
*** 272,278 ****
    gt-cp-repo.h
  cp/semantics.o: cp/semantics.c $(CXX_TREE_H) $(TM_H) cp/lex.h except.h toplev.h \
    flags.h debug.h output.h $(RTL_H) $(TIMEVAR_H) $(EXPR_H) \
!   tree-inline.h
  cp/dump.o: cp/dump.c $(CXX_TREE_H) $(TM_H) tree-dump.h
  cp/optimize.o: cp/optimize.c $(CXX_TREE_H) $(TM_H) rtl.h integrate.h insn-config.h \
    input.h $(PARAMS_H) debug.h tree-inline.h
--- 272,278 ----
    gt-cp-repo.h
  cp/semantics.o: cp/semantics.c $(CXX_TREE_H) $(TM_H) cp/lex.h except.h toplev.h \
    flags.h debug.h output.h $(RTL_H) $(TIMEVAR_H) $(EXPR_H) \
!   tree-inline.h cgraph.h
  cp/dump.o: cp/dump.c $(CXX_TREE_H) $(TM_H) tree-dump.h
  cp/optimize.o: cp/optimize.c $(CXX_TREE_H) $(TM_H) rtl.h integrate.h insn-config.h \
    input.h $(PARAMS_H) debug.h tree-inline.h
Index: cp-lang.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-lang.c,v
retrieving revision 1.51
diff -c -3 -p -r1.51 cp-lang.c
*** cp-lang.c	24 Jun 2003 11:54:00 -0000	1.51
--- cp-lang.c	27 Jun 2003 21:23:29 -0000
*************** static bool cp_var_mod_type_p (tree);
*** 148,153 ****
--- 148,158 ----
  #undef LANG_HOOKS_PREPARE_ASSEMBLE_VARIABLE 
  #define LANG_HOOKS_PREPARE_ASSEMBLE_VARIABLE prepare_assemble_variable
  
+ #undef LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION
+ #define LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION 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-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.860
diff -c -3 -p -r1.860 cp-tree.h
*** cp-tree.h	26 Jun 2003 00:06:58 -0000	1.860
--- cp-tree.h	27 Jun 2003 21:23:29 -0000
*************** struct lang_decl GTY(())
*** 1746,1752 ****
    ((at_eof && TREE_PUBLIC (DECL) && !DECL_COMDAT (DECL))	\
     || (DECL_ASSEMBLER_NAME_SET_P (DECL)				\
         && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (DECL)))	\
!    || (flag_syntax_only && TREE_USED (DECL)))
  
  /* For a FUNCTION_DECL or a VAR_DECL, the language linkage for the
     declaration.  Some entities (like a member function in a local
--- 1746,1752 ----
    ((at_eof && TREE_PUBLIC (DECL) && !DECL_COMDAT (DECL))	\
     || (DECL_ASSEMBLER_NAME_SET_P (DECL)				\
         && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (DECL)))	\
!    || (((flag_syntax_only || flag_unit_at_a_time) && TREE_USED (DECL))))
  
  /* For a FUNCTION_DECL or a VAR_DECL, the language linkage for the
     declaration.  Some entities (like a member function in a local
*************** extern tree get_guard (tree);
*** 3800,3805 ****
--- 3800,3806 ----
  extern tree get_guard_cond (tree);
  extern tree set_guard (tree);
  extern void prepare_assemble_variable (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             
*** 4154,4159 ****
--- 4155,4161 ----
  extern tree begin_global_stmt_expr              (void);
  extern tree finish_global_stmt_expr             (tree);
  extern tree check_template_template_default_arg (tree);
+ extern void expand_or_defer_fn			(tree);
  
  /* in tree.c */
  extern void lang_check_failed			(const char *, int,
Index: decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1072
diff -c -3 -p -r1.1072 decl.c
*** decl.c	24 Jun 2003 15:40:02 -0000	1.1072
--- decl.c	27 Jun 2003 21:23:30 -0000
*************** start_cleanup_fn (void)
*** 8442,8448 ****
  static void
  end_cleanup_fn (void)
  {
!   expand_body (finish_function (0));
  
    pop_from_top_level ();
  }
--- 8442,8448 ----
  static void
  end_cleanup_fn (void)
  {
!   expand_or_defer_fn (finish_function (0));
  
    pop_from_top_level ();
  }
Index: decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.632
diff -c -3 -p -r1.632 decl2.c
*** decl2.c	24 Jun 2003 11:54:01 -0000	1.632
--- decl2.c	27 Jun 2003 21:23:30 -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
*************** mark_vtable_entries (tree decl)
*** 1419,1424 ****
--- 1421,1428 ----
  void
  comdat_linkage (tree decl)
  {
+   bool needed = TREE_PUBLIC (decl) && !DECL_COMDAT (decl);
+ 
    if (flag_weak)
      make_decl_one_only (decl);
    else if (TREE_CODE (decl) == FUNCTION_DECL 
*************** comdat_linkage (tree decl)
*** 1463,1468 ****
--- 1467,1481 ----
  
    if (DECL_LANG_SPECIFIC (decl))
      DECL_COMDAT (decl) = 1;
+ 
+   /* Explicit instantiation:  inform middle end that the decl is needed
+      even tought it is COMDAT. 
+      ??? This would be cleaner if we had a flag expressing that decl
+      is weak, but it is not COMDAT in a sense that it can be emit
+      when not needed.  */
+   if (flag_unit_at_a_time && at_eof && needed
+       && TREE_CODE (decl) == VAR_DECL)
+     cgraph_varpool_mark_needed_node (cgraph_varpool_node (decl));
  }
  
  /* For win32 we also want to put explicit instantiations in
*************** finish_objects (int method_type, int ini
*** 2015,2021 ****
    /* Finish up.  */
    finish_compound_stmt (/*has_no_scope=*/0, body);
    fn = finish_function (0);
!   expand_body (fn);
  
    /* When only doing semantic analysis, and no RTL generation, we
       can't call functions that directly emit assembly code; there is
--- 2028,2034 ----
    /* Finish up.  */
    finish_compound_stmt (/*has_no_scope=*/0, body);
    fn = finish_function (0);
!   expand_or_defer_fn (fn);
  
    /* When only doing semantic analysis, and no RTL generation, we
       can't call functions that directly emit assembly code; there is
*************** finish_static_storage_duration_function 
*** 2168,2174 ****
  {
    /* Close out the function.  */
    finish_compound_stmt (/*has_no_scope=*/0, body);
!   expand_body (finish_function (0));
  }
  
  /* Return the information about the indicated PRIORITY level.  If no
--- 2181,2187 ----
  {
    /* Close out the function.  */
    finish_compound_stmt (/*has_no_scope=*/0, body);
!   expand_or_defer_fn (finish_function (0));
  }
  
  /* Return the information about the indicated PRIORITY level.  If no
*************** generate_ctor_and_dtor_functions_for_pri
*** 2555,2560 ****
--- 2568,2593 ----
    return 0;
  }
  
+ /* Callgraph code does not understand the member pointers.  Mark the methods
+    referenced as used.  */
+ static tree
+ mark_member_pointers (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
+ 		      void *data ATTRIBUTE_UNUSED)
+ {
+   if (TREE_CODE (*tp) == PTRMEM_CST)
+     cgraph_mark_needed_node (cgraph_node (PTRMEM_CST_MEMBER (*tp)), 1);
+   return 0;
+ }
+ 
+ /* Called via LANGHOOK_CALLGRAPH_LOWER_FUNCTION.  It is supposed to lower
+    frontend specific constructs that would otherwise confuse the middle end.  */
+ void
+ lower_function (tree fn)
+ {
+   walk_tree_without_duplicates (&DECL_SAVED_TREE (fn), mark_member_pointers,
+ 				NULL);
+ }
+ 
  /* 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 ()
*** 2802,2808 ****
  	      saved_not_really_extern = DECL_NOT_REALLY_EXTERN (decl);
  	      /* Generate RTL for this function now that we know we
  		 need it.  */
! 	      expand_body (decl);
  	      /* Undo the damage done by finish_function.  */
  	      DECL_EXTERNAL (decl) = 0;
  	      DECL_NOT_REALLY_EXTERN (decl) = saved_not_really_extern;
--- 2835,2841 ----
  	      saved_not_really_extern = DECL_NOT_REALLY_EXTERN (decl);
  	      /* Generate RTL for this function now that we know we
  		 need it.  */
! 	      expand_or_defer_fn (decl);
  	      /* Undo the damage done by finish_function.  */
  	      DECL_EXTERNAL (decl) = 0;
  	      DECL_NOT_REALLY_EXTERN (decl) = saved_not_really_extern;
*************** finish_file ()
*** 2887,2892 ****
--- 2920,2931 ----
    /* We're done with static constructors, so we can go back to "C++"
       linkage now.  */
    pop_lang_context ();
+ 
+   if (flag_unit_at_a_time)
+     {
+       cgraph_finalize_compilation_unit ();
+       cgraph_optimize ();
+     }
  
    /* Now, issue warnings about static, but not defined, functions,
       etc., and emit debugging information.  */
Index: method.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/method.c,v
retrieving revision 1.257
diff -c -3 -p -r1.257 method.c
*** method.c	24 Jun 2003 15:40:03 -0000	1.257
--- method.c	27 Jun 2003 21:23:31 -0000
*************** use_thunk (tree thunk_fndecl, bool emit_
*** 581,587 ****
        /* Re-enable access control.  */
        pop_deferring_access_checks ();
  
!       expand_body (finish_function (0));
      }
  
    pop_from_top_level ();
--- 581,587 ----
        /* Re-enable access control.  */
        pop_deferring_access_checks ();
  
!       expand_or_defer_fn (finish_function (0));
      }
  
    pop_from_top_level ();
*************** synthesize_method (tree fndecl)
*** 862,868 ****
      }
  
    finish_function_body (stmt);
!   expand_body (finish_function (0));
  
    extract_interface_info ();
    if (! context)
--- 862,868 ----
      }
  
    finish_function_body (stmt);
!   expand_or_defer_fn (finish_function (0));
  
    extract_interface_info ();
    if (! context)
Index: optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/optimize.c,v
retrieving revision 1.91
diff -c -3 -p -r1.91 optimize.c
*** optimize.c	18 Jun 2003 05:58:53 -0000	1.91
--- optimize.c	27 Jun 2003 21:23:31 -0000
*************** maybe_clone_body (tree fn)
*** 265,271 ****
        /* Now, expand this function into RTL, if appropriate.  */
        finish_function (0);
        BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
!       expand_body (clone);
        pop_from_top_level ();
      }
  
--- 265,271 ----
        /* Now, expand this function into RTL, if appropriate.  */
        finish_function (0);
        BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
!       expand_or_defer_fn (clone);
        pop_from_top_level ();
      }
  
Index: parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.66
diff -c -3 -p -r1.66 parser.c
*** parser.c	24 Jun 2003 15:40:03 -0000	1.66
--- parser.c	27 Jun 2003 21:23:32 -0000
*************** cp_parser_function_definition_after_decl
*** 13850,13856 ****
    fn = finish_function ((ctor_initializer_p ? 1 : 0) | 
  			(inline_p ? 2 : 0));
    /* Generate code for it, if necessary.  */
!   expand_body (fn);
    /* Restore the saved values.  */
    parser->in_unbraced_linkage_specification_p 
      = saved_in_unbraced_linkage_specification_p;
--- 13850,13856 ----
    fn = finish_function ((ctor_initializer_p ? 1 : 0) | 
  			(inline_p ? 2 : 0));
    /* Generate code for it, if necessary.  */
!   expand_or_defer_fn (fn);
    /* Restore the saved values.  */
    parser->in_unbraced_linkage_specification_p 
      = saved_in_unbraced_linkage_specification_p;
Index: pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.706
diff -c -3 -p -r1.706 pt.c
*** pt.c	26 Jun 2003 12:59:45 -0000	1.706
--- pt.c	27 Jun 2003 21:23:32 -0000
*************** instantiate_decl (tree d, int defer_ok)
*** 10939,10945 ****
  
        /* Finish the function.  */
        d = finish_function (0);
!       expand_body (d);
      }
  
    /* We're not deferring instantiation any more.  */
--- 10939,10945 ----
  
        /* Finish the function.  */
        d = finish_function (0);
!       expand_or_defer_fn (d);
      }
  
    /* We're not deferring instantiation any more.  */
Index: semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.314
diff -c -3 -p -r1.314 semantics.c
*** semantics.c	24 Jun 2003 15:40:05 -0000	1.314
--- semantics.c	27 Jun 2003 21:23:33 -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
*************** expand_body (tree fn)
*** 2279,2347 ****
  {
    location_t saved_loc;
    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.  */
--- 2280,2288 ----
  {
    location_t saved_loc;
    tree saved_function;
!   
!   if (flag_unit_at_a_time && !cgraph_global_info_ready)
!     abort ();
  
    /* Compute the appropriate object-file linkage for inline
       functions.  */
*************** expand_body (tree fn)
*** 2411,2416 ****
--- 2352,2459 ----
  
    /* Emit any thunks that should be emitted at the same time as FN.  */
    emit_associated_thunks (fn);
+ }
+ 
+ /* Generate RTL for FN.  */
+ 
+ void
+ expand_or_defer_fn (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 && cgraph_global_info_ready)
+     abort ();
+ 
+   if (flag_unit_at_a_time && !cgraph_global_info_ready)
+     {
+       if (at_eof)
+ 	{
+ 	  /* Compute the appropriate object-file linkage for inline
+ 	     functions.  */
+ 	  if (DECL_DECLARED_INLINE_P (fn))
+ 	    import_export_decl (fn);
+ 	  cgraph_finalize_function (fn, DECL_SAVED_TREE (fn));
+ 	}
+       else
+ 	{
+ 	  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;
+     }
+ 
+ 
+   /* 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;
+     }
+ 
+   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]