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]

C++ PATCH: reduce memory usage



This patch reduces memory usage substantially in the presence of
templates.  In particular, on the test-case I've been looking at
today, we started out using 289 MB.  The leaks plugged in earlier
patches reduced that to 254 MB, with 1:30 compile-time.  This patch
takes it down to 148 MB, and 1:00 compile-time, for a total savings of
49% memory, and 33% time.  A little profiling goes a long way.

Until now, a call to an inline template function would trigger an
immediate instantiation, even when not optimizing.  That meant that
for complex programs we'd often have a chain of ten or twenty template
instantiations active, Because of how our GC works, we couldn't
collect memory until we were all done with all of them, meaning that
we ended up with lots of memory usage.

There's no point in doing this when not optimizing since we're not
going to inline the functions anyhow.  And, with the tree-based
inliner, we don't need to this until we actually put out the
containing function -- which may never happen.

At this point, the patch doesn't help as much when optimizing; we
still instantiate all the called functions from within the caller.
But, one thing at a time.

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

2000-04-05  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.h (instantiate_decl): Change prototype.
	* decl2.c (mark_used): Adjust call.
	* optimize.c (inlinable_function_p): Adjust handling of templates.
	* pt.c (do_decl_instantiation): Adjust call to instantiate_decl.
	(do_type_instantiation): Likewise.
	(instantiate_decl): Defer more templates.
	(instantiate_pending_templates): Adjust logic to handle inline
	friend functions.

Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.430
diff -c -p -r1.430 cp-tree.h
*** cp-tree.h	2000/04/04 18:13:19	1.430
--- cp-tree.h	2000/04/06 03:07:57
*************** extern int more_specialized			PARAMS ((t
*** 4123,4129 ****
  extern void mark_class_instantiated		PARAMS ((tree, int));
  extern void do_decl_instantiation		PARAMS ((tree, tree, tree));
  extern void do_type_instantiation		PARAMS ((tree, tree));
! extern tree instantiate_decl			PARAMS ((tree));
  extern tree get_bindings			PARAMS ((tree, tree, tree));
  extern void add_tree				PARAMS ((tree));
  extern void add_maybe_template			PARAMS ((tree, tree));
--- 4123,4129 ----
  extern void mark_class_instantiated		PARAMS ((tree, int));
  extern void do_decl_instantiation		PARAMS ((tree, tree, tree));
  extern void do_type_instantiation		PARAMS ((tree, tree));
! extern tree instantiate_decl			PARAMS ((tree, int));
  extern tree get_bindings			PARAMS ((tree, tree, tree));
  extern void add_tree				PARAMS ((tree));
  extern void add_maybe_template			PARAMS ((tree, tree));
Index: decl2.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl2.c,v
retrieving revision 1.324
diff -c -p -r1.324 decl2.c
*** decl2.c	2000/04/06 00:51:24	1.324
--- decl2.c	2000/04/06 03:08:01
*************** mark_used (decl)
*** 5237,5243 ****
        && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)
        && (!DECL_EXPLICIT_INSTANTIATION (decl)
  	  || (TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl))))
!     instantiate_decl (decl);
  }
  
  /* Helper function for named_class_head_sans_basetype nonterminal.  We
--- 5237,5243 ----
        && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)
        && (!DECL_EXPLICIT_INSTANTIATION (decl)
  	  || (TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl))))
!     instantiate_decl (decl, /*defer_ok=*/1);
  }
  
  /* Helper function for named_class_head_sans_basetype nonterminal.  We
Index: optimize.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/optimize.c,v
retrieving revision 1.20
diff -c -p -r1.20 optimize.c
*** optimize.c	2000/04/05 15:27:08	1.20
--- optimize.c	2000/04/06 03:08:01
*************** inlinable_function_p (fn, id)
*** 463,472 ****
       it.  */
    else if (!DECL_INLINE (fn))
      ;
-   /* If we don't have the function body available, we can't inline
-      it.  */
-   else if (!DECL_SAVED_TREE (fn))
-     ;
    /* We can't inline varargs functions.  */
    else if (varargs_function_p (fn))
      ;
--- 463,468 ----
*************** inlinable_function_p (fn, id)
*** 481,486 ****
--- 477,497 ----
    /* Squirrel away the result so that we don't have to check again.  */
    DECL_UNINLINABLE (fn) = !inlinable;
  
