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