Commit 71877985 by Richard Henderson Committed by Richard Henderson

gimple-low.c (struct lower_data): Replace the_return_label and one_return_stmt…

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
parent de101ad2
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> 2004-06-08 Vladimir Makarov <vmakarov@redhat.com>
PR target/15598 PR target/15598
......
...@@ -47,9 +47,9 @@ struct lower_data ...@@ -47,9 +47,9 @@ struct lower_data
/* Block the current statement belongs to. */ /* Block the current statement belongs to. */
tree block; tree block;
/* Label that unifies the return statements. */ /* A TREE_LIST of label and return statements to be moved to the end
tree the_return_label; of the function. */
tree one_return_stmt; tree return_statements;
}; };
static void lower_stmt (tree_stmt_iterator *, struct lower_data *); static void lower_stmt (tree_stmt_iterator *, struct lower_data *);
...@@ -76,8 +76,7 @@ lower_function_body (void) ...@@ -76,8 +76,7 @@ lower_function_body (void)
BLOCK_CHAIN (data.block) = NULL_TREE; BLOCK_CHAIN (data.block) = NULL_TREE;
TREE_ASM_WRITTEN (data.block) = 1; TREE_ASM_WRITTEN (data.block) = 1;
data.the_return_label = NULL_TREE; data.return_statements = NULL_TREE;
data.one_return_stmt = NULL_TREE;
*body_p = alloc_stmt_list (); *body_p = alloc_stmt_list ();
i = tsi_start (*body_p); i = tsi_start (*body_p);
...@@ -86,13 +85,23 @@ lower_function_body (void) ...@@ -86,13 +85,23 @@ lower_function_body (void)
/* If we lowered any return statements, emit the representative at the /* If we lowered any return statements, emit the representative at the
end of the function. */ end of the function. */
if (data.one_return_stmt) if (data.return_statements)
{ {
tree t; tree t, x;
t = build (LABEL_EXPR, void_type_node, data.the_return_label);
i = tsi_last (*body_p); 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)) if (data.block != DECL_INITIAL (current_function_decl))
...@@ -392,16 +401,37 @@ lower_cond_expr (tree_stmt_iterator *tsi, struct lower_data *data) ...@@ -392,16 +401,37 @@ lower_cond_expr (tree_stmt_iterator *tsi, struct lower_data *data)
static void static void
lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data) 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;
/* Extract the value being returned. */
value = TREE_OPERAND (stmt, 0);
if (value && TREE_CODE (value) == MODIFY_EXPR)
value = TREE_OPERAND (value, 1);
if (!label) /* 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 (); tree tvalue = TREE_OPERAND (TREE_VALUE (t), 0);
data->one_return_stmt = tsi_stmt (*tsi); 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); /* Not found. Create a new label and record the return statement. */
tsi_link_before (tsi, stmt, TSI_SAME_STMT); 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); tsi_delink (tsi);
} }
......
...@@ -54,6 +54,7 @@ static struct gimplify_ctx ...@@ -54,6 +54,7 @@ static struct gimplify_ctx
tree conditional_cleanups; tree conditional_cleanups;
int conditions; int conditions;
tree exit_label; tree exit_label;
tree return_temp;
varray_type case_labels; varray_type case_labels;
/* The formal temporary table. Should this be persistent? */ /* The formal temporary table. Should this be persistent? */
htab_t temp_htab; htab_t temp_htab;
...@@ -888,7 +889,7 @@ static enum gimplify_status ...@@ -888,7 +889,7 @@ static enum gimplify_status
gimplify_return_expr (tree stmt, tree *pre_p) gimplify_return_expr (tree stmt, tree *pre_p)
{ {
tree ret_expr = TREE_OPERAND (stmt, 0); tree ret_expr = TREE_OPERAND (stmt, 0);
tree result; tree result_decl, result;
if (!ret_expr || TREE_CODE (ret_expr) == RESULT_DECL) if (!ret_expr || TREE_CODE (ret_expr) == RESULT_DECL)
return GS_ALL_DONE; return GS_ALL_DONE;
...@@ -897,24 +898,51 @@ gimplify_return_expr (tree stmt, tree *pre_p) ...@@ -897,24 +898,51 @@ gimplify_return_expr (tree stmt, tree *pre_p)
return GS_ERROR; return GS_ERROR;
if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))) if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
result = NULL_TREE; result_decl = NULL_TREE;
else else
{ {
result = TREE_OPERAND (ret_expr, 0); result_decl = TREE_OPERAND (ret_expr, 0);
#ifdef ENABLE_CHECKING #ifdef ENABLE_CHECKING
if ((TREE_CODE (ret_expr) != MODIFY_EXPR if ((TREE_CODE (ret_expr) != MODIFY_EXPR
&& TREE_CODE (ret_expr) != INIT_EXPR) && TREE_CODE (ret_expr) != INIT_EXPR)
|| TREE_CODE (result) != RESULT_DECL) || TREE_CODE (result_decl) != RESULT_DECL)
abort (); abort ();
#endif #endif
} }
/* We need to pass the full MODIFY_EXPR down so that special handling /* If aggregate_value_p is true, then we can return the bare RESULT_DECL.
can replace it with something else. */ 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)); gimplify_stmt (&TREE_OPERAND (stmt, 0));
append_to_statement_list (TREE_OPERAND (stmt, 0), pre_p); 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; return GS_ALL_DONE;
} }
......
...@@ -79,7 +79,9 @@ Boston, MA 02111-1307, USA. */ ...@@ -79,7 +79,9 @@ Boston, MA 02111-1307, USA. */
GOTO_EXPR GOTO_EXPR
op0 -> LABEL_DECL | '*' ID op0 -> LABEL_DECL | '*' ID
| RETURN_EXPR | 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 | THROW_EXPR? do we need/want such a thing for opts, perhaps
to generate an ERT_THROW region? I think so. to generate an ERT_THROW region? I think so.
Hmm...this would only work at the GIMPLE level, where we know that Hmm...this would only work at the GIMPLE level, where we know that
......
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