diff mbox series

c++: Avoid unnecessary copying in cp_fold [PR94038]

Message ID 20200504194411.3363531-1-ppalka@redhat.com
State New
Headers show
Series c++: Avoid unnecessary copying in cp_fold [PR94038] | expand

Commit Message

Patrick Palka May 4, 2020, 7:44 p.m. UTC
When folding a CALL_EXPR, we can avoid copying it until folding changes
one of its arguments.  And when folding a TREE_VEC, we can avoid using
an intermediate releasing_vec by working with a copy of the TREE_VEC as
soon as folding changes one of its arguments, like we do in the
CALL_EXPR case.

Incidentally, the CALL_EXPR change also fixes the testcase in PR94038.
The reason is that the call to maybe_constant_value from cp_fold on
bar<int>() now reuses the result of the earlier call to
maybe_constant_value from fold_for_warn, via the cv_cache.  This earlier
call passes uid_sensitive=true, whereas the call from cp_fold passes
uid_sensitive=false, and so by reusing the earlier call we now avoid
instantiating bar<int> at all.

Passes 'make check-c++', does this look OK to commit to master after a
full bootstrap and regtest?

gcc/cp/ChangeLog:

	PR c++/94038
	* cp-gimplify.c (cp_fold) <case CALL_EXPR>: Move some variable
	declarations closer to their uses.  Copy the CALL_EXPR only
	when one of its arguments has changed.
	(cp_fold) <case TREE_VEC>: Instead of first collecting the
	folded arguments into a releasing_vec, just make a copy of the
	TREE_VEC as soon as folding changes one of its arguments.

gcc/testsuite/ChangeLog:

	PR c++/94038
	* g++.dg/warn/pr94038.C: New test.
---
 gcc/cp/cp-gimplify.c                | 39 ++++++++++++-----------------
 gcc/testsuite/g++.dg/warn/pr94038.C | 26 +++++++++++++++++++
 2 files changed, 42 insertions(+), 23 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/warn/pr94038.C

Comments

Jason Merrill May 4, 2020, 9:33 p.m. UTC | #1
On 5/4/20 3:44 PM, Patrick Palka wrote:
> When folding a CALL_EXPR, we can avoid copying it until folding changes
> one of its arguments.  And when folding a TREE_VEC, we can avoid using
> an intermediate releasing_vec by working with a copy of the TREE_VEC as
> soon as folding changes one of its arguments, like we do in the
> CALL_EXPR case.
> 
> Incidentally, the CALL_EXPR change also fixes the testcase in PR94038.
> The reason is that the call to maybe_constant_value from cp_fold on
> bar<int>() now reuses the result of the earlier call to
> maybe_constant_value from fold_for_warn, via the cv_cache.  This earlier
> call passes uid_sensitive=true, whereas the call from cp_fold passes
> uid_sensitive=false, and so by reusing the earlier call we now avoid
> instantiating bar<int> at all.
> 
> Passes 'make check-c++', does this look OK to commit to master after a
> full bootstrap and regtest?

OK.

