From patchwork Wed Apr 6 22:25:04 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 607172 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3qgKzq2pstz9t5V for ; Thu, 7 Apr 2016 08:25:26 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=lbol4j6N; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :date:to:cc:subject:in-reply-to:message-id:references :mime-version:content-type; q=dns; s=default; b=hAIZI8K/ebp7wa+0 Epn57MBUjlUtLkpTPEhnqaoGgZBBevo4KabFBD/zAj4bgtS417/+oyMCRheJetes 0eQpbaOHiw7GRhgjdMqjCGfElfm3UYl2LxTaJKSBaaEfiUVTgTwTgcvN6zYdjuSD 7pJC3IZTumb87mTNbnD0YPcENSs= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :date:to:cc:subject:in-reply-to:message-id:references :mime-version:content-type; s=default; bh=saTgn2mkp3qzMvuccdqSeL 0Jne8=; b=lbol4j6NcTOBnE4PyE/Y7lZVSVu1sWtjEK/W5NpaRdInd+7PeV/S+7 Jsga31RySYgPLSGQXCMM7jhqJX75nLbIbyhucgfDZAiMGg0z4bZ7neoNh/Lbz0tZ 0CW747ZlXr5YVsudljMvz8ATMlYkp5l96DBm1FYrji0jajiSYYgBI= Received: (qmail 48270 invoked by alias); 6 Apr 2016 22:25:19 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 48261 invoked by uid 89); 6 Apr 2016 22:25:18 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 spammy= X-HELO: mail-qg0-f54.google.com Received: from mail-qg0-f54.google.com (HELO mail-qg0-f54.google.com) (209.85.192.54) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Wed, 06 Apr 2016 22:25:08 +0000 Received: by mail-qg0-f54.google.com with SMTP id f52so48538721qga.3 for ; Wed, 06 Apr 2016 15:25:08 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:date:to:cc:subject:in-reply-to:message-id :references:user-agent:mime-version; bh=fy+xBFAc9vvmx8Xf5UL+WrTLMcI+4xegocJFP5fdwic=; b=JDS48i27CsJGOBX0b2p6VXVDfwgaV0crm/2+ZG/5J8/Zcf5OXXbObVZUefSf8mltSK 14AZI43D0vXHm4f+fiZVXDYRKJE61/FiHEmKywCBwfiawPi2ze616XZN+4oBZvc67Ulo 1nAnVKTt79Yy66E9hmvOzPku/r4nF9K6GcNd2p7aGm9PRO5z0KPgBgjppxkp09oQI7HG OHyvVO0xMmd/hOEFHYJsByxuJV8Zp1hdEmFRVSiaJ/V0Tn0+Q7RV11nRbPNZKDHJFAgn uEcA/aR7HuGmz7Lzxj1e77tskwm/IHP4VGESL7AQunH6mG35lnfgXTbopEKHKFeFTc1a 1r1A== X-Gm-Message-State: AD7BkJKGpvpKBffRG3gFBR2YArJB6R0fJin2cWX8PRsXWHv/RcIvpBhagH1w5EXyT7XuUQ== X-Received: by 10.140.198.135 with SMTP id t129mr237257qha.36.1459981506206; Wed, 06 Apr 2016 15:25:06 -0700 (PDT) Received: from [192.168.1.130] (ool-4353abbc.dyn.optonline.net. [67.83.171.188]) by smtp.gmail.com with ESMTPSA id u102sm2171047qge.27.2016.04.06.15.25.05 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Apr 2016 15:25:05 -0700 (PDT) From: Patrick Palka X-Google-Original-From: Patrick Palka Date: Wed, 6 Apr 2016 18:25:04 -0400 (EDT) To: Patrick Palka cc: Richard Biener , GCC Patches , Jason Merrill Subject: Re: [PATCH] Avoid needless unsharing during constexpr evaluation (PR c++/70452) In-Reply-To: Message-ID: References: <1459961500-8709-1-git-send-email-patrick@parcs.ath.cx> <23BF17BD-8114-4EAF-9D97-43718D6BB900@gmail.com> User-Agent: Alpine 2.20.11 (DEB 116 2015-12-14) MIME-Version: 1.0 On Wed, 6 Apr 2016, Patrick Palka wrote: > On Wed, Apr 6, 2016 at 1:17 PM, Richard Biener > wrote: > > On April 6, 2016 6:51:40 PM GMT+02:00, Patrick Palka 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. > > I see... I was assuming that the expressions passed to unshare_expr > would be more or less normalized but of course if the expression > involves a non-constant operand then not much normalization can be > done. So the patch ICEs on the following test case because we don't > normalize = g (X { }) to = 5 since g is not > constexpr. So we end up calling unshare_constructor on this CALL_EXPR > whose argument is a CONSTRUCTOR. > > struct X { }; > > constexpr int > foo (int (*f) (X)) > { > return f (X { }); > } > > int > g (X) > { > return 5; > } > > int a = foo (g); > > So the added assert and probably this patch is wrong. Hmm... Here is a safer and simpler approach that just walks the expression being unshared to try to find a CONSTRUCTOR node. If it finds one, then we unshare the whole expression. Otherwise we return the original expression. It should be completely safe to avoid unsharing an expression if it contains no CONSTRUCTOR nodes. -- >8 -- gcc/cp/ChangeLog: PR c++/70452 * constexpr.c (find_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 | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 1c2701b..5bccdec 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1151,6 +1151,30 @@ adjust_temp_type (tree type, tree temp) return cp_fold_convert (type, temp); } +/* Callback for walk_tree used by unshare_constructor. */ + +static tree +find_constructor (tree *tp, int *walk_subtrees, void *) +{ + if (TYPE_P (*tp)) + *walk_subtrees = 0; + if (TREE_CODE (*tp) == CONSTRUCTOR) + return *tp; + return NULL_TREE; +} + +/* If T is a CONSTRUCTOR or an expression that has a CONSTRUCTOR node as a + subexpression, return an unshared copy of T. Otherwise return T. */ + +static tree +unshare_constructor (tree t) +{ + tree ctor = walk_tree (&t, find_constructor, NULL, NULL); + if (ctor != NULL_TREE) + return unshare_expr (t); + 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 +1478,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 +1558,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 +1904,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 +1920,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 +2589,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 +3137,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 +3589,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 +3634,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; }