[patch] Optimize empty class copies within a C++ return statement

Aldy Hernandez aldyh@redhat.com
Thu Mar 5 23:25:00 GMT 2015


While looking at PR65284, I was confused by the gimple we generate for 
returns of empty classes by value:

class obj {
   public:
    obj(int);
};

obj funky(){
     return obj(555);
}

For the above snippet, we generate:

obj funky() ()
{
   struct obj D.2248;
   struct obj D.2246;

   obj::obj (&D.2246, 555);
   try
     {
       return D.2248;
     }
   finally
     {
       D.2246 = {CLOBBER};
     }
}

Particularly confusing is the return of uninitialized D.2248.  Jason 
tried to beat into me today the fact that it doesn't matter because 
there is no value to initialize since the class is empty.  I still think 
it's weird, however...

What led us to the above gimple was the fact that we lowered into:

	return retval = D.2248 = D.2246

which was later optimized by cp_gimplify_expr into "return D.2248" 
because the C++ gimplifier hook notices that the copy is unnecessary.

Jason suggested that it would be nice to remove D.2248 altogether.  With 
the attached patch we notice the superfluous copy in the return value 
and optimize it away.  After some hoops we now get:

   obj::obj (&D.2246, 555);
   try
     {
       return <retval>;
     }
   finally
     {
       D.2246 = {CLOBBER};
     }

Tested on x86-64 Linux.

OK?
-------------- next part --------------
commit 8fd545d608f2a6c11f889e11c700711b8f911c02
Author: Aldy Hernandez <aldyh@redhat.com>
Date:   Thu Mar 5 12:23:27 2015 -0800

    	* cp-gimplify.c (cp_gimplify_expr): Optimize empty class copies
    	within a return statement.

diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index 4233a64..f8d4559 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -740,6 +740,29 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
 	}
       break;
 
+    case RETURN_EXPR:
+      {
+	/* Optimize `return <retval> = object' where object's type is
+	   an empty class.  Avoid the copy, altogether and just return
+	   retval.  */
+	tree ret = TREE_OPERAND (*expr_p, 0);
+	if (ret && (TREE_CODE (ret) == INIT_EXPR
+		    || TREE_CODE (ret) == MODIFY_EXPR)
+	    && TREE_CODE (TREE_OPERAND (ret, 0)) == RESULT_DECL
+	    && is_gimple_lvalue (TREE_OPERAND (ret, 0))
+	    && is_really_empty_class (TREE_TYPE (TREE_OPERAND (ret, 0))))
+	  {
+	    tree result_decl = TREE_OPERAND (ret, 0);
+	    tree list = alloc_stmt_list ();
+	    append_to_statement_list (TREE_OPERAND (ret, 1), &list);
+	    append_to_statement_list (build1 (RETURN_EXPR, void_type_node,
+					      result_decl), &list);
+	    *expr_p = list;
+	    return GS_OK;
+	  }
+	/* Otherwise fall through.  */
+      }
+
     default:
       ret = (enum gimplify_status) c_gimplify_expr (expr_p, pre_p, post_p);
       break;
diff --git a/gcc/testsuite/g++.dg/other/empty-class.C b/gcc/testsuite/g++.dg/other/empty-class.C
new file mode 100644
index 0000000..a14c437
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/empty-class.C
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-tree-gimple" } */
+
+/* Test that we return retval directly, instead of going through an
+   intermediate temporary, when returning an empty class.  */
+
+class obj {
+  public:
+   obj(int);
+};
+
+obj funky(){
+    return obj(555);
+}
+
+/* { dg-final { scan-tree-dump-times "return <retval>;" 1 "gimple" } } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */


More information about the Gcc-patches mailing list