From 1b4fddaab3acaf31905dfdd348975258c4c798e7 Mon Sep 17 00:00:00 2001 From: jason Date: Wed, 5 May 2010 16:32:20 +0000 Subject: [PATCH] PR c++/43787 gcc: * gimplify.c (gimplify_expr): Keep working if gimplify_modify_expr returns GS_OK. (gimplify_modify_expr_rhs): Return GS_OK if anything changed. gcc/cp: * cp-gimplify.c (cp_gimplify_expr): Remove copies of empty classes. * call.c (build_over_call): Don't try to avoid INIT_EXPR copies here. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@159072 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 7 + gcc/cp/ChangeLog | 6 + gcc/cp/call.c | 14 +- gcc/gimplify.c | 429 ++++++++++++++++++++++++------------------------ gcc/testsuite/ChangeLog | 5 + 5 files changed, 237 insertions(+), 224 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 89487f7aa52..26ef33b3fc7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2010-05-05 Jason Merrill + + PR c++/43787 + * gimplify.c (gimplify_expr): Keep working if gimplify_modify_expr + returns GS_OK. + (gimplify_modify_expr_rhs): Return GS_OK if anything changed. + 2010-05-05 Alexandre Oliva Jakub Jelinek diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e186a5d1b56..4e9a2d0bfb5 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2010-05-05 Jason Merrill + + PR c++/43787 + * cp-gimplify.c (cp_gimplify_expr): Remove copies of empty classes. + * call.c (build_over_call): Don't try to avoid INIT_EXPR copies here. + 2010-05-04 Paolo Carlini PR c++/43028 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 157b473cdc4..0ba0994d1a6 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -5778,20 +5778,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) { tree to = stabilize_reference (cp_build_indirect_ref (fa, RO_NULL, complain)); - tree type = TREE_TYPE (to); - if (TREE_CODE (arg) != TARGET_EXPR - && TREE_CODE (arg) != AGGR_INIT_EXPR - && is_really_empty_class (type)) - { - /* Avoid copying empty classes. */ - val = build2 (COMPOUND_EXPR, void_type_node, to, arg); - TREE_NO_WARNING (val) = 1; - val = build2 (COMPOUND_EXPR, type, val, to); - TREE_NO_WARNING (val) = 1; - } - else - val = build2 (INIT_EXPR, DECL_CONTEXT (fn), to, arg); + val = build2 (INIT_EXPR, DECL_CONTEXT (fn), to, arg); return val; } } diff --git a/gcc/gimplify.c b/gcc/gimplify.c index b46072506ee..8f7ff89d44c 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -4089,253 +4089,252 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, gimple_seq *pre_p, gimple_seq *post_p, bool want_value) { - enum gimplify_status ret = GS_OK; + enum gimplify_status ret = GS_UNHANDLED; + bool changed; - while (ret != GS_UNHANDLED) - switch (TREE_CODE (*from_p)) - { - case VAR_DECL: - /* If we're assigning from a read-only variable initialized with - a constructor, do the direct assignment from the constructor, - but only if neither source nor target are volatile since this - latter assignment might end up being done on a per-field basis. */ - if (DECL_INITIAL (*from_p) - && TREE_READONLY (*from_p) - && !TREE_THIS_VOLATILE (*from_p) - && !TREE_THIS_VOLATILE (*to_p) - && TREE_CODE (DECL_INITIAL (*from_p)) == CONSTRUCTOR) + do + { + changed = false; + switch (TREE_CODE (*from_p)) + { + case VAR_DECL: + /* If we're assigning from a read-only variable initialized with + a constructor, do the direct assignment from the constructor, + but only if neither source nor target are volatile since this + latter assignment might end up being done on a per-field basis. */ + if (DECL_INITIAL (*from_p) + && TREE_READONLY (*from_p) + && !TREE_THIS_VOLATILE (*from_p) + && !TREE_THIS_VOLATILE (*to_p) + && TREE_CODE (DECL_INITIAL (*from_p)) == CONSTRUCTOR) + { + tree old_from = *from_p; + enum gimplify_status subret; + + /* Move the constructor into the RHS. */ + *from_p = unshare_expr (DECL_INITIAL (*from_p)); + + /* Let's see if gimplify_init_constructor will need to put + it in memory. */ + subret = gimplify_init_constructor (expr_p, NULL, NULL, + false, true); + if (subret == GS_ERROR) + { + /* If so, revert the change. */ + *from_p = old_from; + } + else + { + ret = GS_OK; + changed = true; + } + } + break; + case INDIRECT_REF: { - tree old_from = *from_p; + /* If we have code like - /* Move the constructor into the RHS. */ - *from_p = unshare_expr (DECL_INITIAL (*from_p)); + *(const A*)(A*)&x - /* Let's see if gimplify_init_constructor will need to put - it in memory. If so, revert the change. */ - ret = gimplify_init_constructor (expr_p, NULL, NULL, false, true); - if (ret == GS_ERROR) + where the type of "x" is a (possibly cv-qualified variant + of "A"), treat the entire expression as identical to "x". + This kind of code arises in C++ when an object is bound + to a const reference, and if "x" is a TARGET_EXPR we want + to take advantage of the optimization below. */ + tree t = gimple_fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0)); + if (t) { - *from_p = old_from; - /* Fall through. */ + *from_p = t; + ret = GS_OK; + changed = true; } - else + break; + } + + case TARGET_EXPR: + { + /* If we are initializing something from a TARGET_EXPR, strip the + TARGET_EXPR and initialize it directly, if possible. This can't + be done if the initializer is void, since that implies that the + temporary is set in some non-trivial way. + + ??? What about code that pulls out the temp and uses it + elsewhere? I think that such code never uses the TARGET_EXPR as + an initializer. If I'm wrong, we'll die because the temp won't + have any RTL. In that case, I guess we'll need to replace + references somehow. */ + tree init = TARGET_EXPR_INITIAL (*from_p); + + if (init + && !VOID_TYPE_P (TREE_TYPE (init))) { + *from_p = init; ret = GS_OK; - break; + changed = true; } } - ret = GS_UNHANDLED; - break; - case INDIRECT_REF: - { - /* If we have code like + break; - *(const A*)(A*)&x + case COMPOUND_EXPR: + /* Remove any COMPOUND_EXPR in the RHS so the following cases will be + caught. */ + gimplify_compound_expr (from_p, pre_p, true); + ret = GS_OK; + changed = true; + break; - where the type of "x" is a (possibly cv-qualified variant - of "A"), treat the entire expression as identical to "x". - This kind of code arises in C++ when an object is bound - to a const reference, and if "x" is a TARGET_EXPR we want - to take advantage of the optimization below. */ - tree t = gimple_fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0)); - if (t) + case CONSTRUCTOR: + /* If we're initializing from a CONSTRUCTOR, break this into + individual MODIFY_EXPRs. */ + return gimplify_init_constructor (expr_p, pre_p, post_p, want_value, + false); + + case COND_EXPR: + /* If we're assigning to a non-register type, push the assignment + down into the branches. This is mandatory for ADDRESSABLE types, + since we cannot generate temporaries for such, but it saves a + copy in other cases as well. */ + if (!is_gimple_reg_type (TREE_TYPE (*from_p))) { - *from_p = t; - ret = GS_OK; + /* This code should mirror the code in gimplify_cond_expr. */ + enum tree_code code = TREE_CODE (*expr_p); + tree cond = *from_p; + tree result = *to_p; + + ret = gimplify_expr (&result, pre_p, post_p, + is_gimple_lvalue, fb_lvalue); + if (ret != GS_ERROR) + ret = GS_OK; + + if (TREE_TYPE (TREE_OPERAND (cond, 1)) != void_type_node) + TREE_OPERAND (cond, 1) + = build2 (code, void_type_node, result, + TREE_OPERAND (cond, 1)); + if (TREE_TYPE (TREE_OPERAND (cond, 2)) != void_type_node) + TREE_OPERAND (cond, 2) + = build2 (code, void_type_node, unshare_expr (result), + TREE_OPERAND (cond, 2)); + + TREE_TYPE (cond) = void_type_node; + recalculate_side_effects (cond); + + if (want_value) + { + gimplify_and_add (cond, pre_p); + *expr_p = unshare_expr (result); + } + else + *expr_p = cond; + return ret; } - else - ret = GS_UNHANDLED; break; - } - case TARGET_EXPR: - { - /* If we are initializing something from a TARGET_EXPR, strip the - TARGET_EXPR and initialize it directly, if possible. This can't - be done if the initializer is void, since that implies that the - temporary is set in some non-trivial way. - - ??? What about code that pulls out the temp and uses it - elsewhere? I think that such code never uses the TARGET_EXPR as - an initializer. If I'm wrong, we'll die because the temp won't - have any RTL. In that case, I guess we'll need to replace - references somehow. */ - tree init = TARGET_EXPR_INITIAL (*from_p); - - if (init - && !VOID_TYPE_P (TREE_TYPE (init))) + case CALL_EXPR: + /* For calls that return in memory, give *to_p as the CALL_EXPR's + return slot so that we don't generate a temporary. */ + if (!CALL_EXPR_RETURN_SLOT_OPT (*from_p) + && aggregate_value_p (*from_p, *from_p)) { - *from_p = init; - ret = GS_OK; + bool use_target; + + if (!(rhs_predicate_for (*to_p))(*from_p)) + /* If we need a temporary, *to_p isn't accurate. */ + use_target = false; + else if (TREE_CODE (*to_p) == RESULT_DECL + && DECL_NAME (*to_p) == NULL_TREE + && needs_to_live_in_memory (*to_p)) + /* It's OK to use the return slot directly unless it's an NRV. */ + use_target = true; + else if (is_gimple_reg_type (TREE_TYPE (*to_p)) + || (DECL_P (*to_p) && DECL_REGISTER (*to_p))) + /* Don't force regs into memory. */ + use_target = false; + else if (TREE_CODE (*expr_p) == INIT_EXPR) + /* It's OK to use the target directly if it's being + initialized. */ + use_target = true; + else if (!is_gimple_non_addressable (*to_p)) + /* Don't use the original target if it's already addressable; + if its address escapes, and the called function uses the + NRV optimization, a conforming program could see *to_p + change before the called function returns; see c++/19317. + When optimizing, the return_slot pass marks more functions + as safe after we have escape info. */ + use_target = false; + else + use_target = true; + + if (use_target) + { + CALL_EXPR_RETURN_SLOT_OPT (*from_p) = 1; + mark_addressable (*to_p); + } } - else - ret = GS_UNHANDLED; - } - break; + break; - case COMPOUND_EXPR: - /* Remove any COMPOUND_EXPR in the RHS so the following cases will be - caught. */ - gimplify_compound_expr (from_p, pre_p, true); - ret = GS_OK; - break; + case WITH_SIZE_EXPR: + /* Likewise for calls that return an aggregate of non-constant size, + since we would not be able to generate a temporary at all. */ + if (TREE_CODE (TREE_OPERAND (*from_p, 0)) == CALL_EXPR) + { + *from_p = TREE_OPERAND (*from_p, 0); + ret = GS_OK; + changed = true; + } + break; - case CONSTRUCTOR: - /* If we're initializing from a CONSTRUCTOR, break this into - individual MODIFY_EXPRs. */ - return gimplify_init_constructor (expr_p, pre_p, post_p, want_value, - false); - - case COND_EXPR: - /* If we're assigning to a non-register type, push the assignment - down into the branches. This is mandatory for ADDRESSABLE types, - since we cannot generate temporaries for such, but it saves a - copy in other cases as well. */ - if (!is_gimple_reg_type (TREE_TYPE (*from_p))) + /* If we're initializing from a container, push the initialization + inside it. */ + case CLEANUP_POINT_EXPR: + case BIND_EXPR: + case STATEMENT_LIST: { - /* This code should mirror the code in gimplify_cond_expr. */ - enum tree_code code = TREE_CODE (*expr_p); - tree cond = *from_p; - tree result = *to_p; + tree wrap = *from_p; + tree t; - ret = gimplify_expr (&result, pre_p, post_p, - is_gimple_lvalue, fb_lvalue); + ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_min_lval, + fb_lvalue); if (ret != GS_ERROR) ret = GS_OK; - if (TREE_TYPE (TREE_OPERAND (cond, 1)) != void_type_node) - TREE_OPERAND (cond, 1) - = build2 (code, void_type_node, result, - TREE_OPERAND (cond, 1)); - if (TREE_TYPE (TREE_OPERAND (cond, 2)) != void_type_node) - TREE_OPERAND (cond, 2) - = build2 (code, void_type_node, unshare_expr (result), - TREE_OPERAND (cond, 2)); - - TREE_TYPE (cond) = void_type_node; - recalculate_side_effects (cond); + t = voidify_wrapper_expr (wrap, *expr_p); + gcc_assert (t == *expr_p); if (want_value) { - gimplify_and_add (cond, pre_p); - *expr_p = unshare_expr (result); + gimplify_and_add (wrap, pre_p); + *expr_p = unshare_expr (*to_p); } else - *expr_p = cond; - return ret; + *expr_p = wrap; + return GS_OK; } - else - ret = GS_UNHANDLED; - break; - case CALL_EXPR: - /* For calls that return in memory, give *to_p as the CALL_EXPR's - return slot so that we don't generate a temporary. */ - if (!CALL_EXPR_RETURN_SLOT_OPT (*from_p) - && aggregate_value_p (*from_p, *from_p)) + case COMPOUND_LITERAL_EXPR: { - bool use_target; - - if (!(rhs_predicate_for (*to_p))(*from_p)) - /* If we need a temporary, *to_p isn't accurate. */ - use_target = false; - else if (TREE_CODE (*to_p) == RESULT_DECL - && DECL_NAME (*to_p) == NULL_TREE - && needs_to_live_in_memory (*to_p)) - /* It's OK to use the return slot directly unless it's an NRV. */ - use_target = true; - else if (is_gimple_reg_type (TREE_TYPE (*to_p)) - || (DECL_P (*to_p) && DECL_REGISTER (*to_p))) - /* Don't force regs into memory. */ - use_target = false; - else if (TREE_CODE (*expr_p) == INIT_EXPR) - /* It's OK to use the target directly if it's being - initialized. */ - use_target = true; - else if (!is_gimple_non_addressable (*to_p)) - /* Don't use the original target if it's already addressable; - if its address escapes, and the called function uses the - NRV optimization, a conforming program could see *to_p - change before the called function returns; see c++/19317. - When optimizing, the return_slot pass marks more functions - as safe after we have escape info. */ - use_target = false; - else - use_target = true; - - if (use_target) + tree complit = TREE_OPERAND (*expr_p, 1); + tree decl_s = COMPOUND_LITERAL_EXPR_DECL_EXPR (complit); + tree decl = DECL_EXPR_DECL (decl_s); + tree init = DECL_INITIAL (decl); + + /* struct T x = (struct T) { 0, 1, 2 } can be optimized + into struct T x = { 0, 1, 2 } if the address of the + compound literal has never been taken. */ + if (!TREE_ADDRESSABLE (complit) + && !TREE_ADDRESSABLE (decl) + && init) { - CALL_EXPR_RETURN_SLOT_OPT (*from_p) = 1; - mark_addressable (*to_p); + *expr_p = copy_node (*expr_p); + TREE_OPERAND (*expr_p, 1) = init; + return GS_OK; } } - ret = GS_UNHANDLED; - break; - - case WITH_SIZE_EXPR: - /* Likewise for calls that return an aggregate of non-constant size, - since we would not be able to generate a temporary at all. */ - if (TREE_CODE (TREE_OPERAND (*from_p, 0)) == CALL_EXPR) - { - *from_p = TREE_OPERAND (*from_p, 0); - ret = GS_OK; - } - else - ret = GS_UNHANDLED; - break; - - /* If we're initializing from a container, push the initialization - inside it. */ - case CLEANUP_POINT_EXPR: - case BIND_EXPR: - case STATEMENT_LIST: - { - tree wrap = *from_p; - tree t; - - ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_min_lval, - fb_lvalue); - if (ret != GS_ERROR) - ret = GS_OK; - - t = voidify_wrapper_expr (wrap, *expr_p); - gcc_assert (t == *expr_p); - - if (want_value) - { - gimplify_and_add (wrap, pre_p); - *expr_p = unshare_expr (*to_p); - } - else - *expr_p = wrap; - return GS_OK; - } - - case COMPOUND_LITERAL_EXPR: - { - tree complit = TREE_OPERAND (*expr_p, 1); - tree decl_s = COMPOUND_LITERAL_EXPR_DECL_EXPR (complit); - tree decl = DECL_EXPR_DECL (decl_s); - tree init = DECL_INITIAL (decl); - - /* struct T x = (struct T) { 0, 1, 2 } can be optimized - into struct T x = { 0, 1, 2 } if the address of the - compound literal has never been taken. */ - if (!TREE_ADDRESSABLE (complit) - && !TREE_ADDRESSABLE (decl) - && init) - { - *expr_p = copy_node (*expr_p); - TREE_OPERAND (*expr_p, 1) = init; - return GS_OK; - } + default: + break; } - - default: - ret = GS_UNHANDLED; - break; - } + } + while (changed); return ret; } @@ -6616,8 +6615,16 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, case MODIFY_EXPR: case INIT_EXPR: - ret = gimplify_modify_expr (expr_p, pre_p, post_p, - fallback != fb_none); + { + tree from = TREE_OPERAND (*expr_p, 1); + ret = gimplify_modify_expr (expr_p, pre_p, post_p, + fallback != fb_none); + /* Don't let the end of loop logic change GS_OK into GS_ALL_DONE + if the RHS has changed. */ + if (ret == GS_OK && *expr_p == save_expr + && TREE_OPERAND (*expr_p, 1) != from) + continue; + } break; case TRUTH_ANDIF_EXPR: diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5c068902b8a..ebba7731f1c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2010-05-05 Jason Merrill + + PR c++/43787 + * g++.dg/opt/empty1.C: New. + 2010-05-05 Janus Weil PR fortran/43696 -- 2.11.0