c++: further optimize tsubst_template_decl
Checks
Commit Message
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk?
-- >8 --
This patch makes tsubst_template_decl use use_spec_table=false also in
the non-class non-function template case, to avoid computing 'argvec' and
doing a hash table lookup from tsubst_decl (when partially instantiating
a member variable or alias template).
This change reveals that for function templates, tsubst_template_decl
registers the partially instantiated TEMPLATE_DECL, whereas for other
non-class templates it registers the corresponding DECL_TEMPLATE_RESULT
which is an interesting inconsistency that I decided to preserve for now.
Trying to consistently register the TEMPLATE_DECL (or FUNCTION_DECL)
causes modules crashes, but I haven't looked into why.
In passing, I noticed in tsubst_function_decl that its 'argvec' goes
unused when 'lambda_fntype' is set (since lambdas aren't recorded in the
specializations table), so we can avoid computing it in that case.
gcc/cp/ChangeLog:
* pt.cc (tsubst_function_decl): Don't bother computing 'argvec'
when 'lambda_fntype' is set.
(tsubst_template_decl): Make sure we return a TEMPLATE_DECL
after specialization lookup. In the non-class non-function
template case, use tsubst_decl directly with use_spec_table=false,
update DECL_TI_ARGS and call register_specialization like
tsubst_decl would have done if use_spec_table=true.
---
gcc/cp/pt.cc | 39 +++++++++++++++++++++------------------
1 file changed, 21 insertions(+), 18 deletions(-)
Comments
On 9/19/23 11:04, Patrick Palka wrote:
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> for trunk?
>
> -- >8 --
>
> This patch makes tsubst_template_decl use use_spec_table=false also in
> the non-class non-function template case, to avoid computing 'argvec' and
> doing a hash table lookup from tsubst_decl (when partially instantiating
> a member variable or alias template).
>
> This change reveals that for function templates, tsubst_template_decl
> registers the partially instantiated TEMPLATE_DECL, whereas for other
> non-class templates it registers the corresponding DECL_TEMPLATE_RESULT
> which is an interesting inconsistency that I decided to preserve for now.
Can you document that in a comment somewhere, maybe at the bottom of
tsubst_template_decl where you're handling them differently? OK with
that change.
> Trying to consistently register the TEMPLATE_DECL (or FUNCTION_DECL)
> causes modules crashes, but I haven't looked into why.
>
> In passing, I noticed in tsubst_function_decl that its 'argvec' goes
> unused when 'lambda_fntype' is set (since lambdas aren't recorded in the
> specializations table), so we can avoid computing it in that case.
>
> gcc/cp/ChangeLog:
>
> * pt.cc (tsubst_function_decl): Don't bother computing 'argvec'
> when 'lambda_fntype' is set.
> (tsubst_template_decl): Make sure we return a TEMPLATE_DECL
> after specialization lookup. In the non-class non-function
> template case, use tsubst_decl directly with use_spec_table=false,
> update DECL_TI_ARGS and call register_specialization like
> tsubst_decl would have done if use_spec_table=true.
> ---
> gcc/cp/pt.cc | 39 +++++++++++++++++++++------------------
> 1 file changed, 21 insertions(+), 18 deletions(-)
>
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 777ff592789..cc8ba21d6fd 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -14370,7 +14370,7 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
>
> /* Calculate the complete set of arguments used to
> specialize R. */
> - if (use_spec_table)
> + if (use_spec_table && !lambda_fntype)
> {
> argvec = tsubst_template_args (DECL_TI_ARGS
> (DECL_TEMPLATE_RESULT
> @@ -14380,14 +14380,11 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
> return error_mark_node;
>
> /* Check to see if we already have this specialization. */
> - if (!lambda_fntype)
> - {
> - hash = spec_hasher::hash (gen_tmpl, argvec);
> - if (tree spec = retrieve_specialization (gen_tmpl, argvec, hash))
> - /* The spec for these args might be a partial instantiation of the
> - template, but here what we want is the FUNCTION_DECL. */
> - return STRIP_TEMPLATE (spec);
> - }
> + hash = spec_hasher::hash (gen_tmpl, argvec);
> + if (tree spec = retrieve_specialization (gen_tmpl, argvec, hash))
> + /* The spec for these args might be a partial instantiation of the
> + template, but here what we want is the FUNCTION_DECL. */
> + return STRIP_TEMPLATE (spec);
> }
> else
> argvec = args;
> @@ -14704,6 +14701,8 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,
> /* Type partial instantiations are stored as the type by
> lookup_template_class_1, not here as the template. */
> spec = CLASSTYPE_TI_TEMPLATE (spec);
> + else if (TREE_CODE (spec) != TEMPLATE_DECL)
> + spec = DECL_TI_TEMPLATE (spec);
> return spec;
> }
> }
> @@ -14754,7 +14753,7 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,
> inner = tsubst_aggr_type (inner, args, complain,
> in_decl, /*entering*/1);
> else
> - inner = tsubst (inner, args, complain, in_decl);
> + inner = tsubst_decl (inner, args, complain, /*use_spec_table=*/false);
> }
> --processing_template_decl;
> if (inner == error_mark_node)
> @@ -14780,12 +14779,11 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,
> }
> else
> {
> - if (TREE_CODE (inner) == FUNCTION_DECL)
> - /* Set DECL_TI_ARGS to the full set of template arguments, which
> - tsubst_function_decl didn't do due to use_spec_table=false. */
> - DECL_TI_ARGS (inner) = full_args;
> -
> DECL_TI_TEMPLATE (inner) = r;
> + /* Set DECL_TI_ARGS to the full set of template arguments,
> + which tsubst_function_decl / tsubst_decl didn't do due to
> + use_spec_table=false. */
> + DECL_TI_ARGS (inner) = full_args;
> DECL_TI_ARGS (r) = DECL_TI_ARGS (inner);
> }
>
> @@ -14813,9 +14811,14 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,
> if (PRIMARY_TEMPLATE_P (t))
> DECL_PRIMARY_TEMPLATE (r) = r;
>
> - if (TREE_CODE (decl) == FUNCTION_DECL && !lambda_fntype)
> - /* Record this non-type partial instantiation. */
> - register_specialization (r, t, full_args, false, hash);
> + if (!lambda_fntype && !class_p)
> + {
> + /* Record this non-type partial instantiation. */
> + if (TREE_CODE (inner) == FUNCTION_DECL)
> + register_specialization (r, t, full_args, false, hash);
> + else
> + register_specialization (inner, t, full_args, false, hash);
> + }
>
> return r;
> }
@@ -14370,7 +14370,7 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
/* Calculate the complete set of arguments used to
specialize R. */
- if (use_spec_table)
+ if (use_spec_table && !lambda_fntype)
{
argvec = tsubst_template_args (DECL_TI_ARGS
(DECL_TEMPLATE_RESULT
@@ -14380,14 +14380,11 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
return error_mark_node;
/* Check to see if we already have this specialization. */
- if (!lambda_fntype)
- {
- hash = spec_hasher::hash (gen_tmpl, argvec);
- if (tree spec = retrieve_specialization (gen_tmpl, argvec, hash))
- /* The spec for these args might be a partial instantiation of the
- template, but here what we want is the FUNCTION_DECL. */
- return STRIP_TEMPLATE (spec);
- }
+ hash = spec_hasher::hash (gen_tmpl, argvec);
+ if (tree spec = retrieve_specialization (gen_tmpl, argvec, hash))
+ /* The spec for these args might be a partial instantiation of the
+ template, but here what we want is the FUNCTION_DECL. */
+ return STRIP_TEMPLATE (spec);
}
else
argvec = args;
@@ -14704,6 +14701,8 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,
/* Type partial instantiations are stored as the type by
lookup_template_class_1, not here as the template. */
spec = CLASSTYPE_TI_TEMPLATE (spec);
+ else if (TREE_CODE (spec) != TEMPLATE_DECL)
+ spec = DECL_TI_TEMPLATE (spec);
return spec;
}
}
@@ -14754,7 +14753,7 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,
inner = tsubst_aggr_type (inner, args, complain,
in_decl, /*entering*/1);
else
- inner = tsubst (inner, args, complain, in_decl);
+ inner = tsubst_decl (inner, args, complain, /*use_spec_table=*/false);
}
--processing_template_decl;
if (inner == error_mark_node)
@@ -14780,12 +14779,11 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,
}
else
{
- if (TREE_CODE (inner) == FUNCTION_DECL)
- /* Set DECL_TI_ARGS to the full set of template arguments, which
- tsubst_function_decl didn't do due to use_spec_table=false. */
- DECL_TI_ARGS (inner) = full_args;
-
DECL_TI_TEMPLATE (inner) = r;
+ /* Set DECL_TI_ARGS to the full set of template arguments,
+ which tsubst_function_decl / tsubst_decl didn't do due to
+ use_spec_table=false. */
+ DECL_TI_ARGS (inner) = full_args;
DECL_TI_ARGS (r) = DECL_TI_ARGS (inner);
}
@@ -14813,9 +14811,14 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,
if (PRIMARY_TEMPLATE_P (t))
DECL_PRIMARY_TEMPLATE (r) = r;
- if (TREE_CODE (decl) == FUNCTION_DECL && !lambda_fntype)
- /* Record this non-type partial instantiation. */
- register_specialization (r, t, full_args, false, hash);
+ if (!lambda_fntype && !class_p)
+ {
+ /* Record this non-type partial instantiation. */
+ if (TREE_CODE (inner) == FUNCTION_DECL)
+ register_specialization (r, t, full_args, false, hash);
+ else
+ register_specialization (inner, t, full_args, false, hash);
+ }
return r;
}