aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2020-03-19 11:06:52 -0400
committerJason Merrill <jason@redhat.com>2020-03-19 21:47:28 -0400
commit94e2418780f1d13235f3e2e6e5c09dbe821c1ce3 (patch)
treeea07f1fcf672378cce0331e64ffdb78894a228e4
parent3373d3e38eaf807573cd04150a12ab1e43035f4d (diff)
downloadgcc-94e2418780f1d13235f3e2e6e5c09dbe821c1ce3.zip
gcc-94e2418780f1d13235f3e2e6e5c09dbe821c1ce3.tar.gz
gcc-94e2418780f1d13235f3e2e6e5c09dbe821c1ce3.tar.bz2
c++: Avoid unnecessary empty class copy [94175].
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. 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.
-rw-r--r--gcc/cp/ChangeLog11
-rw-r--r--gcc/cp/call.c4
-rw-r--r--gcc/cp/cp-gimplify.c13
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/testsuite/g++.dg/abi/empty30.C14
5 files changed, 42 insertions, 1 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index b5d429b..929e709 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,14 @@
+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.
+
2020-03-19 Jakub Jelinek <jakub@redhat.com>
PR c++/93931
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 1715acc..65a3ea3 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 87c7e39..aa80384 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/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 757cdd8..0783b31 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/testsuite/g++.dg/abi/empty30.C b/gcc/testsuite/g++.dg/abi/empty30.C
new file mode 100644
index 0000000..f10d203
--- /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);
+}