+   /* We can inline a template instantiation only if it's fully
+      instantiated.  */
+   if (inlinable 
+       && DECL_TEMPLATE_INFO (fn) 
+       && TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn)))
+     {
+       fn = instantiate_decl (fn, /*defer_ok=*/0);
+       inlinable = !TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn));
+     }
+ 
+   /* If we don't have the function body available, we can't inline
+      it.  */
+   if (!DECL_SAVED_TREE (fn))
+     inlinable = 0;
+ 
    /* Don't do recursive inlining, either.  We don't record this in
       DECL_UNLINABLE; we may be able to inline this function later.  */
    if (inlinable)
*************** inlinable_function_p (fn, id)
*** 490,505 ****
        for (i = 0; i < id->fns->elements_used; ++i)
  	if (VARRAY_TREE (id->fns, i) == fn)
  	  inlinable = 0;
-     }
- 
-   /* We can inline a template instantiation only if it's fully
-      instantiated.  */
-   if (inlinable
-       && DECL_TEMPLATE_INFO (fn) 
-       && TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn)))
-     {
-       fn = instantiate_decl (fn);
-       inlinable = !TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn));
      }
  
    /* Return the result.  */
--- 501,506 ----
Index: pt.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/pt.c,v
retrieving revision 1.414
diff -c -p -r1.414 pt.c
*** pt.c	2000/03/29 00:58:46	1.414
--- pt.c	2000/04/06 03:08:07
*************** do_decl_instantiation (declspecs, declar
*** 9129,9135 ****
    mark_decl_instantiated (result, extern_p);
    repo_template_instantiated (result, extern_p);
    if (! extern_p)
!     instantiate_decl (result);
  }
  
  void
--- 9129,9135 ----
    mark_decl_instantiated (result, extern_p);
    repo_template_instantiated (result, extern_p);
    if (! extern_p)
!     instantiate_decl (result, /*defer_ok=*/1);
  }
  
  void
*************** do_type_instantiation (t, storage)
*** 9265,9271 ****
  	    mark_decl_instantiated (tmp, extern_p);
  	    repo_template_instantiated (tmp, extern_p);
  	    if (! extern_p)
! 	      instantiate_decl (tmp);
  	  }
  
      for (tmp = TYPE_FIELDS (t); tmp; tmp = TREE_CHAIN (tmp))
--- 9265,9271 ----
  	    mark_decl_instantiated (tmp, extern_p);
  	    repo_template_instantiated (tmp, extern_p);
  	    if (! extern_p)
! 	      instantiate_decl (tmp, /*defer_ok=*/1);
  	  }
  
      for (tmp = TYPE_FIELDS (t); tmp; tmp = TREE_CHAIN (tmp))
*************** do_type_instantiation (t, storage)
*** 9274,9280 ****
  	  mark_decl_instantiated (tmp, extern_p);
  	  repo_template_instantiated (tmp, extern_p);
  	  if (! extern_p)
! 	    instantiate_decl (tmp);
  	}
  
      for (tmp = CLASSTYPE_TAGS (t); tmp; tmp = TREE_CHAIN (tmp))
--- 9274,9280 ----
  	  mark_decl_instantiated (tmp, extern_p);
  	  repo_template_instantiated (tmp, extern_p);
  	  if (! extern_p)
! 	    instantiate_decl (tmp, /*defer_ok=*/1);
  	}
  
      for (tmp = CLASSTYPE_TAGS (t); tmp; tmp = TREE_CHAIN (tmp))
*************** regenerate_decl_from_template (decl, tmp
*** 9376,9386 ****
    register_specialization (decl, gen_tmpl, args);
  }
  
! /* Produce the definition of D, a _DECL generated from a template.  */
  
  tree
! instantiate_decl (d)
       tree d;
  {
    tree tmpl = DECL_TI_TEMPLATE (d);
    tree args = DECL_TI_ARGS (d);
--- 9376,9389 ----
    register_specialization (decl, gen_tmpl, args);
  }
  
! /* Produce the definition of D, a _DECL generated from a template.  If
!    DEFER_OK is non-zero, then we don't have to actually do the
!    instantiation now; we just have to do it sometime.  */
  
  tree
! instantiate_decl (d, defer_ok)
       tree d;
+      int defer_ok;
  {
    tree tmpl = DECL_TI_TEMPLATE (d);
    tree args = DECL_TI_ARGS (d);
*************** instantiate_decl (d)
*** 9513,9532 ****
        && ! (TREE_CODE (d) == FUNCTION_DECL && DECL_INLINE (d)))
      goto out;
  
    if (TREE_CODE (d) == VAR_DECL 
        && TREE_READONLY (d)
        && DECL_INITIAL (d) == NULL_TREE
        && DECL_INITIAL (code_pattern) != NULL_TREE)
