From patchwork Fri Mar 17 13:42:27 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Biener X-Patchwork-Id: 740326 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 3vl63S5P2Vz9ryZ for ; Sat, 18 Mar 2017 00:42:42 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="SqDzXyqK"; 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:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=xIv80GsX1A+bQhe6q/9PxzGhwiJRm+p6vFQ08P650TyxcPNFJhIEC ickX4djO6alRqxEXAcXYetznaSBwtEXE8MpEOcnURg19uulP13TRQRLsbq1FDXUA xtruulLQWq+gD93cW0KxhFqsD/vqSFnLjw1rtkhL7e5ZIK5FdhkZbw= 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:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=PijSeNKzilP7qC+o+BotkCxNKv8=; b=SqDzXyqKoUYNIgE1Zcso RkNM7jJCQyqd/RmzL1aGcHsG/KJPHL1+77EvPJvThEizV/PrOzWSI5bw61bE6BT7 SOioi0p3hEDVcnclyMyz8qO6AXRCBfcEbgp+4QmhjstCiF6wxFpDxsMaujWPRivJ EzqWA6HaMJP83hcFmQ+w2QQ= Received: (qmail 13797 invoked by alias); 17 Mar 2017 13:42:32 -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 12510 invoked by uid 89); 17 Mar 2017 13:42:31 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-11.1 required=5.0 tests=BAYES_00, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 spammy=roof, controlling X-HELO: mx2.suse.de Received: from mx2.suse.de (HELO mx2.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 17 Mar 2017 13:42:29 +0000 Received: from relay2.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id CC2FBAC48 for ; Fri, 17 Mar 2017 13:42:27 +0000 (UTC) Date: Fri, 17 Mar 2017 14:42:27 +0100 (CET) From: Richard Biener To: gcc-patches@gcc.gnu.org Subject: [PATCH] Fix PR80032 - handle CLOBBER gimplification differently Message-ID: User-Agent: Alpine 2.20 (LSU 67 2015-01-07) MIME-Version: 1.0 The following addresses PR80032 which reports that stack usage has gone up since DCE got the ability to remove clobbers. (Control-dependent-)DCE basically treats clobbers as not necessary and after eliminating unnecessary stmts sees if it can retain them and if not, removes them. This ability was added to keep removing "empty" loops (well, now loops with clobbers). With control-dependent DCE this always will remove code like if (cond) x = CLOBBER; because as the clobber itself is not necessary the controlling stmt isn't either and thus the BB with the clobber gets removed. We can't simply promote the CLOBBER to execute unconditionally because that changes semantics. But what we can do (I think) and what the patch does is at the time we add the CLOBBER, add it to a point post-dominating the old insertion point to avoid the above situation. This will be a spurious one in the case the condition was not true but at this point we know that the variable wasn't live in that case. Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Ok? Thanks, Richard. 2017-03-17 Richard Biener PR tree-optimization/80032 * gimplify.c (gimple_push_cleanup): Add force_uncond parameter, if set force the cleanup to happen unconditionally. (gimplify_target_expr): Push inserted clobbers with force_uncond to avoid them being removed by control-dependent DCE. * g++.dg/opt/pr80032.C: New testcase. Index: gcc/gimplify.c =================================================================== *** gcc/gimplify.c (revision 246216) --- gcc/gimplify.c (working copy) *************** gimplify_cleanup_point_expr (tree *expr_ *** 6288,6297 **** /* Insert a cleanup marker for gimplify_cleanup_point_expr. CLEANUP is the cleanup action required. EH_ONLY is true if the cleanup should ! only be executed if an exception is thrown, not on normal exit. */ static void ! gimple_push_cleanup (tree var, tree cleanup, bool eh_only, gimple_seq *pre_p) { gimple *wce; gimple_seq cleanup_stmts = NULL; --- 6288,6300 ---- /* Insert a cleanup marker for gimplify_cleanup_point_expr. CLEANUP is the cleanup action required. EH_ONLY is true if the cleanup should ! only be executed if an exception is thrown, not on normal exit. ! If FORCE_UNCOND is true perform the cleanup unconditionally; this is ! only valid for clobbers. */ static void ! gimple_push_cleanup (tree var, tree cleanup, bool eh_only, gimple_seq *pre_p, ! bool force_uncond = false) { gimple *wce; gimple_seq cleanup_stmts = NULL; *************** gimple_push_cleanup (tree var, tree clea *** 6301,6307 **** if (seen_error ()) return; ! if (gimple_conditional_context ()) { /* If we're in a conditional context, this is more complex. We only want to run the cleanup if we actually ran the initialization that --- 6304,6311 ---- if (seen_error ()) return; ! if (gimple_conditional_context () ! && ! force_uncond) { /* If we're in a conditional context, this is more complex. We only want to run the cleanup if we actually ran the initialization that *************** gimplify_target_expr (tree *expr_p, gimp *** 6426,6436 **** NULL); TREE_THIS_VOLATILE (clobber) = true; clobber = build2 (MODIFY_EXPR, TREE_TYPE (temp), temp, clobber); ! if (cleanup) ! cleanup = build2 (COMPOUND_EXPR, void_type_node, cleanup, ! clobber); ! else ! cleanup = clobber; } if (asan_poisoned_variables && dbg_cnt (asan_use_after_scope)) { --- 6430,6436 ---- NULL); TREE_THIS_VOLATILE (clobber) = true; clobber = build2 (MODIFY_EXPR, TREE_TYPE (temp), temp, clobber); ! gimple_push_cleanup (temp, clobber, false, pre_p, true); } if (asan_poisoned_variables && dbg_cnt (asan_use_after_scope)) { Index: gcc/testsuite/g++.dg/opt/pr80032.C =================================================================== Index: gcc/testsuite/g++.dg/opt/pr80032.C =================================================================== --- gcc/testsuite/g++.dg/opt/pr80032.C (nonexistent) +++ gcc/testsuite/g++.dg/opt/pr80032.C (working copy) @@ -0,0 +1,121 @@ +// PR tree-optimization/80032 +/* { dg-do compile } */ +/* { dg-require-effective-target c++11 } */ +/* { dg-options "-O2" } */ +/* If DCE removes too many CLOBBERs then stack usage goes through the + roof as stack slots can no longer be shared. */ +/* { dg-additional-options "-Wstack-usage=200" { target x86_64-*-* i?86-*-* } } */ + +typedef unsigned a; +namespace test { + enum b { c }; + class ADataContainer; + class BitMask; + namespace api { + enum DataStore { candidate }; + } + using d = api::DataStore; + namespace db { + class e; + class f; + class g; + class ManagedObjectConst { + public: + ManagedObjectConst(const ManagedObjectConst &); + bool isFieldDefault(a, d) const; + ADataContainer &getFieldDefault(a, d) const; + g *h; + e *i; + f *j; + }; + struct FieldInfo { + FieldInfo(ManagedObjectConst, a, d); + ManagedObjectConst k; + }; + b compare(const FieldInfo &, const ADataContainer &); + class ManagedObject : public ManagedObjectConst {}; + } + using namespace db; + void FN(ManagedObject &k, const BitMask &) { + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + if (!k.isFieldDefault(8, d::candidate) && + !compare(FieldInfo(k, 11, d::candidate), + k.getFieldDefault(11, d::candidate)) == c) + return; + } +}