[C++ PATCH] Reduce accumulated garbage in constexpr evaluation.

Jason Merrill jason@redhat.com
Tue Jun 4 14:46:00 GMT 2019


We want to evaluate the arguments to a call before looking into the cache so
that we have constant values, but if we then find the call in the cache we
end up with a TREE_LIST that we don't end up using; in highly recursive
constexpr evaluation this ends up being a large proportion of the garbage
generated.

The cxx_eval_increment_expression hunk is less important, but it's an easy
tweak; we only use the MODIFY_EXPR to evaluate it, so after that it's
garbage.

Tested x86_64-pc-linux-gnu, applying to trunk.

	* constexpr.c (cxx_eval_call_expression): ggc_free any bindings we
	don't save.
	(cxx_eval_increment_expression): ggc_free the MODIFY_EXPR after
	evaluating it.
---
 gcc/cp/constexpr.c | 25 +++++++++++++++++++++++++
 gcc/cp/ChangeLog   |  8 ++++++++
 2 files changed, 33 insertions(+)

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 67a8f04310c..84c98342835 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1733,6 +1733,29 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
   bool non_constant_args = false;
   cxx_bind_parameters_in_call (ctx, t, &new_call,
 			       non_constant_p, overflow_p, &non_constant_args);
+
+  /* We build up the bindings list before we know whether we already have this
+     call cached.  If we don't end up saving these bindings, ggc_free them when
+     this function exits.  */
+  struct free_bindings
+  {
+    tree &bindings;
+    bool do_free;
+    free_bindings (tree &b): bindings (b), do_free(true) { }
+    void preserve () { do_free = false; }
+    ~free_bindings () {
+      if (do_free)
+	{
+	  while (bindings)
+	    {
+	      tree b = bindings;
+	      bindings = TREE_CHAIN (bindings);
+	      ggc_free (b);
+	    }
+	}
+    }
+  } fb (new_call.bindings);
+
   if (*non_constant_p)
     return t;
 
@@ -1760,6 +1783,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 	     slot can move in the call to cxx_eval_builtin_function_call.  */
 	  *slot = entry = ggc_alloc<constexpr_call> ();
 	  *entry = new_call;
+	  fb.preserve ();
 	}
       /* Calls that are in progress have their result set to NULL,
 	 so that we can detect circular dependencies.  */
@@ -4002,6 +4026,7 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
   tree store = build2 (MODIFY_EXPR, type, op, mod);
   cxx_eval_constant_expression (ctx, store,
 				true, non_constant_p, overflow_p);
+  ggc_free (store);
 
   /* And the value of the expression.  */
   if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index a3b18c76f5e..efa79f3ad35 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,11 @@
+2019-06-04  Jason Merrill  <jason@redhat.com>
+
+	Reduce accumulated garbage in constexpr evaluation.
+	* constexpr.c (cxx_eval_call_expression): ggc_free any bindings we
+	don't save.
+	(cxx_eval_increment_expression): ggc_free the MODIFY_EXPR after
+	evaluating it.
+
 2019-06-04  Jakub Jelinek  <jakub@redhat.com>
 
 	* cp-tree.h (CP_OMP_CLAUSE_INFO): Allow for any clauses up to _condvar_

base-commit: 384aea128aac71e96ac413298adb49d7bae71c7d
-- 
2.20.1



More information about the Gcc-patches mailing list