[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