Commit dae7ec87 by Jason Merrill Committed by Jason Merrill

re PR c++/25979 (incorrect codegen for conditional [SVO issue])

        PR c++/25979
        * tree.def: Elaborate on difference from MODIFY_EXPR.
        * doc/c-tree.texi (INIT_EXPR): Likewise.
        * gimplify.c (internal_get_tmp_var): Use INIT_EXPR.
        (gimplify_decl_expr, gimplify_init_ctor_eval): Likewise.
        (gimplify_target_expr): Likewise.
        (gimplify_cond_expr): Remove target handling.
        (gimplify_modify_expr): Don't clobber INIT_EXPR code here.
        (gimplify_expr): Clobber it here.
        (gimplify_modify_expr_rhs): Push assignment into COND_EXPR here.
        Do return slot optimization if we have an INIT_EXPR.

        PR tree-opt/24365
        * tree-inline.c (declare_return_variable): Also clear
        DECL_COMPLEX_GIMPLE_REG_P as needed in the modify_dest case.

        PR c++/16405
        * gimplify.c (gimplify_modify_expr_rhs): Re-enable *& handling.

        PR middle-end/22439
        * gimplify.c (gimplify_one_sizepos): Fix typo.

From-SVN: r110789
parent 845d2a4b
2006-02-08 Jason Merrill <jason@redhat.com>
PR c++/25979
* tree.def: Elaborate on difference from MODIFY_EXPR.
* doc/c-tree.texi (INIT_EXPR): Likewise.
* gimplify.c (internal_get_tmp_var): Use INIT_EXPR.
(gimplify_decl_expr, gimplify_init_ctor_eval): Likewise.
(gimplify_target_expr): Likewise.
(gimplify_cond_expr): Remove target handling.
(gimplify_modify_expr): Don't clobber INIT_EXPR code here.
(gimplify_expr): Clobber it here.
(gimplify_modify_expr_rhs): Push assignment into COND_EXPR here.
Do return slot optimization if we have an INIT_EXPR.
PR tree-opt/24365
* tree-inline.c (declare_return_variable): Also clear
DECL_COMPLEX_GIMPLE_REG_P as needed in the modify_dest case.
PR c++/16405
* gimplify.c (gimplify_modify_expr_rhs): Re-enable *& handling.
PR middle-end/22439
* gimplify.c (gimplify_one_sizepos): Fix typo.
2006-02-08 Jeff Law <law@redhat.com>
PR tree-optimization/21417
......
2006-02-08 Jason Merrill <jason@redhat.com>
PR c++/25979
* cp-gimplify.c (cp_gimplify_expr): Don't call
cp_gimplify_init_expr for MODIFY_EXPRs.
* typeck2.c (split_nonconstant_init_1): Use INIT_EXPR.
2006-02-08 Volker Reichelt <reichelt@igpm.rwth-aachen.de>
PR c++/26071
......
......@@ -477,8 +477,10 @@ cp_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p)
ret = GS_OK;
break;
/* We used to do this for MODIFY_EXPR as well, but that's unsafe; the
LHS of an assignment might also be involved in the RHS, as in bug
25979. */
case INIT_EXPR:
case MODIFY_EXPR:
cp_gimplify_init_expr (expr_p, pre_p, post_p);
ret = GS_OK;
break;
......
......@@ -502,7 +502,7 @@ split_nonconstant_init_1 (tree dest, tree init)
sub = build3 (COMPONENT_REF, inner_type, dest, field_index,
NULL_TREE);
code = build2 (MODIFY_EXPR, inner_type, sub, value);
code = build2 (INIT_EXPR, inner_type, sub, value);
code = build_stmt (EXPR_STMT, code);
add_stmt (code);
continue;
......
......@@ -2350,7 +2350,10 @@ just like that for @samp{i = i + 3}.
@item INIT_EXPR
These nodes are just like @code{MODIFY_EXPR}, but are used only when a
variable is initialized, rather than assigned to subsequently.
variable is initialized, rather than assigned to subsequently. This
means that we can assume that the target of the initialization is not
used in computing its own value; any reference to the lhs in computing
the rhs is undefined.
@item COMPONENT_REF
These nodes represent non-static data member accesses. The first
......
......@@ -606,7 +606,7 @@ internal_get_tmp_var (tree val, tree *pre_p, tree *post_p, bool is_formal)
if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE)
DECL_COMPLEX_GIMPLE_REG_P (t) = 1;
mod = build2 (MODIFY_EXPR, TREE_TYPE (t), t, val);
mod = build2 (INIT_EXPR, TREE_TYPE (t), t, val);
if (EXPR_HAS_LOCATION (val))
SET_EXPR_LOCUS (mod, EXPR_LOCUS (val));
......@@ -1204,7 +1204,7 @@ gimplify_decl_expr (tree *stmt_p)
if (!TREE_STATIC (decl))
{
DECL_INITIAL (decl) = NULL_TREE;
init = build2 (MODIFY_EXPR, void_type_node, decl, init);
init = build2 (INIT_EXPR, void_type_node, decl, init);
gimplify_and_add (init, stmt_p);
}
else
......@@ -2341,14 +2341,10 @@ gimple_boolify (tree expr)
TARGET is the tree for T1 above.
PRE_P points to the list where side effects that must happen before
*EXPR_P should be stored.
POST_P points to the list where side effects that must happen after
*EXPR_P should be stored. */
*EXPR_P should be stored. */
static enum gimplify_status
gimplify_cond_expr (tree *expr_p, tree *pre_p, tree *post_p, tree target,
fallback_t fallback)
gimplify_cond_expr (tree *expr_p, tree *pre_p, fallback_t fallback)
{
tree expr = *expr_p;
tree tmp, tmp2, type;
......@@ -2362,16 +2358,7 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, tree *post_p, tree target,
{
tree result;
if (target)
{
ret = gimplify_expr (&target, pre_p, post_p,
is_gimple_min_lval, fb_lvalue);
if (ret != GS_ERROR)
ret = GS_OK;
result = tmp = target;
tmp2 = unshare_expr (target);
}
else if ((fallback & fb_lvalue) == 0)
if ((fallback & fb_lvalue) == 0)
{
result = tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
ret = GS_ALL_DONE;
......@@ -2836,7 +2823,7 @@ gimplify_init_ctor_eval (tree object, VEC(constructor_elt,gc) *elts,
pre_p, cleared);
else
{
init = build2 (MODIFY_EXPR, TREE_TYPE (cref), cref, value);
init = build2 (INIT_EXPR, TREE_TYPE (cref), cref, value);
gimplify_and_add (init, pre_p);
}
}
......@@ -3190,7 +3177,6 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
while (ret != GS_UNHANDLED)
switch (TREE_CODE (*from_p))
{
#if 0
case INDIRECT_REF:
{
/* If we have code like
......@@ -3212,7 +3198,6 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
ret = GS_UNHANDLED;
break;
}
#endif
case TARGET_EXPR:
{
......@@ -3257,9 +3242,36 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
copy in other cases as well. */
if (!is_gimple_reg_type (TREE_TYPE (*from_p)))
{
*expr_p = *from_p;
return gimplify_cond_expr (expr_p, pre_p, post_p, *to_p,
fb_rvalue);
/* 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_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);
if (want_value)
{
gimplify_and_add (cond, pre_p);
*expr_p = unshare_expr (result);
}
else
*expr_p = cond;
return ret;
}
else
ret = GS_UNHANDLED;
......@@ -3273,11 +3285,26 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
{
bool use_target;
if (TREE_CODE (*to_p) == RESULT_DECL
&& DECL_NAME (*to_p) == NULL_TREE
&& needs_to_live_in_memory (*to_p))
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)))
/* Don't force regs into memory. */
use_target = false;
else if (TREE_CODE (*to_p) == VAR_DECL
&& DECL_GIMPLE_FORMAL_TEMP_P (*to_p))
/* Don't use the original target if it's a formal temp; we
don't want to take their addresses. */
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
......@@ -3286,14 +3313,6 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
When optimizing, the return_slot pass marks more functions
as safe after we have escape info. */
use_target = false;
else if (TREE_CODE (*to_p) != PARM_DECL
&& DECL_GIMPLE_FORMAL_TEMP_P (*to_p))
/* Don't use the original target if it's a formal temp; we
don't want to take their addresses. */
use_target = false;
else if (is_gimple_reg_type (TREE_TYPE (*to_p)))
/* Also don't force regs into memory. */
use_target = false;
else
use_target = true;
......@@ -3379,10 +3398,6 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
gcc_assert (TREE_CODE (*expr_p) == MODIFY_EXPR
|| TREE_CODE (*expr_p) == INIT_EXPR);
/* The distinction between MODIFY_EXPR and INIT_EXPR is no longer useful. */
if (TREE_CODE (*expr_p) == INIT_EXPR)
TREE_SET_CODE (*expr_p, MODIFY_EXPR);
/* For zero sized types only gimplify the left hand side and right hand side
as statements and throw away the assignment. */
if (zero_sized_type (TREE_TYPE (*from_p)))
......@@ -4072,7 +4087,7 @@ gimplify_target_expr (tree *expr_p, tree *pre_p, tree *post_p)
gimplify_bind_expr (&init, temp, pre_p);
if (init != temp)
{
init = build2 (MODIFY_EXPR, void_type_node, temp, init);
init = build2 (INIT_EXPR, void_type_node, temp, init);
ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt,
fb_none);
}
......@@ -5216,8 +5231,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
break;
case COND_EXPR:
ret = gimplify_cond_expr (expr_p, pre_p, post_p, NULL_TREE,
fallback);
ret = gimplify_cond_expr (expr_p, pre_p, fallback);
/* C99 code may assign to an array in a structure value of a
conditional expression, and this has undefined behavior
only on execution, so create a temporary if an lvalue is
......@@ -5253,6 +5267,11 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
case INIT_EXPR:
ret = gimplify_modify_expr (expr_p, pre_p, post_p,
fallback != fb_none);
/* The distinction between MODIFY_EXPR and INIT_EXPR is no longer
useful. */
if (*expr_p && TREE_CODE (*expr_p) == INIT_EXPR)
TREE_SET_CODE (*expr_p, MODIFY_EXPR);
break;
case TRUTH_ANDIF_EXPR:
......@@ -5889,7 +5908,7 @@ gimplify_one_sizepos (tree *expr_p, tree *stmt_p)
*expr_p = create_tmp_var (type, NULL);
tmp = build1 (NOP_EXPR, type, expr);
tmp = build2 (MODIFY_EXPR, type, *expr_p, expr);
tmp = build2 (MODIFY_EXPR, type, *expr_p, tmp);
if (EXPR_HAS_LOCATION (expr))
SET_EXPR_LOCUS (tmp, EXPR_LOCUS (expr));
else
......
// PR c++/16405
// { dg-options "-O2" }
// { dg-do run { xfail *-*-* } }
// { dg-do run }
// There should be exactly one temporary generated for the code in "f"
// below when optimizing -- for the result of "b + c". We have no
......
......@@ -1222,6 +1222,9 @@ declare_return_variable (copy_body_data *id, tree return_slot_addr,
use_it = false;
else if (is_global_var (base_m))
use_it = false;
else if (TREE_CODE (TREE_TYPE (base_m)) == COMPLEX_TYPE
&& !DECL_COMPLEX_GIMPLE_REG_P (result))
DECL_COMPLEX_GIMPLE_REG_P (base_m) = 0;
else if (!TREE_ADDRESSABLE (base_m))
use_it = true;
}
......
......@@ -465,7 +465,8 @@ DEFTREECODE (COMPOUND_EXPR, "compound_expr", tcc_expression, 2)
DEFTREECODE (MODIFY_EXPR, "modify_expr", tcc_expression, 2)
/* Initialization expression. Operand 0 is the variable to initialize;
Operand 1 is the initializer. */
Operand 1 is the initializer. This differs from MODIFY_EXPR in that any
reference to the referent of operand 0 within operand 1 is undefined. */
DEFTREECODE (INIT_EXPR, "init_expr", tcc_expression, 2)
/* For TARGET_EXPR, operand 0 is the target of an initialization,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment