This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: simplify the argument of return_expr
On Mon, Jun 07, 2004 at 03:38:45PM -0400, Jason Merrill wrote:
> My mistake, the new box I was testing on is actually x86_64.
Testing the following on amd64-linux. It cures the problem in
the .i file provided by Jason.
r~
* 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.
Index: gimple-low.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimple-low.c,v
retrieving revision 2.3
diff -c -p -d -r2.3 gimple-low.c
*** gimple-low.c 7 Jun 2004 17:53:02 -0000 2.3
--- gimple-low.c 7 Jun 2004 21:26:51 -0000
*************** struct lower_data
*** 47,55 ****
/* Block the current statement belongs to. */
tree block;
! /* Label that unifies the return statements. */
! tree the_return_label;
! tree one_return_stmt;
};
static void lower_stmt (tree_stmt_iterator *, struct lower_data *);
--- 47,55 ----
/* Block the current statement belongs to. */
tree block;
! /* 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 *);
*************** lower_function_body (void)
*** 76,83 ****
BLOCK_CHAIN (data.block) = NULL_TREE;
TREE_ASM_WRITTEN (data.block) = 1;
! data.the_return_label = NULL_TREE;
! data.one_return_stmt = NULL_TREE;
*body_p = alloc_stmt_list ();
i = tsi_start (*body_p);
--- 76,82 ----
BLOCK_CHAIN (data.block) = NULL_TREE;
TREE_ASM_WRITTEN (data.block) = 1;
! data.return_statements = NULL_TREE;
*body_p = alloc_stmt_list ();
i = tsi_start (*body_p);
*************** lower_function_body (void)
*** 86,98 ****
/* If we lowered any return statements, emit the representative at the
end of the function. */
! if (data.one_return_stmt)
{
! tree t;
! t = build (LABEL_EXPR, void_type_node, data.the_return_label);
i = tsi_last (*body_p);
! tsi_link_after (&i, t, TSI_CONTINUE_LINKING);
! tsi_link_after (&i, data.one_return_stmt, TSI_CONTINUE_LINKING);
}
if (data.block != DECL_INITIAL (current_function_decl))
--- 85,107 ----
/* If we lowered any return statements, emit the representative at the
end of the function. */
! if (data.return_statements)
{
! tree t, x;
i = tsi_last (*body_p);
!
! 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))
*************** lower_cond_expr (tree_stmt_iterator *tsi
*** 392,407 ****
static void
lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data)
{
! tree stmt, label = data->the_return_label;
! if (!label)
{
! data->the_return_label = label = create_artificial_label ();
! data->one_return_stmt = tsi_stmt (*tsi);
}
! stmt = build (GOTO_EXPR, void_type_node, label);
! tsi_link_before (tsi, stmt, TSI_SAME_STMT);
tsi_delink (tsi);
}
--- 401,437 ----
static void
lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data)
{
! 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);
!
! /* Match this up with an existing return statement that's been created. */
! for (t = data->return_statements; t ; t = TREE_CHAIN (t))
{
! 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;
! }
}
! /* 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);
}
Index: gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.11
diff -c -p -d -r2.11 gimplify.c
*** gimplify.c 7 Jun 2004 17:53:02 -0000 2.11
--- gimplify.c 7 Jun 2004 21:26:51 -0000
*************** static struct gimplify_ctx
*** 54,59 ****
--- 54,60 ----
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;
*************** static enum gimplify_status
*** 876,882 ****
gimplify_return_expr (tree stmt, tree *pre_p)
{
tree ret_expr = TREE_OPERAND (stmt, 0);
! tree result;
if (!ret_expr || TREE_CODE (ret_expr) == RESULT_DECL)
return GS_ALL_DONE;
--- 877,883 ----
gimplify_return_expr (tree stmt, tree *pre_p)
{
tree ret_expr = TREE_OPERAND (stmt, 0);
! tree result_decl, result;
if (!ret_expr || TREE_CODE (ret_expr) == RESULT_DECL)
return GS_ALL_DONE;
*************** gimplify_return_expr (tree stmt, tree *p
*** 885,908 ****
return GS_ERROR;
if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
! result = NULL_TREE;
else
{
! result = 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)
abort ();
#endif
}
! /* We need to pass the full MODIFY_EXPR down so that special handling
! can replace it with something else. */
gimplify_stmt (&TREE_OPERAND (stmt, 0));
append_to_statement_list (TREE_OPERAND (stmt, 0), pre_p);
! TREE_OPERAND (stmt, 0) = result;
return GS_ALL_DONE;
}
--- 886,936 ----
return GS_ERROR;
if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
! result_decl = NULL_TREE;
else
{
! 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_decl) != RESULT_DECL)
abort ();
#endif
}
! /* 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);
! /* 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;
}
Index: tree-gimple.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-gimple.c,v
retrieving revision 2.4
diff -c -p -d -r2.4 tree-gimple.c
*** tree-gimple.c 7 Jun 2004 17:53:02 -0000 2.4
--- tree-gimple.c 7 Jun 2004 21:26:51 -0000
*************** Boston, MA 02111-1307, USA. */
*** 79,85 ****
GOTO_EXPR
op0 -> LABEL_DECL | '*' ID
| RETURN_EXPR
! op0 -> RESULT_DECL | NULL_TREE
| 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
--- 79,87 ----
GOTO_EXPR
op0 -> LABEL_DECL | '*' ID
| RETURN_EXPR
! 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