gimple-low.c (struct lower_data): Replace the_return_label and one_return_stmt with return_statements.
* gimple-low.c (struct lower_data): Replace the_return_label and one_return_stmt with return_statements. (lower_function_body): Process the entire list of return_statements. (lower_return_expr): Check source value before unifying return_exprs. * gimplify.c (gimplify_return_expr): Force the use of a temporary for !aggregate_value_p. * tree-gimple.c: Update RETURN_EXPR grammer. From-SVN: r82768
This commit is contained in:
parent
de101ad2f7
commit
7187798577
|
@ -1,3 +1,13 @@
|
|||
2004-06-08 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* gimple-low.c (struct lower_data): Replace the_return_label and
|
||||
one_return_stmt with return_statements.
|
||||
(lower_function_body): Process the entire list of return_statements.
|
||||
(lower_return_expr): Check source value before unifying return_exprs.
|
||||
* gimplify.c (gimplify_return_expr): Force the use of a temporary
|
||||
for !aggregate_value_p.
|
||||
* tree-gimple.c: Update RETURN_EXPR grammer.
|
||||
|
||||
2004-06-08 Vladimir Makarov <vmakarov@redhat.com>
|
||||
|
||||
PR target/15598
|
||||
|
|
|
@ -47,9 +47,9 @@ struct lower_data
|
|||
/* Block the current statement belongs to. */
|
||||
tree block;
|
||||
|
||||
/* Label that unifies the return statements. */
|
||||
tree the_return_label;
|
||||
tree one_return_stmt;
|
||||
/* A TREE_LIST of label and return statements to be moved to the end
|
||||
of the function. */
|
||||
tree return_statements;
|
||||
};
|
||||
|
||||
static void lower_stmt (tree_stmt_iterator *, struct lower_data *);
|
||||
|
@ -76,8 +76,7 @@ lower_function_body (void)
|
|||
BLOCK_CHAIN (data.block) = NULL_TREE;
|
||||
TREE_ASM_WRITTEN (data.block) = 1;
|
||||
|
||||
data.the_return_label = NULL_TREE;
|
||||
data.one_return_stmt = NULL_TREE;
|
||||
data.return_statements = NULL_TREE;
|
||||
|
||||
*body_p = alloc_stmt_list ();
|
||||
i = tsi_start (*body_p);
|
||||
|
@ -86,13 +85,23 @@ lower_function_body (void)
|
|||
|
||||
/* If we lowered any return statements, emit the representative at the
|
||||
end of the function. */
|
||||
if (data.one_return_stmt)
|
||||
if (data.return_statements)
|
||||
{
|
||||
tree t;
|
||||
t = build (LABEL_EXPR, void_type_node, data.the_return_label);
|
||||
tree t, x;
|
||||
i = tsi_last (*body_p);
|
||||
tsi_link_after (&i, t, TSI_CONTINUE_LINKING);
|
||||
tsi_link_after (&i, data.one_return_stmt, TSI_CONTINUE_LINKING);
|
||||
|
||||
for (t = data.return_statements; t ; t = TREE_CHAIN (t))
|
||||
{
|
||||
x = build (LABEL_EXPR, void_type_node, TREE_PURPOSE (t));
|
||||
tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
|
||||
|
||||
/* Remove the line number from the representative return statement.
|
||||
It now fills in for many such returns. Failure to remove this
|
||||
will result in incorrect results for coverage analysis. */
|
||||
x = TREE_VALUE (t);
|
||||
SET_EXPR_LOCUS (x, NULL);
|
||||
tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
|
||||
}
|
||||
}
|
||||
|
||||
if (data.block != DECL_INITIAL (current_function_decl))
|
||||
|
@ -392,16 +401,37 @@ lower_cond_expr (tree_stmt_iterator *tsi, struct lower_data *data)
|
|||
static void
|
||||
lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data)
|
||||
{
|
||||
tree stmt, label = data->the_return_label;
|
||||
tree stmt = tsi_stmt (*tsi);
|
||||
tree value, t, label;
|
||||
|
||||
if (!label)
|
||||
/* Extract the value being returned. */
|
||||
value = TREE_OPERAND (stmt, 0);
|
||||
if (value && TREE_CODE (value) == MODIFY_EXPR)
|
||||
value = TREE_OPERAND (value, 1);
|
||||
|
||||
/* Match this up with an existing return statement that's been created. */
|
||||
for (t = data->return_statements; t ; t = TREE_CHAIN (t))
|
||||
{
|
||||
data->the_return_label = label = create_artificial_label ();
|
||||
data->one_return_stmt = tsi_stmt (*tsi);
|
||||
tree tvalue = TREE_OPERAND (TREE_VALUE (t), 0);
|
||||
if (tvalue && TREE_CODE (tvalue) == MODIFY_EXPR)
|
||||
tvalue = TREE_OPERAND (tvalue, 1);
|
||||
|
||||
if (value == tvalue)
|
||||
{
|
||||
label = TREE_PURPOSE (t);
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
stmt = build (GOTO_EXPR, void_type_node, label);
|
||||
tsi_link_before (tsi, stmt, TSI_SAME_STMT);
|
||||
/* Not found. Create a new label and record the return statement. */
|
||||
label = create_artificial_label ();
|
||||
data->return_statements = tree_cons (label, stmt, data->return_statements);
|
||||
|
||||
/* Generate a goto statement and remove the return statement. */
|
||||
found:
|
||||
t = build (GOTO_EXPR, void_type_node, label);
|
||||
SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
|
||||
tsi_link_before (tsi, t, TSI_SAME_STMT);
|
||||
tsi_delink (tsi);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ static struct gimplify_ctx
|
|||
tree conditional_cleanups;
|
||||
int conditions;
|
||||
tree exit_label;
|
||||
tree return_temp;
|
||||
varray_type case_labels;
|
||||
/* The formal temporary table. Should this be persistent? */
|
||||
htab_t temp_htab;
|
||||
|
@ -888,7 +889,7 @@ static enum gimplify_status
|
|||
gimplify_return_expr (tree stmt, tree *pre_p)
|
||||
{
|
||||
tree ret_expr = TREE_OPERAND (stmt, 0);
|
||||
tree result;
|
||||
tree result_decl, result;
|
||||
|
||||
if (!ret_expr || TREE_CODE (ret_expr) == RESULT_DECL)
|
||||
return GS_ALL_DONE;
|
||||
|
@ -897,24 +898,51 @@ gimplify_return_expr (tree stmt, tree *pre_p)
|
|||
return GS_ERROR;
|
||||
|
||||
if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
|
||||
result = NULL_TREE;
|
||||
result_decl = NULL_TREE;
|
||||
else
|
||||
{
|
||||
result = TREE_OPERAND (ret_expr, 0);
|
||||
result_decl = TREE_OPERAND (ret_expr, 0);
|
||||
#ifdef ENABLE_CHECKING
|
||||
if ((TREE_CODE (ret_expr) != MODIFY_EXPR
|
||||
&& TREE_CODE (ret_expr) != INIT_EXPR)
|
||||
|| TREE_CODE (result) != RESULT_DECL)
|
||||
|| TREE_CODE (result_decl) != RESULT_DECL)
|
||||
abort ();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* We need to pass the full MODIFY_EXPR down so that special handling
|
||||
can replace it with something else. */
|
||||
/* If aggregate_value_p is true, then we can return the bare RESULT_DECL.
|
||||
Recall that aggregate_value_p is FALSE for any aggregate type that is
|
||||
returned in registers. If we're returning values in registers, then
|
||||
we don't want to extend the lifetime of the RESULT_DECL, particularly
|
||||
across another call. In addition, for those aggregates for which
|
||||
hard_function_value generates a PARALLEL, we'll abort during normal
|
||||
expansion of structure assignments; there's special code in expand_return
|
||||
to handle this case that does not exist in expand_expr. */
|
||||
if (!result_decl
|
||||
|| aggregate_value_p (result_decl, TREE_TYPE (current_function_decl)))
|
||||
result = result_decl;
|
||||
else if (gimplify_ctxp->return_temp)
|
||||
result = gimplify_ctxp->return_temp;
|
||||
else
|
||||
{
|
||||
result = create_tmp_var (TREE_TYPE (result_decl), NULL);
|
||||
gimplify_ctxp->return_temp = result;
|
||||
}
|
||||
|
||||
/* Smash the lhs of the MODIFY_EXPR to the temporary we plan to use.
|
||||
Then gimplify the whole thing. */
|
||||
if (result != result_decl)
|
||||
TREE_OPERAND (ret_expr, 0) = result;
|
||||
gimplify_stmt (&TREE_OPERAND (stmt, 0));
|
||||
append_to_statement_list (TREE_OPERAND (stmt, 0), pre_p);
|
||||
|
||||
TREE_OPERAND (stmt, 0) = result;
|
||||
/* If we didn't use a temporary, then the result is just the result_decl.
|
||||
Otherwise we need a simple copy. This should already be gimple. */
|
||||
if (result == result_decl)
|
||||
ret_expr = result;
|
||||
else
|
||||
ret_expr = build (MODIFY_EXPR, TREE_TYPE (result), result_decl, result);
|
||||
TREE_OPERAND (stmt, 0) = ret_expr;
|
||||
|
||||
return GS_ALL_DONE;
|
||||
}
|
||||
|
|
|
@ -79,7 +79,9 @@ Boston, MA 02111-1307, USA. */
|
|||
GOTO_EXPR
|
||||
op0 -> LABEL_DECL | '*' ID
|
||||
| RETURN_EXPR
|
||||
op0 -> RESULT_DECL | NULL_TREE
|
||||
op0 -> NULL_TREE
|
||||
| RESULT_DECL
|
||||
| MODIFY_EXPR -> RESULT_DECL, varname
|
||||
| THROW_EXPR? do we need/want such a thing for opts, perhaps
|
||||
to generate an ERT_THROW region? I think so.
|
||||
Hmm...this would only work at the GIMPLE level, where we know that
|
||||
|
|
Loading…
Reference in New Issue