Markus pointed out that my patch for DR 1558 slowed down the compiler
significantly for building Chrome: comparing entries in the template
specialization hash table had to spend a lot of time figuring out if
types were specializations of alias templates with dependent template
arguments in order to avoid comparing them by TYPE_CANONICAL.
This patch addresses this in multiple ways:
1) Instead of looking deep into the type to see if it's a dependent
alias, we just check for it being any kind of alias; strip_typedefs
strips any aliases in non-dependent template argument lists, so we're
safe just treating any aliases that make it to template_args_equal as
different.
2) I optimized alias_template_specialization_p a bit to check for the
alias bit before looking up the template info. This is less interesting
given #1, but I did it first and figured we might as well keep it.
3) I adjusted iterative_hash_template_arg to hash aliases differently to
reduce the number of collisions that result in calls to template_args_equal.
And while I was in the area, I also fixed dependent_alias_spec_p to only
look at the innermost template arguments.
alias_template_specialization_p is now down to 0.34% of perf time on the
testcase. template_args_equal is still at the top, but with a much
smaller lead than before.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 99d81c4c903fb91fd017edbedfc4b4998934fc54
Author: Jason Merrill <ja...@redhat.com>
Date: Fri Dec 19 12:11:01 2014 -0500
PR c++/64359
* pt.c (iterative_hash_template_arg): Hash alias specializations
differently from their TYPE_CANONICAL.
(alias_template_specialization_p): Optimize.
(template_args_equal): Optimize alias handling.
(dependent_alias_template_spec_p): Only check innermost args.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 15d304a..f5bd842 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -1674,6 +1674,18 @@ iterative_hash_template_arg (tree arg, hashval_t val)
switch (tclass)
{
case tcc_type:
+ if (alias_template_specialization_p (arg))
+ {
+ // We want an alias specialization that survived strip_typedefs
+ // to hash differently from its TYPE_CANONICAL, to avoid hash
+ // collisions that compare as different in template_args_equal.
+ // These could be dependent specializations that strip_typedefs
+ // left alone, or untouched specializations because
+ // coerce_template_parms returns the unconverted template
+ // arguments if it sees incomplete argument packs.
+ tree ti = TYPE_TEMPLATE_INFO (arg);
+ return hash_tmpl_and_args (TI_TEMPLATE (ti), TI_ARGS (ti));
+ }
if (TYPE_CANONICAL (arg))
return iterative_hash_object (TYPE_HASH (TYPE_CANONICAL (arg)),
val);
@@ -5314,13 +5326,19 @@ alias_type_or_template_p (tree t)
bool
alias_template_specialization_p (const_tree t)
{
- if (t == NULL_TREE)
- return false;
-
- return (TYPE_P (t)
- && TYPE_TEMPLATE_INFO (t)
- && PRIMARY_TEMPLATE_P (TYPE_TI_TEMPLATE (t))
- && DECL_ALIAS_TEMPLATE_P (TYPE_TI_TEMPLATE (t)));
+ /* It's an alias template specialization if it's an alias and its
+ TYPE_NAME is a specialization of a primary template. */
+ if (TYPE_ALIAS_P (t))
+ {
+ tree name = TYPE_NAME (t);
+ if (DECL_LANG_SPECIFIC (name))
+ if (tree ti = DECL_TEMPLATE_INFO (name))
+ {
+ tree tmpl = TI_TEMPLATE (ti);
+ return PRIMARY_TEMPLATE_P (tmpl);
+ }
+ }
+ return false;
}
/* Return TRUE iff T is a specialization of an alias template with
@@ -5330,7 +5348,8 @@ bool
dependent_alias_template_spec_p (const_tree t)
{
return (alias_template_specialization_p (t)
- && any_dependent_template_arguments_p (TYPE_TI_ARGS (t)));
+ && (any_dependent_template_arguments_p
+ (INNERMOST_TEMPLATE_ARGS (TYPE_TI_ARGS (t)))));
}
/* Return the number of innermost template parameters in TMPL. */
@@ -7283,16 +7302,12 @@ template_args_equal (tree ot, tree nt)
return false;
/* Don't treat an alias template specialization with dependent
arguments as equivalent to its underlying type when used as a
- template argument; we need them to hash differently. */
- bool ndep = dependent_alias_template_spec_p (nt);
- ++processing_template_decl;
- bool odep = dependent_alias_template_spec_p (ot);
- --processing_template_decl;
- if (ndep != odep)
+ template argument; we need them to be distinct so that we
+ substitute into the specialization arguments at instantiation
+ time. And aliases can't be equivalent without being ==, so
+ we don't need to look any deeper. */
+ if (TYPE_ALIAS_P (nt) || TYPE_ALIAS_P (ot))
return false;
- else if (ndep)
- return (TYPE_TI_TEMPLATE (nt) == TYPE_TI_TEMPLATE (ot)
- && template_args_equal (TYPE_TI_ARGS (nt), TYPE_TI_ARGS (ot)));
else
return same_type_p (ot, nt);
}