This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix PR80032 - handle CLOBBER gimplification differently


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  <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.

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;
+    }
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]