!     /* We need to set up DECL_INITIAL regardless of pattern_defined if
!        the variable is a static const initialized in the class body.  */;
!   else if (pattern_defined && nested
! 	   && TREE_CODE (d) == FUNCTION_DECL && DECL_INLINE (d))
!     /* An inline function used in another function; instantiate it now so
!        we can inline it.  */;
!   else if (! pattern_defined || ! at_eof)
      {
-       /* Defer all other templates.  We restore the source position
-          here because it's used by add_pending_template.  */
        lineno = line;
        input_filename = file;
  
--- 9516,9533 ----
        && ! (TREE_CODE (d) == FUNCTION_DECL && DECL_INLINE (d)))
      goto out;
  
+   /* We need to set up DECL_INITIAL regardless of pattern_defined if
+      the variable is a static const initialized in the class body.  */
    if (TREE_CODE (d) == VAR_DECL 
        && TREE_READONLY (d)
        && DECL_INITIAL (d) == NULL_TREE
        && DECL_INITIAL (code_pattern) != NULL_TREE)
!     ;
!   /* Defer all other templates, unless we have been explicitly
!      forbidden from doing so.  We restore the source position here
!      because it's used by add_pending_template.  */
!   else if (! pattern_defined || defer_ok)
      {
        lineno = line;
        input_filename = file;
  
*************** instantiate_pending_templates ()
*** 9657,9663 ****
  			 fn;
  			 fn = TREE_CHAIN (fn))
  		      if (! DECL_ARTIFICIAL (fn))
! 			instantiate_decl (fn);
  		  if (COMPLETE_TYPE_P (instantiation))
  		    {
  		      instantiated_something = 1;
--- 9658,9664 ----
  			 fn;
  			 fn = TREE_CHAIN (fn))
  		      if (! DECL_ARTIFICIAL (fn))
! 			instantiate_decl (fn, /*defer_ok=*/0);
  		  if (COMPLETE_TYPE_P (instantiation))
  		    {
  		      instantiated_something = 1;
*************** instantiate_pending_templates ()
*** 9674,9683 ****
  	    }
  	  else
  	    {
! 	      if (DECL_TEMPLATE_INSTANTIATION (instantiation)
  		  && !DECL_TEMPLATE_INSTANTIATED (instantiation))
  		{
! 		  instantiation = instantiate_decl (instantiation);
  		  if (DECL_TEMPLATE_INSTANTIATED (instantiation))
  		    {
  		      instantiated_something = 1;
--- 9675,9685 ----
  	    }
  	  else
  	    {
! 	      if (!DECL_TEMPLATE_SPECIALIZATION (instantiation)
  		  && !DECL_TEMPLATE_INSTANTIATED (instantiation))
  		{
! 		  instantiation = instantiate_decl (instantiation,
! 						    /*defer_ok=*/0);
  		  if (DECL_TEMPLATE_INSTANTIATED (instantiation))
  		    {
  		      instantiated_something = 1;
*************** instantiate_pending_templates ()
*** 9685,9691 ****
  		    }
  		}
  
! 	      if (!DECL_TEMPLATE_INSTANTIATION (instantiation)
  		  || DECL_TEMPLATE_INSTANTIATED (instantiation))
  		/* If INSTANTIATION has been instantiated, then we don't
  		   need to consider it again in the future.  */
--- 9687,9693 ----
  		    }
  		}
  
! 	      if (DECL_TEMPLATE_SPECIALIZATION (instantiation)
  		  || DECL_TEMPLATE_INSTANTIATED (instantiation))
  		/* If INSTANTIATION has been instantiated, then we don't
  		   need to consider it again in the future.  */
*************** instantiate_pending_templates ()
*** 9717,9723 ****
  	      template = TREE_PURPOSE (*t);
  	      args = get_bindings (template, fn, NULL_TREE);
  	      fn = instantiate_template (template, args);
! 	      instantiate_decl (fn);
  	      reconsider = 1;
  	    }
  	
--- 9719,9725 ----
  	      template = TREE_PURPOSE (*t);
  	      args = get_bindings (template, fn, NULL_TREE);
  	      fn = instantiate_template (template, args);
! 	      instantiate_decl (fn, /*defer_ok=*/0);
  	      reconsider = 1;
  	    }
  	

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