From patchwork Fri Jan 13 03:37:21 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Law X-Patchwork-Id: 714769 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 3v07cX54Gfz9t1F for ; Fri, 13 Jan 2017 14:37:48 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="NxAq8r7z"; 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:to :from:subject:message-id:date:mime-version:content-type; q=dns; s=default; b=xTwj6Mhhbww8VzwKKQPYKr+3YykA03JJayk29HEmWH8PEuVbRs yHqqNFDXc3nMcorc30/fEbMwz/tFt10hqLC9uwImT8rB1NJRlcsJVKzABkJ82OAz LyRwqwqd0339FfW+qhFeq1XKcNjb/yqxekWWoUYNU4f23GTZFZRXkuGzE= 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:to :from:subject:message-id:date:mime-version:content-type; s= default; bh=BGFfNGPAMrk3DzSmnKN9sJcC+eE=; b=NxAq8r7z+bLwKtTpqDvq uJ6JTjentqS+0aGQ5OPKWt3PjGEJGu6BKr8aBxKhaccLN4a18W6E74DqQpGK0o4z joSJYf1sutdPEW2eRcWup0yIdLi3Ed4Ij3wGcTKuBTHS3YNoOJRUf9dBfC6OcQHJ htCSUNrvAr+g6PUoUlBhdk0= Received: (qmail 20434 invoked by alias); 13 Jan 2017 03:37:30 -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 20362 invoked by uid 89); 13 Jan 2017 03:37:29 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-4.1 required=5.0 tests=BAYES_00, KAM_LAZY_DOMAIN_SECURITY, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=bos, cur, UD:alias.h, alias.h X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 13 Jan 2017 03:37:23 +0000 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 39E614E05F for ; Fri, 13 Jan 2017 03:37:23 +0000 (UTC) Received: from localhost.localdomain (ovpn-119-37.rdu2.redhat.com [10.10.119.37]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v0D3bMdU001788 for ; Thu, 12 Jan 2017 22:37:22 -0500 To: gcc-patches From: Jeff Law Subject: [RFA][PATCH 2/4] [PR tree-optimization/61912] Trimming CONSTRUCTOR stores Message-ID: <5dd08215-b290-996d-e836-8ad037a34152@redhat.com> Date: Thu, 12 Jan 2017 20:37:21 -0700 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.5.1 MIME-Version: 1.0 X-IsSubscribed: yes This is a relatively minor update to the trimming CONSTRUCTOR stores patch to address various comments from Richi. First, simplification of maybe_trim_constructor_store given we only handle one case (CONSTRUCTOR_NELTS (ctor) == 0). Use build_array_type_elts and building an appropriate alias type to avoid pessimizing code, adding is_gimple_min_invariant check to avoid creating invalid gimple. Bootstrapped and regression tested with patches 1a & 1b on x86_64-linux-gnu as well as with subsequent patches. Given the changes Richi requested were dropped in verbatim I'm going to assume his LGTM comment is an approval once prereqs are in. JHeff PR tree-optimization/61912 PR tree-optimization/77485 * tree-ssa-dse.c: Include expr.h. (maybe_trim_constructor_store): New function. (maybe_trim_partially_dead_store): Call maybe_trim_constructor_store. * g++.dg/tree-ssa/ssa-dse-1.C: New test. * gcc.dg/tree-ssa/pr30375: Adjust expected output. * gcc.dg/tree-ssa/ssa-dse-24.c: New test. diff --git a/gcc/testsuite/g++.dg/tree-ssa/ssa-dse-1.C b/gcc/testsuite/g++.dg/tree-ssa/ssa-dse-1.C new file mode 100644 index 0000000..1fd8dec --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/ssa-dse-1.C @@ -0,0 +1,101 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c++14 -O -fdump-tree-dse1-details" } */ + +using uint = unsigned int; + +template +struct FixBuf +{ + C buf[S] = {}; +}; + +template +struct OutBuf +{ + C* cur; + C* end; + C* beg; + + template + constexpr + OutBuf(FixBuf& b) : cur{b.buf}, end{b.buf + S}, beg{b.buf} { } + + OutBuf(C* b, C* e) : cur{b}, end{e} { } + OutBuf(C* b, uint s) : cur{b}, end{b + s} { } + + constexpr + OutBuf& operator<<(C v) + { + if (cur < end) { + *cur = v; + } + ++cur; + return *this; + } + + constexpr + OutBuf& operator<<(uint v) + { + uint q = v / 10U; + uint r = v % 10U; + if (q) { + *this << q; + } + *this << static_cast(r + '0'); + return *this; + } +}; + +template +struct BufOrSize +{ + template + static constexpr auto Select(FixBuf& fb, OutBuf&) + { + return fb; + } +}; + +template<> +struct BufOrSize +{ + template + static constexpr auto Select(FixBuf&, OutBuf& ob) + { + return ob.cur - ob.beg; + } +}; + +// if BOS=1, it will return the size of the generated data, else the data itself +template +constexpr +auto fixbuf() +{ + FixBuf fb; + OutBuf ob{fb}; + for (uint i = 0; i <= N; ++i) { + ob << i << static_cast(i == N ? 0 : ' '); + } + return BufOrSize::Select(fb, ob); +} + +auto foo() +{ + constexpr auto x = fixbuf<13, 200>(); + return x; +} + +auto foo_sized() +{ + constexpr auto s = fixbuf<13, 0, 1>(); + constexpr auto x = fixbuf<13, s>(); + return x; +} + +int main() +{ +} + + +/* { dg-final { scan-tree-dump-times "MEM\\\[\\(struct FixBuf \\*\\)& \\+ \[0-9\]+B\\\] = {}" 1 "dse1" } } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr30375.c b/gcc/testsuite/gcc.dg/tree-ssa/pr30375.c index 0439b1c..4494a2b 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr30375.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr30375.c @@ -22,4 +22,5 @@ void test_signed_msg_encoding(void) f(); } -/* { dg-final { scan-tree-dump-times "signInfo = {}" 1 "dse1" } } */ +/* { dg-final { scan-tree-dump-times "MEM\\\[\\(struct _s \\*\\)&signInfo \\+ \[0-9\]+B\\\] = {}" 1 "dse1" } } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-24.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-24.c new file mode 100644 index 0000000..282194c --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-24.c @@ -0,0 +1,62 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dse1" } */ + + +typedef unsigned int wchar_t; +struct printf_info +{ + int prec; + int width; + wchar_t spec; + unsigned int is_long_double:1; + unsigned int is_short:1; + unsigned int is_long:1; + unsigned int alt:1; + unsigned int space:1; + unsigned int left:1; + unsigned int showsign:1; + unsigned int group:1; + unsigned int extra:1; + unsigned int is_char:1; + unsigned int wide:1; + unsigned int i18n:1; + unsigned int __pad:4; + unsigned short int user; + wchar_t pad; +} info; + +void bar (struct printf_info *); + +void foo(int prec, + int width, + wchar_t spec, + unsigned int is_long_double, + unsigned int is_short, + unsigned int is_long, + unsigned int alt, + unsigned int space, + unsigned int left, + unsigned int showsign, + unsigned int group, + wchar_t pad) +{ + struct printf_info info = { + .prec = prec, + .width = width, + .spec = spec, + .is_long_double = is_long_double, + .is_short = is_short, + .is_long = is_long, + .alt = alt, + .space = space, + .left = left, + .showsign = showsign, + .group = group, + .pad = pad, + .extra = 0, + .wide = sizeof (char) != 1 }; + + bar (&info); +} + +/* { dg-final { scan-tree-dump-times "MEM\\\[\\(struct printf_info \\*\\)&info \\+ \[0-9\]+B\\\] = {}" 1 "dse1" } } */ diff --git a/gcc/tree-ssa-dse.c b/gcc/tree-ssa-dse.c index daaa99c..83ce29b 100644 --- a/gcc/tree-ssa-dse.c +++ b/gcc/tree-ssa-dse.c @@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see #include "domwalk.h" #include "tree-cfgcleanup.h" #include "params.h" +#include "alias.h" /* This file implements dead store elimination. @@ -271,6 +272,66 @@ maybe_trim_complex_store (ao_ref *ref, sbitmap live, gimple *stmt) are live. We do not try to optimize those cases. */ } +/* STMT initializes an object using a CONSTRUCTOR where one or more of the + bytes written are dead stores. ORIG is the bitmap of bytes stored by + STMT. LIVE is the bitmap of stores that are actually live. + + Attempt to rewrite STMT so that only the real or imaginary part of + the object is actually stored. + + The most common case for getting here is a CONSTRUCTOR with no elements + being used to zero initialize an object. We do not try to handle other + cases as those would force us to fully cover the object with the + CONSTRUCTOR node except for the components that are dead. */ + +static void +maybe_trim_constructor_store (ao_ref *ref, sbitmap live, gimple *stmt) +{ + tree ctor = gimple_assign_rhs1 (stmt); + + /* This is the only case we currently handle. It actually seems to + catch most cases of actual interest. */ + gcc_assert (CONSTRUCTOR_NELTS (ctor) == 0); + + int head_trim = 0; + int tail_trim = 0; + compute_trims (ref, live, &head_trim, &tail_trim); + + /* Now we want to replace the constructor initializer + with memset (object + head_trim, 0, size - head_trim - tail_trim). */ + if (head_trim || tail_trim) + { + /* We want &lhs for the MEM_REF expression. */ + tree lhs_addr = build_fold_addr_expr (gimple_assign_lhs (stmt)); + + if (! is_gimple_min_invariant (lhs_addr)) + return; + + /* The number of bytes for the new constructor. */ + int count = (ref->size / BITS_PER_UNIT) - head_trim - tail_trim; + + /* And the new type for the CONSTRUCTOR. Essentially it's just + a char array large enough to cover the non-trimmed parts of + the original CONSTRUCTOR. Note we want explicit bounds here + so that we know how many bytes to clear when expanding the + CONSTRUCTOR. */ + tree type = build_array_type_nelts (char_type_node, count); + + /* Build a suitable alias type rather than using alias set zero + to avoid pessimizing. */ + tree alias_type = reference_alias_ptr_type (gimple_assign_lhs (stmt)); + + /* Build a MEM_REF representing the whole accessed area, starting + at the first byte not trimmed. */ + tree exp = fold_build2 (MEM_REF, type, lhs_addr, + build_int_cst (alias_type, head_trim)); + + /* Now update STMT with a new RHS and LHS. */ + gimple_assign_set_lhs (stmt, exp); + gimple_assign_set_rhs1 (stmt, build_constructor (type, NULL)); + } +} + /* STMT is a memory write where one or more bytes written are dead stores. ORIG is the bitmap of bytes stored by STMT. LIVE is the bitmap of stores that are actually live. @@ -287,6 +348,9 @@ maybe_trim_partially_dead_store (ao_ref *ref, sbitmap live, gimple *stmt) { switch (gimple_assign_rhs_code (stmt)) { + case CONSTRUCTOR: + maybe_trim_constructor_store (ref, live, stmt); + break; case COMPLEX_CST: maybe_trim_complex_store (ref, live, stmt); break;