On April 6, 2016 6:51:40 PM GMT+02:00, Patrick Palka <patr...@parcs.ath.cx> 
wrote:
>During constexpr evaluation we unconditionally call unshare_expr in a
>bunch of places to ensure that CONSTRUCTORs (and their
>CONSTRUCTOR_ELTS)
>don't get shared.  But as far as I can tell, we don't have any reason
>to
>call unshare_expr on non-CONSTRUCTORs, and a CONSTRUCTOR will never be
>an operand of a non-CONSTRUCTOR tree.  Assuming these two things are
>true, then I think we can safely restrict the calls to unshare_expr to
>only CONSTRUCTOR trees. Doing so saves 50MB of peak memory usage in the
>test case in the PR (bringing memory usage down to 4.9 levels).
>
>This patch takes this idea a bit further and implements a custom
>unshare_constructor procedure that recursively unshares just
>CONSTRUCTORs and their CONSTRUCTOR elements.  This is in contrast to
>unshare_expr which unshares even non-CONSTRUCTOR elements of a
>CONSTRUCTOR.  unshare_constructor also has an assert which verifies
>that
>there really is no CONSTRUCTOR subexpression inside a non-CONSTRUCTOR
>tree.  So far I haven't been able to get this assert to trigger which
>makes me reasonably confident about this optimization.

At least the middle end uses CONSTRUCTOR to build vectors from components which 
can then of course be operands of expressions.

Richard.