> gcc/cp/ChangeLog:
> 
> 	PR c++/94038
> 	* cp-gimplify.c (cp_fold) <case CALL_EXPR>: Move some variable
> 	declarations closer to their uses.  Copy the CALL_EXPR only
> 	when one of its arguments has changed.
> 	(cp_fold) <case TREE_VEC>: Instead of first collecting the
> 	folded arguments into a releasing_vec, just make a copy of the
> 	TREE_VEC as soon as folding changes one of its arguments.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/94038
> 	* g++.dg/warn/pr94038.C: New test.
> ---
>   gcc/cp/cp-gimplify.c                | 39 ++++++++++++-----------------
>   gcc/testsuite/g++.dg/warn/pr94038.C | 26 +++++++++++++++++++
>   2 files changed, 42 insertions(+), 23 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/warn/pr94038.C
> 
> diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
> index f326d71637b..fc26a85f43a 100644
> --- a/gcc/cp/cp-gimplify.c
> +++ b/gcc/cp/cp-gimplify.c
> @@ -2744,7 +2744,7 @@ cp_fold (tree x)
>   
>       case CALL_EXPR:
>         {
> -	int i, m, sv = optimize, nw = sv, changed = 0;
> +	int sv = optimize, nw = sv;
>   	tree callee = get_callee_fndecl (x);
>   
>   	/* Some built-in function calls will be evaluated at compile-time in
> @@ -2770,10 +2770,9 @@ cp_fold (tree x)
>   	    break;
>   	  }
>   
> -	x = copy_node (x);
> -
> -	m = call_expr_nargs (x);
> -	for (i = 0; i < m; i++)
> +	bool changed = false;
> +	int m = call_expr_nargs (x);
> +	for (int i = 0; i < m; i++)
>   	  {
>   	    r = cp_fold (CALL_EXPR_ARG (x, i));
>   	    if (r != CALL_EXPR_ARG (x, i))
> @@ -2783,9 +2782,11 @@ cp_fold (tree x)
>   		    x = error_mark_node;
>   		    break;
>   		  }
> -		changed = 1;
> +		if (!changed)
> +		  x = copy_node (x);
> +		CALL_EXPR_ARG (x, i) = r;
> +		changed = true;
>   	      }
> -	    CALL_EXPR_ARG (x, i) = r;
>   	  }
>   	if (x == error_mark_node)
>   	  break;
> @@ -2825,8 +2826,6 @@ cp_fold (tree x)
>   	    break;
>   	  }
>   
> -	if (!changed)
> -	  x = org_x;
>   	break;
>         }
>   
> @@ -2865,24 +2864,18 @@ cp_fold (tree x)
>       case TREE_VEC:
>         {
>   	bool changed = false;
> -	releasing_vec vec;
> -	int i, n = TREE_VEC_LENGTH (x);
> -	vec_safe_reserve (vec, n);
> +	int n = TREE_VEC_LENGTH (x);
>   
> -	for (i = 0; i < n; i++)
> +	for (int i = 0; i < n; i++)
>   	  {
>   	    tree op = cp_fold (TREE_VEC_ELT (x, i));
> -	    vec->quick_push (op);
>   	    if (op != TREE_VEC_ELT (x, i))
> -	      changed = true;
> -	  }
> -
> -	if (changed)
> -	  {
> -	    r = copy_node (x);
> -	    for (i = 0; i < n; i++)
> -	      TREE_VEC_ELT (r, i) = (*vec)[i];
> -	    x = r;
> +	      {
> +		if (!changed)
> +		  x = copy_node (x);
> +		TREE_VEC_ELT (x, i) = op;
> +		changed = true;
> +	      }
>   	  }
>         }
>   
> diff --git a/gcc/testsuite/g++.dg/warn/pr94038.C b/gcc/testsuite/g++.dg/warn/pr94038.C
> new file mode 100644
> index 00000000000..4edfae72d99
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/warn/pr94038.C
> @@ -0,0 +1,26 @@
> +// PR c++/94038
> +// { dg-do compile { target c++11 } }
> +// { dg-additional-options "-O -Wall" }
> +
> +template<typename T>
> +constexpr int
> +foo()
> +{
> +  static_assert(T(1) == 0, "");
> +  return 0;
> +}
> +
> +template<typename T>
> +constexpr int
> +bar()
> +{
> +  return foo<T>();
> +}
> +
> +constexpr int
> +baz(int a)
> +{
> +  return a;
> +}
> +
> +static_assert(decltype(baz(bar<int>())){} == 0, "");
>
diff mbox series

Patch

diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index f326d71637b..fc26a85f43a 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -2744,7 +2744,7 @@  cp_fold (tree x)
 
     case CALL_EXPR:
       {
-	int i, m, sv = optimize, nw = sv, changed = 0;
+	int sv = optimize, nw = sv;
 	tree callee = get_callee_fndecl (x);
 
 	/* Some built-in function calls will be evaluated at compile-time in
@@ -2770,10 +2770,9 @@  cp_fold (tree x)
 	    break;
 	  }
 
-	x = copy_node (x);
-
-	m = call_expr_nargs (x);
-	for (i = 0; i < m; i++)
+	bool changed = false;
+	int m = call_expr_nargs (x);
+	for (int i = 0; i < m; i++)
 	  {
 	    r = cp_fold (CALL_EXPR_ARG (x, i));
 	    if (r != CALL_EXPR_ARG (x, i))
@@ -2783,9 +2782,11 @@  cp_fold (tree x)
 		    x = error_mark_node;
 		    break;
 		  }
-		changed = 1;
+		if (!changed)
+		  x = copy_node (x);
+		CALL_EXPR_ARG (x, i) = r;
+		changed = true;
 	      }
-	    CALL_EXPR_ARG (x, i) = r;
 	  }
 	if (x == error_mark_node)
 	  break;
@@ -2825,8 +2826,6 @@  cp_fold (tree x)
 	    break;
 	  }
 
-	if (!changed)
-	  x = org_x;
 	break;
       }
 
@@ -2865,24 +2864,18 @@  cp_fold (tree x)
     case TREE_VEC:
       {
 	bool changed = false;
-	releasing_vec vec;
-	int i, n = TREE_VEC_LENGTH (x);
-	vec_safe_reserve (vec, n);
+	int n = TREE_VEC_LENGTH (x);
 
-	for (i = 0; i < n; i++)
+	for (int i = 0; i < n; i++)
 	  {
 	    tree op = cp_fold (TREE_VEC_ELT (x, i));
-	    vec->quick_push (op);
 	    if (op != TREE_VEC_ELT (x, i))
-	      changed = true;
-	  }
-
-	if (changed)
-	  {
-	    r = copy_node (x);
-	    for (i = 0; i < n; i++)
-	      TREE_VEC_ELT (r, i) = (*vec)[i];
-	    x = r;
+	      {
+		if (!changed)
+		  x = copy_node (x);
+		TREE_VEC_ELT (x, i) = op;
+		changed = true;
+	      }
 	  }
       }
 
diff --git a/gcc/testsuite/g++.dg/warn/pr94038.C b/gcc/testsuite/g++.dg/warn/pr94038.C
new file mode 100644
index 00000000000..4edfae72d99
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/pr94038.C
@@ -0,0 +1,26 @@ 
+// PR c++/94038
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-O -Wall" }
+
+template<typename T>
+constexpr int
+foo()
+{
+  static_assert(T(1) == 0, "");
+  return 0;
+}
+
+template<typename T>
+constexpr int
+bar()
+{
+  return foo<T>();
+}
+
+constexpr int
+baz(int a)
+{
+  return a;
+}
+
+static_assert(decltype(baz(bar<int>())){} == 0, "");