diff mbox series

[pushed] c++: Avoid unnecessary empty class copy [94175].

Message ID 20200320030957.4889-1-jason@redhat.com
State New
Headers show
Series [pushed] c++: Avoid unnecessary empty class copy [94175]. | expand

Commit Message

Jeff Law via Gcc-patches March 20, 2020, 3:09 a.m. UTC
A simple empty class copy is still simple when wrapped in a TARGET_EXPR, so
we need to strip that as well.  This change also exposed some unnecessary
copies in return statements, which when returning by invisible reference led
to <RETURN_EXPR <MEM_REF <RESULT_DECL>>>, which gimplify_return_expr didn't
like.  So we also need to strip the _REF when we eliminate the INIT_EXPR.

Tested x86_64-pc-linux-gnu, applying to trunk.

gcc/cp/ChangeLog
2020-03-19  Jason Merrill  <jason@redhat.com>

	PR c++/94175
	* cp-gimplify.c (simple_empty_class_p): Look through
	SIMPLE_TARGET_EXPR_P.
	(cp_gimplify_expr) [MODIFY_EXPR]: Likewise.
	[RETURN_EXPR]: Avoid producing 'return *retval;'.
	* call.c (build_call_a): Strip TARGET_EXPR from empty class arg.
	* cp-tree.h (SIMPLE_TARGET_EXPR_P): Check that TARGET_EXPR_INITIAL
	is non-null.
---
 gcc/cp/cp-tree.h                   |  1 +
 gcc/cp/call.c                      |  4 ++++
 gcc/cp/cp-gimplify.c               | 13 ++++++++++++-
 gcc/testsuite/g++.dg/abi/empty30.C | 14 ++++++++++++++
 4 files changed, 31 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/abi/empty30.C


base-commit: 3373d3e38eaf807573cd04150a12ab1e43035f4d
diff mbox series

Patch

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 757cdd8168a..0783b3114f2 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5145,6 +5145,7 @@  more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
    the initializer has void type, it's doing something more complicated.  */
 #define SIMPLE_TARGET_EXPR_P(NODE)				\
   (TREE_CODE (NODE) == TARGET_EXPR				\
+   && TARGET_EXPR_INITIAL (NODE)				\
    && !VOID_TYPE_P (TREE_TYPE (TARGET_EXPR_INITIAL (NODE))))
 
 /* True if EXPR expresses direct-initialization of a TYPE.  */
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 1715acc0ec3..65a3ea35dee 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -392,6 +392,10 @@  build_call_a (tree function, int n, tree *argarray)
 	if (is_empty_class (TREE_TYPE (arg))
 	    && simple_empty_class_p (TREE_TYPE (arg), arg, INIT_EXPR))
 	  {
+	    while (TREE_CODE (arg) == TARGET_EXPR)
+	      /* We're disconnecting the initializer from its target,
+		 don't create a temporary.  */
+	      arg = TARGET_EXPR_INITIAL (arg);
 	    tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (arg));
 	    arg = build2 (COMPOUND_EXPR, TREE_TYPE (t), arg, t);
 	    CALL_EXPR_ARG (function, i) = arg;
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index 87c7e394b01..aa80384e1a4 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -603,6 +603,10 @@  simple_empty_class_p (tree type, tree op, tree_code code)
 {
   if (TREE_CODE (op) == COMPOUND_EXPR)
     return simple_empty_class_p (type, TREE_OPERAND (op, 1), code);
+  if (SIMPLE_TARGET_EXPR_P (op)
+      && TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
+    /* The TARGET_EXPR is itself a simple copy, look through it.  */
+    return simple_empty_class_p (type, TARGET_EXPR_INITIAL (op), code);
   return
     (TREE_CODE (op) == EMPTY_CLASS_EXPR
      || code == MODIFY_EXPR
@@ -740,6 +744,11 @@  cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
 
 	else if (simple_empty_class_p (TREE_TYPE (op0), op1, code))
 	  {
+	    while (TREE_CODE (op1) == TARGET_EXPR)
+	      /* We're disconnecting the initializer from its target,
+		 don't create a temporary.  */
+	      op1 = TARGET_EXPR_INITIAL (op1);
+
 	    /* Remove any copies of empty classes.  Also drop volatile
 	       variables on the RHS to avoid infinite recursion from
 	       gimplify_expr trying to load the value.  */
@@ -754,6 +763,9 @@  cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
 	    gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
 			   is_gimple_lvalue, fb_lvalue);
 	    *expr_p = TREE_OPERAND (*expr_p, 0);
+	    if (code == RETURN_EXPR && REFERENCE_CLASS_P (*expr_p))
+	      /* Avoid 'return *<retval>;'  */
+	      *expr_p = TREE_OPERAND (*expr_p, 0);
 	  }
 	/* P0145 says that the RHS is sequenced before the LHS.
 	   gimplify_modify_expr gimplifies the RHS before the LHS, but that
@@ -924,7 +936,6 @@  cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
 	      || TREE_CODE (TREE_OPERAND (*expr_p, 0)) == MODIFY_EXPR))
 	{
 	  expr_p = &TREE_OPERAND (*expr_p, 0);
-	  code = TREE_CODE (*expr_p);
 	  /* Avoid going through the INIT_EXPR case, which can
 	     degrade INIT_EXPRs into AGGR_INIT_EXPRs.  */
 	  goto modify_expr_case;
diff --git a/gcc/testsuite/g++.dg/abi/empty30.C b/gcc/testsuite/g++.dg/abi/empty30.C
new file mode 100644
index 00000000000..f10d2034e36
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty30.C
@@ -0,0 +1,14 @@ 
+// PR c++/94175
+// { dg-do link }
+
+struct A {};
+extern A a;
+
+int i;
+__attribute ((noinline, noclone))
+void f(A) { ++i; }
+
+int main()
+{
+  f(a);
+}