>Does this look OK to commit after bootstrap + regtesting?
>
>gcc/cp/ChangeLog:
>
>       PR c++/70452
>       * constexpr.c (not_a_constructor): New function.
>       (unshare_constructor): New function.
>       (cxx_eval_call_expression): Use unshare_constructor instead of
>       unshare_expr.
>       (find_array_ctor_elt): Likewise.
>       (cxx_eval_vec_init_1): Likewise.
>       (cxx_eval_store_expression): Likewise.
>       (cxx_eval_constant_expression): Likewise.
>---
>gcc/cp/constexpr.c | 55
>++++++++++++++++++++++++++++++++++++++++++++++--------
> 1 file changed, 47 insertions(+), 8 deletions(-)
>
>diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
>index 1c2701b..5d33a11 100644
>--- a/gcc/cp/constexpr.c
>+++ b/gcc/cp/constexpr.c
>@@ -1151,6 +1151,45 @@ adjust_temp_type (tree type, tree temp)
>   return cp_fold_convert (type, temp);
> }
> 
>+/* Callback for walk_tree used by unshare_constructor.  */
>+
>+static tree
>+not_a_constructor (tree *tp, int *walk_subtrees, void *)
>+{
>+  if (TYPE_P (*tp))
>+    *walk_subtrees = 0;
>+  gcc_assert (TREE_CODE (*tp) != CONSTRUCTOR);
>+  return NULL_TREE;
>+}
>+
>+/* If T is a CONSTRUCTOR, return an unshared copy of T.  Otherwise
>+   return T.  */
>+
>+static tree
>+unshare_constructor (tree t)
>+{
>+  if (TREE_CODE (t) == CONSTRUCTOR)
>+    {
>+      tree r;
>+
>+      r = copy_node (t);
>+      CONSTRUCTOR_ELTS (r) = vec_safe_copy (CONSTRUCTOR_ELTS (t));
>+
>+      /* Unshare any of its elements that also happen to be
>CONSTRUCTORs.  */
>+      for (unsigned idx = 0;
>+         idx < vec_safe_length (CONSTRUCTOR_ELTS (r)); idx++)
>+      CONSTRUCTOR_ELT (r, idx)->value
>+        = unshare_constructor (CONSTRUCTOR_ELT (r, idx)->value);
>+
>+      return r;
>+    }
>+
>+  /* If T is not itself a CONSTRUCTOR then we don't expect it to
>contain
>+     any CONSTRUCTOR subexpressions.  */
>+  walk_tree_without_duplicates (&t, not_a_constructor, NULL);
>+  return t;
>+}
>+
> /* Subroutine of cxx_eval_call_expression.
>    We are processing a call expression (either CALL_EXPR or
>    AGGR_INIT_EXPR) in the context of CTX.  Evaluate
>@@ -1454,7 +1493,7 @@ cxx_eval_call_expression (const constexpr_ctx
>*ctx, tree t,
>             tree arg = TREE_VALUE (bound);
>             gcc_assert (DECL_NAME (remapped) == DECL_NAME (oparm));
>             /* Don't share a CONSTRUCTOR that might be changed.  */
>-            arg = unshare_expr (arg);
>+            arg = unshare_constructor (arg);
>             ctx->values->put (remapped, arg);
>             bound = TREE_CHAIN (bound);
>             remapped = DECL_CHAIN (remapped);
>@@ -1534,7 +1573,7 @@ cxx_eval_call_expression (const constexpr_ctx
>*ctx, tree t,
>     }
> 
>   pop_cx_call_context ();
>-  return unshare_expr (result);
>+  return unshare_constructor (result);
> }
> 
>/* FIXME speed this up, it's taking 16% of compile time on sieve
>testcase.  */
>@@ -1880,7 +1919,7 @@ find_array_ctor_elt (tree ary, tree dindex, bool
>insert = false)
>                 /* Append the element we want to insert.  */
>                 ++middle;
>                 e.index = dindex;
>-                e.value = unshare_expr (elt.value);
>+                e.value = unshare_constructor (elt.value);
>                 vec_safe_insert (CONSTRUCTOR_ELTS (ary), middle, e);
>               }
>             else
>@@ -1896,7 +1935,7 @@ find_array_ctor_elt (tree ary, tree dindex, bool
>insert = false)
>                   e.index = hi;
>                 else
>                   e.index = build2 (RANGE_EXPR, sizetype, new_lo, hi);
>-                e.value = unshare_expr (elt.value);
>+                e.value = unshare_constructor (elt.value);
>                 vec_safe_insert (CONSTRUCTOR_ELTS (ary), middle+1, e);
>               }
>           }
>@@ -2565,7 +2604,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx,
>tree atype, tree init,
>         for (i = 1; i < max; ++i)
>           {
>             idx = build_int_cst (size_type_node, i);
>-            CONSTRUCTOR_APPEND_ELT (*p, idx, unshare_expr (eltinit));
>+            CONSTRUCTOR_APPEND_ELT (*p, idx, unshare_constructor
>(eltinit));
>           }
>         break;
>       }
>@@ -3113,7 +3152,7 @@ cxx_eval_store_expression (const constexpr_ctx
>*ctx, tree t,
>   init = cxx_eval_constant_expression (&new_ctx, init, false,
>                                      non_constant_p, overflow_p);
>   /* Don't share a CONSTRUCTOR that might be changed later.  */
>-  init = unshare_expr (init);
>+  init = unshare_constructor (init);
>   if (target == object)
>     /* The hash table might have moved since the get earlier.  */
>     valp = ctx->values->get (object);
>@@ -3565,7 +3604,7 @@ cxx_eval_constant_expression (const constexpr_ctx
>*ctx, tree t,
>                                                false,
>                                                non_constant_p, overflow_p);
>           /* Don't share a CONSTRUCTOR that might be changed.  */
>-          init = unshare_expr (init);
>+          init = unshare_constructor (init);
>           ctx->values->put (r, init);
>         }
>       else if (ctx == &new_ctx)
>@@ -3610,7 +3649,7 @@ cxx_eval_constant_expression (const constexpr_ctx
>*ctx, tree t,
>       if (lval)
>       {
>         tree slot = TARGET_EXPR_SLOT (t);
>-        r = unshare_expr (r);
>+        r = unshare_constructor (r);
>         ctx->values->put (slot, r);
>         return slot;
>       }


Reply via email to