[PATCH][C++][RFH] Improve PR29433, cut down memory usage and compile-time

Richard Guenther rguenther@suse.de
Wed Nov 22 16:56:00 GMT 2006


For DECL_NAME of template types we use the diagnostic machinery to
create a (so-called) "mangled" name in pt.c:classtype_mangled_name which
obviously is slow (the diagnostic machiner is not optimized for this
use) and uses lots of memory in this testcase due to the size of
the (not mangled!) strings.  Using a truly mangled DECL_NAME allows
us to use a routine designed for this task (mangle_decl_string) and
exploit the compression features of the mangling scheme to save
(a lot of!) memory.  At least in theory...

Timings and memory usage on main.ii from PR29433 (-S -O0 -o /dev/null):

                            unpatched      patched
max virtual memory used       1.4GB         380MB
compile time                   87s           41s

(the unpatched compiler goes into swap as it reaches top memory usage
as the machine only has 1.5GB ram)

Instead of

  %   cumulative   self              self     total           
 time   seconds   seconds    calls  Ks/call  Ks/call  name    
 11.26    131.84   131.84 77379135     0.00     0.00  comptypes
 11.05    261.22   129.38 153228836     0.00     0.00  dump_aggr_type
  7.47    348.70    87.48 441675354     0.00     0.00  pp_base_append_text
  7.06    431.38    82.68 101695144     0.00     0.00  comp_template_args
  6.90    512.09    80.71   870176     0.00     0.00  retrieve_specialization
  6.09    583.32    71.24 116984878     0.00     0.00  template_args_equal
  4.82    639.78    56.46 325283356     0.00     0.00  pp_base_character

we now get (sorry, oprofile only)

samples  %        symbol name
452969   56.7361  comptypes
114270   14.3128  template_args_equal
85236    10.6761  comp_template_args
9900      1.2400  purpose_member
9816      1.2295  retrieve_specialization

which Doughs patch probably will improve further.

Unfortunately with this patch we mangle foo() differently for

template<typename _CharT>
class basic_istream;
template<typename _CharT>     
class basic_streambuf 
{
    template<typename _CharT2>
    friend basic_istream<_CharT2>& foo(basic_istream<_CharT2>&);
};
template class basic_streambuf<char>;
template<> basic_istream<char>& foo(basic_istream<char>&) { }

before and after the patch (and so libstdc++ breaks).  Before (and correct)
we get
_Z3fooIcER13basic_istreamIT_ES3_
but afterwards we have
_Z3fooIcER13basic_istreamIT_ES2_

any idea why this goes wrong?  One thing is that we don't seem to get
complete types at the point of calling classtype_mangled_name, which
is why even returning a string from TYPE_UID works for the c++ testsuite.
Still there seem to be some invariants classtype_mangled_name needs to
guarantee - which are unfortunately not documented and somewhat hard to
dig out.

Any hints appreciated!  (At least mangle_class_name_for_template in its
current form has to go)

Thanks,
Richard.


2006-11-22  Richard Guenther  <rguenther@suse.de>

	PR c++/29433
	* cp-tree.h (mangle_decl_string): Export.
	* mangle.c (mangle_decl_string): Likewise.
	* pt.c (mangle_class_name_for_template): Remove.
	(classtype_mangled_name): Use mangle_decl_string to get
	an identifier.

Index: cp/cp-tree.h
===================================================================
*** cp/cp-tree.h	(revision 119088)
--- cp/cp-tree.h	(working copy)
*************** extern tree merge_exception_specifiers		
*** 4521,4526 ****
--- 4521,4527 ----
  /* in mangle.c */
  extern void init_mangle				(void);
  extern void mangle_decl				(tree);
+ extern const char *mangle_decl_string		(tree);
  extern const char *mangle_type_string		(tree);
  extern tree mangle_typeinfo_for_type		(tree);
  extern tree mangle_typeinfo_string_for_type	(tree);
Index: cp/mangle.c
===================================================================
*** cp/mangle.c	(revision 119088)
--- cp/mangle.c	(working copy)
*************** static int discriminator_for_string_lite
*** 218,224 ****
  static void write_discriminator (const int);
  static void write_local_name (const tree, const tree, const tree);
  static void dump_substitution_candidates (void);
- static const char *mangle_decl_string (const tree);
  
  /* Control functions.  */
  
--- 218,223 ----
*************** init_mangle (void)
*** 2560,2566 ****
  
  /* Generate the mangled name of DECL.  */
  
