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]

Do not produce empty try-finally statements


Hi,
when compiling:
struct A  
{
    virtual int foo (void) {return 42;}
};
int test (void)
{ 
  struct A a, *b=&a;
  return b->foo();
}

We wind up the following useless EH:
int test() ()
{
  int D.2235;
  int (*__vtbl_ptr_type) () * D.2236;
  int (*__vtbl_ptr_type) () D.2237;
  struct A a;
  struct A * b;

  try
    {
      A::A (&a);
      b = &a;
      D.2236 = b->_vptr.A;
      D.2237 = *D.2236;
      D.2235 = OBJ_TYPE_REF(D.2237;b->0) (b);
      return D.2235;
    }
  finally
    {
      a = {CLOBBER};
    }
}

while ehcleanup gets rid of the try..finally code later, it happens only
with optimizing compilation. With -O0 the EH gets all the way down to the
binary that is rather embarassing.

I believe this is a regression since CLOBBERs were introduced.

Gimplifier already has logic to skip empty cleanups, the patch bellow
just makes it to ignore clobbers.

I checked that empty_body_p is used only in gomp lowering in very similar
scenario, so I think it is safe to change them and we don't need to introduce
new statement.

On related note however, the ehcleanup pass itself is using nondebug_stmt
to detect empty cleanups.  Again I think it is bug.  I wonder if we should
not invent active_stmt (matching RTL's naming scheme) and revisit current
uses of non-debug?

Bootstrapped/regtested x86_64-linux, OK?

	* gimplify.c (gimplify_bind_expr, gimplify_expr): Use empty_body_p
	to detect no-op sequences.
	* gimple.c (empty_body_p): Ignore clobbers.

	* g++.dg/tree-ssa/ehcleanup-1.C: Update testcase so it is harder
	to optimize
	* g++.dg/tree-ssa/ehcleanup-2.C: New testcase.


Index: gimplify.c
===================================================================
--- gimplify.c	(revision 206684)
+++ gimplify.c	(working copy)
@@ -1106,7 +1106,7 @@
 	}
     }
 
-  if (cleanup)
+  if (!empty_body_p (cleanup))
     {
       gimple gs;
       gimple_seq new_body;
@@ -7771,7 +7771,7 @@
 	    gimplify_and_add (TREE_OPERAND (*expr_p, 0), &eval);
 	    gimplify_and_add (TREE_OPERAND (*expr_p, 1), &cleanup);
 	    /* Don't create bogus GIMPLE_TRY with empty cleanup.  */
-	    if (gimple_seq_empty_p (cleanup))
+	    if (empty_body_p (cleanup))
 	      {
 		gimple_seq_add_seq (pre_p, eval);
 		ret = GS_ALL_DONE;
Index: gimple.c
===================================================================
--- gimple.c	(revision 206684)
+++ gimple.c	(working copy)
@@ -1264,6 +1264,7 @@
     return true;
   for (i = gsi_start (body); !gsi_end_p (i); gsi_next (&i))
     if (!empty_stmt_p (gsi_stmt (i))
+	&& !gimple_clobber_p (gsi_stmt (i))
 	&& !is_gimple_debug (gsi_stmt (i)))
       return false;
 
Index: testsuite/g++.dg/tree-ssa/ehcleanup-1.C
===================================================================
--- testsuite/g++.dg/tree-ssa/ehcleanup-1.C	(revision 206684)
+++ testsuite/g++.dg/tree-ssa/ehcleanup-1.C	(working copy)
@@ -12,7 +12,8 @@
 public:
   ~a () NOEXCEPT_FALSE
   {
-    if (0)
+    int t = 0;
+    if (t)
       can_throw ();
   }
 };
@@ -23,9 +24,9 @@
   can_throw ();
 }
 // We ought to remove implicit cleanup, since destructor is empty. 
-// { dg-final { scan-tree-dump-times "Empty EH handler" 2 "ehcleanup1" } }
+// { dg-final { scan-tree-dump-times "Empty EH handler" 1 "ehcleanup1" } }
 //
 // And as a result also contained control flow.
-// { dg-final { scan-tree-dump-times "Removing unreachable" 6 "ehcleanup1" } }
+// { dg-final { scan-tree-dump-times "Removing unreachable" 2 "ehcleanup1" } }
 //
 // { dg-final { cleanup-tree-dump "ehcleanup1" } }
Index: testsuite/g++.dg/tree-ssa/ehcleanup-2.C
===================================================================
--- testsuite/g++.dg/tree-ssa/ehcleanup-2.C	(revision 0)
+++ testsuite/g++.dg/tree-ssa/ehcleanup-2.C	(revision 0)
@@ -0,0 +1,12 @@
+// { dg-options "-O0 -fdump-tree-gimple" }
+  struct A 
+  {
+    virtual int foo (void) {return 42;}
+  };
+int test (void)
+{
+  struct A a, *b=&a;
+  return b->foo();
+}
+// { dg-final { scan-tree-dump-not "finally" "gimple" } }
+// { dg-final { cleanup-tree-dump "gimple" } }


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