re PR tree-optimization/80032 (C++ excessive stack usage (no stack reuse))
authorRichard Biener <rguenther@suse.de>
Tue, 21 Mar 2017 11:43:45 +0000 (11:43 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Tue, 21 Mar 2017 11:43:45 +0000 (11:43 +0000)
2017-03-21  Richard Biener  <rguenther@suse.de>

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.

From-SVN: r246314

gcc/ChangeLog
gcc/gimplify.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/opt/pr80032.C [new file with mode: 0644]

index f48f6d3..d679a5c 100644 (file)
@@ -1,5 +1,13 @@
 2017-03-21  Richard Biener  <rguenther@suse.de>
 
+       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.
+
+2017-03-21  Richard Biener  <rguenther@suse.de>
+
        PR tree-optimization/80122
        * tree-inline.c (copy_bb): Do not expans va-arg packs or
        va_arg_pack_len when the inlined call stmt requires pack
index fbf136f..06f984c 100644 (file)
@@ -6288,10 +6288,13 @@ gimplify_cleanup_point_expr (tree *expr_p, gimple_seq *pre_p)
 
 /* 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.  */
+   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)
+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;
@@ -6301,7 +6304,7 @@ gimple_push_cleanup (tree var, tree cleanup, bool eh_only, gimple_seq *pre_p)
   if (seen_error ())
     return;
 
-  if (gimple_conditional_context ())
+  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
@@ -6426,11 +6429,7 @@ gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
                                                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;
+             gimple_push_cleanup (temp, clobber, false, pre_p, true);
            }
          if (asan_poisoned_variables && dbg_cnt (asan_use_after_scope))
            {
index 68705a7..08fcb72 100644 (file)
@@ -1,5 +1,10 @@
 2017-03-21  Richard Biener  <rguenther@suse.de>
 
+       PR tree-optimization/80032
+       * g++.dg/opt/pr80032.C: New testcase.
+
+2017-03-21  Richard Biener  <rguenther@suse.de>
+
        PR tree-optimization/80122
        * gcc.dg/torture/pr80122.c: New testcase.
 
diff --git a/gcc/testsuite/g++.dg/opt/pr80032.C b/gcc/testsuite/g++.dg/opt/pr80032.C
new file mode 100644 (file)
index 0000000..9cdad68
--- /dev/null
@@ -0,0 +1,120 @@
+// PR tree-optimization/80032
+// { dg-do compile { 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;
+    }
+}