! static const char *
  mangle_decl_string (const tree decl)
  {
    const char *result;
--- 2559,2565 ----
  
  /* Generate the mangled name of DECL.  */
  
! const char *
  mangle_decl_string (const tree decl)
  {
    const char *result;
Index: cp/pt.c
===================================================================
*** cp/pt.c	(revision 119088)
--- cp/pt.c	(working copy)
*************** static int push_tinst_level (tree);
*** 101,107 ****
  static void pop_tinst_level (void);
  static void reopen_tinst_level (tree);
  static tree classtype_mangled_name (tree);
- static char* mangle_class_name_for_template (const char *, tree, tree);
  static tree tsubst_initializer_list (tree, tree);
  static tree get_class_bindings (tree, tree, tree);
  static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t,
--- 101,106 ----
*************** comp_template_args (tree oldargs, tree n
*** 4250,4345 ****
    return 1;
  }
  
- /* Given class template name and parameter list, produce a user-friendly name
-    for the instantiation.  */
- 
- static char *
- mangle_class_name_for_template (const char* name, tree parms, tree arglist)
- {
-   static struct obstack scratch_obstack;
-   static char *scratch_firstobj;
-   int i, nparms;
- 
-   if (!scratch_firstobj)
-     gcc_obstack_init (&scratch_obstack);
-   else
-     obstack_free (&scratch_obstack, scratch_firstobj);
-   scratch_firstobj = (char *) obstack_alloc (&scratch_obstack, 1);
- 
- #define ccat(C)	obstack_1grow (&scratch_obstack, (C));
- #define cat(S)	obstack_grow (&scratch_obstack, (S), strlen (S))
- 
-   cat (name);
-   ccat ('<');
-   nparms = TREE_VEC_LENGTH (parms);
-   arglist = INNERMOST_TEMPLATE_ARGS (arglist);
-   gcc_assert (nparms == TREE_VEC_LENGTH (arglist));
-   for (i = 0; i < nparms; i++)
-     {
-       tree parm;
-       tree arg;
- 
-       parm = TREE_VALUE (TREE_VEC_ELT (parms, i));
-       arg = TREE_VEC_ELT (arglist, i);
- 
-       if (parm == error_mark_node)
- 	continue;
- 
-       if (i)
- 	ccat (',');
- 
-       if (TREE_CODE (parm) == TYPE_DECL)
- 	{
- 	  cat (type_as_string (arg, TFF_CHASE_TYPEDEF));
- 	  continue;
- 	}
-       else if (TREE_CODE (parm) == TEMPLATE_DECL)
- 	{
- 	  if (TREE_CODE (arg) == TEMPLATE_DECL)
- 	    {
- 	      /* Already substituted with real template.  Just output
- 		 the template name here */
- 	      tree context = DECL_CONTEXT (arg);
- 	      if (context)
- 		{
- 		  /* The template may be defined in a namespace, or
- 		     may be a member template.  */
- 		  gcc_assert (TREE_CODE (context) == NAMESPACE_DECL
- 			      || CLASS_TYPE_P (context));
- 		  cat (decl_as_string (DECL_CONTEXT (arg),
- 				      TFF_PLAIN_IDENTIFIER));
- 		  cat ("::");
- 		}
- 	      cat (IDENTIFIER_POINTER (DECL_NAME (arg)));
- 	    }
- 	  else
- 	    /* Output the parameter declaration.  */
- 	    cat (type_as_string (arg, TFF_CHASE_TYPEDEF));
- 	  continue;
- 	}
-       else
- 	gcc_assert (TREE_CODE (parm) == PARM_DECL);
- 
-       /* No need to check arglist against parmlist here; we did that
- 	 in coerce_template_parms, called from lookup_template_class.  */
-       cat (expr_as_string (arg, TFF_PLAIN_IDENTIFIER));
-     }
-   {
-     char *bufp = obstack_next_free (&scratch_obstack);
-     int offset = 0;
-     while (bufp[offset - 1] == ' ')
-       offset--;
-     obstack_blank_fast (&scratch_obstack, offset);
- 
-     /* B<C<char> >, not B<C<char>> */
-     if (bufp[offset - 1] == '>')
-       ccat (' ');
-   }
-   ccat ('>');
-   ccat ('\0');
-   return (char *) obstack_base (&scratch_obstack);
- }
- 
  static tree
  classtype_mangled_name (tree t)
  {
--- 4249,4254 ----
*************** classtype_mangled_name (tree t)
*** 4355,4364 ****
        if (PRIMARY_TEMPLATE_P (tmpl))
  	{
  	  tree name = DECL_NAME (tmpl);
! 	  char *mangled_name = mangle_class_name_for_template
! 	    (IDENTIFIER_POINTER (name),
! 	     DECL_INNERMOST_TEMPLATE_PARMS (tmpl),
! 	     CLASSTYPE_TI_ARGS (t));
  	  tree id = get_identifier (mangled_name);
  	  IDENTIFIER_TEMPLATE (id) = name;
  	  return id;
--- 4264,4270 ----
        if (PRIMARY_TEMPLATE_P (tmpl))
  	{
  	  tree name = DECL_NAME (tmpl);
! 	  const char *mangled_name = mangle_decl_string (tmpl);
  	  tree id = get_identifier (mangled_name);
  	  IDENTIFIER_TEMPLATE (id) = name;
  	  return id;



More information about the Gcc-patches mailing list