c++: further optimize tsubst_template_decl

Message ID 20230919150444.356437-1-ppalka@redhat.com
State Unresolved
Headers
Series c++: further optimize tsubst_template_decl |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Patrick Palka Sept. 19, 2023, 3:04 p.m. UTC
  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

Jason Merrill Sept. 19, 2023, 6:59 p.m. UTC | #1
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;
>   }
  

Patch

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;
 }