Reduce accumulated garbage in constexpr evaluation.
authorJason Merrill <jason@redhat.com>
Tue, 4 Jun 2019 14:47:40 +0000 (10:47 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 4 Jun 2019 14:47:40 +0000 (10:47 -0400)
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.

* 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.

From-SVN: r271909

gcc/cp/ChangeLog
gcc/cp/constexpr.c

index a3b18c76f5ea10946c6d4185e6d5529ddc287bbf..efa79f3ad35432047f6acf188b5534d7ec0e0f75 100644 (file)
@@ -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_
index 67a8f04310cbb381a1e6a62d4a9f6a09d00a590d..84c983428357b25d5043972726c034b4458ea012 100644 (file)
@@ -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)