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.
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.
--- /dev/null
+/* { 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" } } */
+
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" } } */
+
--- /dev/null
+/* { 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" } } */
#include "domwalk.h"
#include "tree-cfgcleanup.h"
#include "params.h"
+#include "alias.h"
/* This file implements dead store elimination.
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.
{
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;