From 94e2418780f1d13235f3e2e6e5c09dbe821c1ce3 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 19 Mar 2020 11:06:52 -0400 Subject: [PATCH] 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 >>, 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 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/ChangeLog | 11 +++++++++++ gcc/cp/call.c | 4 ++++ gcc/cp/cp-gimplify.c | 13 ++++++++++++- gcc/cp/cp-tree.h | 1 + gcc/testsuite/g++.dg/abi/empty30.C | 14 ++++++++++++++ 5 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/abi/empty30.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b5d429b5c35..929e709fadf 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2020-03-19 Jason Merrill + + 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 PR c++/93931 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 *;' */ + *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 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/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); +} -- 2.30.2