On 10/2/24 7:50 AM, Richard Biener wrote:
This reduces peak memory usage by 20% for a specific testcase.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

It's very ugly so I'd appreciate suggestions on how to handle such
situations better?

I'm pushing this alternative patch, tested x86_64-pc-linux-gnu.
From 5b08ae503dd4aef2789a667daaf1984e7cc94aaa Mon Sep 17 00:00:00 2001
From: Jason Merrill <ja...@redhat.com>
Date: Wed, 2 Oct 2024 08:05:28 -0400
Subject: [PATCH] c++: free garbage vec in coerce_template_parms
To: gcc-patches@gcc.gnu.org

coerce_template_parms can create two different vecs for the inner template
arguments, new_inner_args and (potentially) the result of
expand_template_argument_pack.  One or the other, or possibly both, end up
being garbage: in the typical case, the expanded vec is garbage because it's
only used as the source for convert_template_argument.  In some dependent
cases, the new vec is garbage because we decide to return the original args
instead.  In these cases, ggc_free the garbage vec to reduce the memory
overhead of overload resolution.

gcc/cp/ChangeLog:

	* pt.cc (struct free_if_changed_proxy): New.
	(coerce_template_parms): Use it.

Co-authored-by: Richard Biener  <rguent...@suse.de>
---
 gcc/cp/pt.cc | 36 ++++++++++++++++++++++++++++++------
 1 file changed, 30 insertions(+), 6 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 20affcd65a2..6d488128d68 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -9079,6 +9079,30 @@ pack_expansion_args_count (tree args)
   return count;
 }
 
+/* Used for a variable of pointer type T (typically 'tree') that starts out
+   pointing to exposed data, but might get changed to point to internal data
+   that can be safely discarded at scope exit.  Use .release when exposing the
+   internal data to prevent ggc_free.  */
+
+template <class T>
+struct free_if_changed_proxy
+{
+  T val;
+  T orig;
+
+  free_if_changed_proxy (T t): val(t), orig(t) { }
+  ~free_if_changed_proxy ()
+  {
+    if (val != orig)
+      ggc_free (val);
+  }
+
+  T release () { return orig = val; }
+
+  operator T () { return val; }
+  free_if_changed_proxy& operator= (const T& t) { val = t; return *this; }
+};
+
 /* Convert all template arguments to their appropriate types, and
    return a vector containing the innermost resulting template
    arguments.  If any error occurs, return error_mark_node. Error and
@@ -9105,8 +9129,6 @@ coerce_template_parms (tree parms,
 		       bool require_all_args /* = true */)
 {
   int nparms, nargs, parm_idx, arg_idx, lost = 0;
-  tree orig_inner_args;
-  tree inner_args;
 
   /* When used as a boolean value, indicates whether this is a
      variadic template parameter list. Since it's an int, we can also
@@ -9152,7 +9174,6 @@ coerce_template_parms (tree parms,
 	++default_p;
     }
 
-  inner_args = orig_inner_args = INNERMOST_TEMPLATE_ARGS (args);
   /* If there are no parameters that follow a parameter pack, we need to
      expand any argument packs so that we can deduce a parameter pack from
      some non-packed args followed by an argument pack, as in variadic85.C.
@@ -9161,6 +9182,7 @@ coerce_template_parms (tree parms,
      with a nested class inside a partial specialization of a class
      template, as in variadic92.C, or when deducing a template parameter pack
      from a sub-declarator, as in variadic114.C.  */
+  free_if_changed_proxy<tree> inner_args = INNERMOST_TEMPLATE_ARGS (args);
   if (!post_variadic_parms)
     inner_args = expand_template_argument_pack (inner_args);
 
@@ -9275,7 +9297,8 @@ coerce_template_parms (tree parms,
 	    {
 	      /* We don't know how many args we have yet, just use the
 		 unconverted (and still packed) ones for now.  */
-	      new_inner_args = orig_inner_args;
+	      ggc_free (new_inner_args);
+	      new_inner_args = inner_args.orig;
 	      arg_idx = nargs;
 	      break;
 	    }
@@ -9329,8 +9352,9 @@ coerce_template_parms (tree parms,
 		  = make_pack_expansion (conv, complain);
 
               /* We don't know how many args we have yet, just
-                 use the unconverted ones for now.  */
-              new_inner_args = inner_args;
+		 use the unconverted (but unpacked) ones for now.  */
+	      ggc_free (new_inner_args);
+	      new_inner_args = inner_args.release ();
 	      arg_idx = nargs;
               break;
             }
-- 
2.46.2

Reply via email to