re PR middle-end/61912 (Missed (partial) dead store elimination for structures on...
authorJeff Law <law@redhat.com>
Fri, 13 Jan 2017 15:46:22 +0000 (08:46 -0700)
committerJeff Law <law@gcc.gnu.org>
Fri, 13 Jan 2017 15:46:22 +0000 (08:46 -0700)
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.

PR tree-optimization/61912
PR tree-optimization/77485
* 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.

From-SVN: r244443

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/tree-ssa/ssa-dse-1.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr30375.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-24.c [new file with mode: 0644]
gcc/tree-ssa-dse.c

index 3cb1a600c42ff4f365f6109c3fe99878c1369540..221aff93d49d59cae74e5e852193b49c2eca8ecc 100644 (file)
@@ -1,8 +1,14 @@
 2017-01-13  Jeff Law  <law@redhat.com>
 
-        PR tree-optimization/33562
-        PR tree-optimization/61912
-        PR tree-optimization/77485
+       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.
+
+       PR tree-optimization/33562
+       PR tree-optimization/61912
+       PR tree-optimization/77485
        * doc/invoke.texi: Document new dse-max-object-size param.
        * params.def (PARM_DSE_MAX_OBJECT_SIZE): New PARAM.
        * tree-ssa-dse.c: Include params.h.
index edee5a4a6332927cfa6fa05f74ec0ef7ee2c7f0d..bb9b824b18753bd2bed8615995b85433313ed32b 100644 (file)
@@ -1,8 +1,14 @@
 2017-01-13  Jeff Law  <law@redhat.com>
 
-        PR tree-optimization/33562
-        PR tree-optimization/61912
-        PR tree-optimization/77485
+       PR tree-optimization/61912
+       PR tree-optimization/77485
+       * 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.
+
+       PR tree-optimization/33562
+       PR tree-optimization/61912
+       PR tree-optimization/77485
        * gcc.dg/tree-ssa/complex-4.c: Remove xfail.
        * gcc.dg/tree-ssa/complex-5.c: Likewise.
        * gcc.dg/tree-ssa/ssa-dse-9.c: Likewise.
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 (file)
index 0000000..1fd8dec
--- /dev/null
@@ -0,0 +1,101 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c++14 -O -fdump-tree-dse1-details" } */
+
+using uint = unsigned int;
+
+template<typename C, uint S>
+struct FixBuf
+{
+       C buf[S] = {};
+};
+
+template<typename C>
+struct OutBuf
+{
+       C*      cur;
+       C*      end;
+       C*      beg;
+
+       template<uint S>
+       constexpr
+       OutBuf(FixBuf<C, S>& 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<C>(r + '0');
+               return *this;
+       }
+};
+
+template<bool BOS>
+struct BufOrSize
+{
+       template<typename C, uint S>
+       static constexpr auto Select(FixBuf<C, S>& fb, OutBuf<C>&)
+       {
+               return fb;
+       }
+};
+
+template<>
+struct BufOrSize<true>
+{
+       template<typename C, uint S>
+       static constexpr auto Select(FixBuf<C, S>&, OutBuf<C>& ob)
+       {
+               return ob.cur - ob.beg;
+       }
+};
+
+// if BOS=1, it will return the size of the generated data, else the data itself
+template<uint N, uint S, bool BOS = 0>
+constexpr
+auto fixbuf()
+{
+       FixBuf<char, S> fb;
+       OutBuf<char> ob{fb};
+       for (uint i = 0; i <= N; ++i) {
+               ob << i << static_cast<char>(i == N ? 0 : ' ');
+       }
+       return BufOrSize<BOS>::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 \\*\\)&<retval> \\+ \[0-9\]+B\\\] = {}" 1 "dse1" } } */
+
index 0439b1c9ce26eed672beb2b0b54edeb111ee2ec5..4494a2b0bd6b274ac983914c75580f9098fe00f3 100644 (file)
@@ -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 (file)
index 0000000..282194c
--- /dev/null
@@ -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" } } */
index daaa99c4dd8e343c9e7d512e3dd772fcb0c64a01..83ce29b86701781e8ec6a1c97d825062e5a30a95 100644 (file)
@@ -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;