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]

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


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.

The libstdc++ is about 11K smaller than without unit-at-a-time and compiles in
the same time.  I got similar results on eon benchmark (2% code size decrease)
and few other C++ programs I compiled so I think it can be enabled by default
at -O3 level unless we hit some inexpected problems. (I still expect
some but I will try to take care to fix these)

OK for mainline?

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_body): Declare.
	* decl2.c: Include cgraph.h and varpool.h
	(comdat_linkage):  Make explicit instantations as needed.
	(finish_file): Do unit-at-a-time.
	* semantics.c: Include cgraph.h
	(really_expand_body): Break out from ...
	(expand_body): ... here; deal with unit-at-a-time.

diff -Nrc3p gcc.tmp/cp/cp-tree.h gcc/cp/cp-tree.h
*** gcc.tmp/cp/cp-tree.h	Sun Jun 22 01:50:33 2003
--- gcc/cp/cp-tree.h	Fri Jun 20 23:09:59 2003
*************** struct lang_decl GTY(())
*** 1745,1751 ****
    ((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
--- 1745,1751 ----
    ((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 void clear_out_block             
*** 4146,4151 ****
--- 4147,4153 ----
  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,
diff -Nrc3p gcc.tmp/cp/decl2.c gcc/cp/decl2.c
*** gcc.tmp/cp/decl2.c	Sun Jun 22 01:58:32 2003
--- gcc/cp/decl2.c	Sat Jun 21 23:28:01 2003
*************** Boston, MA 02111-1307, USA.  */
*** 46,51 ****
--- 46,53 ----
  #include "cpplib.h"
  #include "target.h"
  #include "c-common.h"
+ #include "cgraph.h"
+ #include "varpool.h"
  extern cpp_reader *parse_in;
  
  /* This structure contains information about the initializations
*************** mark_vtable_entries (tree decl)
*** 1422,1427 ****
--- 1425,1432 ----
  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)
*** 1466,1471 ****
--- 1471,1485 ----
  
    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)
+     varpool_mark_needed_node (varpool_node (decl));
  }
  
  /* For win32 we also want to put explicit instantiations in
*************** finish_file ()
*** 2873,2878 ****
--- 2914,2925 ----
       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.  */
    walk_namespaces (wrapup_globals_for_namespace, /*data=*/&reconsider);
diff -Nrc3p gcc.tmp/cp/semantics.c gcc/cp/semantics.c
*** gcc.tmp/cp/semantics.c	Sun Jun 22 01:50:33 2003
--- gcc/cp/semantics.c	Sat Jun 21 21:47:06 2003
***************
*** 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)
*** 2380,2453 ****
  /* Generate RTL for FN.  */
  
  void
! expand_body (fn)
       tree fn;
  {
    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.  */
--- 2381,2394 ----
  /* Generate RTL for FN.  */
  
  void
! really_expand_body (fn)
       tree fn;
  {
    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 (fn)
*** 2519,2524 ****
--- 2460,2567 ----
    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 && 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;
+     }
+ 
+   really_expand_body (fn);
+ }
+ 
  /* Helper function for walk_tree, used by finish_function to override all
     the RETURN_STMTs and pertinent CLEANUP_STMTs for the named return
     value optimization.  */
*** gcc.tmp/cp/cp-lang.c	Sun Jun 22 01:50:33 2003
--- gcc/cp/cp-lang.c	Fri Jun 20 23:09:59 2003
*************** static bool cp_var_mod_type_p (tree);
*** 145,150 ****
--- 145,153 ----
  #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_MAKE_TYPE
  #define LANG_HOOKS_MAKE_TYPE cxx_make_type
  #undef LANG_HOOKS_TYPE_FOR_MODE
*** gcc.tmp/cp/Make-lang.in	Sun Jun 22 01:50:31 2003
--- gcc/cp/Make-lang.in	Sun Jun 22 02:32:16 2003
*************** cp/decl.o: cp/decl.c $(CXX_TREE_H) $(TM_
*** 242,248 ****
    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 \
--- 242,248 ----
    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 varpool.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_
*** 273,279 ****
    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
--- 273,279 ----
    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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]