Make return in memory explicit.
* function.c (aggregate_value_p): Check DECL_BY_REFERENCE. (assign_parm_find_data_types): Remove code for old front end invisible reference handling. (assign_parms): Handle DECL_BY_REFERENCE on the RESULT_DECL. (expand_function_end): Likewise. * gimplify.c (gimplify_return_expr): Handle a dereferenced RESULT_DECL. * tree-inline.c (copy_body_r): Don't bother looking for &* anymore. (declare_return_variable): Handle DECL_BY_REFERENCE. * cp/cp-gimplify.c (is_invisiref_parm): Also handle RESULT_DECL. (cp_genericize_r): Use convert_from_reference. Don't dereference a RESULT_DECL directly inside a RETURN_EXPR. (cp_genericize): Handle the RESULT_DECL. Unset TREE_ADDRESSABLE. From-SVN: r85675
This commit is contained in:
parent
0737fbff59
commit
cc77ae108d
5 changed files with 68 additions and 52 deletions
|
@ -14,6 +14,21 @@
|
|||
|
||||
2004-08-07 Jason Merrill <jason@redhat.com>
|
||||
|
||||
Make return in memory explicit.
|
||||
* function.c (aggregate_value_p): Check DECL_BY_REFERENCE.
|
||||
(assign_parm_find_data_types): Remove code for old front end
|
||||
invisible reference handling.
|
||||
(assign_parms): Handle DECL_BY_REFERENCE on the RESULT_DECL.
|
||||
(expand_function_end): Likewise.
|
||||
* gimplify.c (gimplify_return_expr): Handle a dereferenced
|
||||
RESULT_DECL.
|
||||
* tree-inline.c (copy_body_r): Don't bother looking for &* anymore.
|
||||
(declare_return_variable): Handle DECL_BY_REFERENCE.
|
||||
* cp/cp-gimplify.c (is_invisiref_parm): Also handle RESULT_DECL.
|
||||
(cp_genericize_r): Use convert_from_reference.
|
||||
Don't dereference a RESULT_DECL directly inside a RETURN_EXPR.
|
||||
(cp_genericize): Handle the RESULT_DECL. Unset TREE_ADDRESSABLE.
|
||||
|
||||
* gimplify.c (gimplify_call_expr): Make return in memory explicit.
|
||||
(gimplify_modify_expr_rhs): Likewise.
|
||||
* c-common.c (c_warn_unused_result): Check TREE_USED before
|
||||
|
|
|
@ -267,7 +267,7 @@ cp_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p)
|
|||
static inline bool
|
||||
is_invisiref_parm (tree t)
|
||||
{
|
||||
return (TREE_CODE (t) == PARM_DECL
|
||||
return ((TREE_CODE (t) == PARM_DECL || TREE_CODE (t) == RESULT_DECL)
|
||||
&& DECL_BY_REFERENCE (t));
|
||||
}
|
||||
|
||||
|
@ -283,7 +283,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
|
|||
|
||||
if (is_invisiref_parm (stmt))
|
||||
{
|
||||
*stmt_p = build_fold_indirect_ref (stmt);
|
||||
*stmt_p = convert_from_reference (stmt);
|
||||
*walk_subtrees = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -302,6 +302,11 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
|
|||
*stmt_p = convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0));
|
||||
*walk_subtrees = 0;
|
||||
}
|
||||
else if (TREE_CODE (stmt) == RETURN_EXPR
|
||||
&& TREE_OPERAND (stmt, 0)
|
||||
&& is_invisiref_parm (TREE_OPERAND (stmt, 0)))
|
||||
/* Don't dereference an invisiref RESULT_DECL inside a RETURN_EXPR. */
|
||||
*walk_subtrees = 0;
|
||||
else if (DECL_P (stmt) || TYPE_P (stmt))
|
||||
*walk_subtrees = 0;
|
||||
|
||||
|
@ -331,12 +336,23 @@ cp_genericize (tree fndecl)
|
|||
{
|
||||
if (DECL_ARG_TYPE (t) == TREE_TYPE (t))
|
||||
abort ();
|
||||
DECL_BY_REFERENCE (t) = 1;
|
||||
TREE_TYPE (t) = DECL_ARG_TYPE (t);
|
||||
DECL_BY_REFERENCE (t) = 1;
|
||||
TREE_ADDRESSABLE (t) = 0;
|
||||
relayout_decl (t);
|
||||
}
|
||||
}
|
||||
|
||||
/* Do the same for the return value. */
|
||||
if (TREE_ADDRESSABLE (TREE_TYPE (DECL_RESULT (fndecl))))
|
||||
{
|
||||
t = DECL_RESULT (fndecl);
|
||||
TREE_TYPE (t) = build_reference_type (TREE_TYPE (t));
|
||||
DECL_BY_REFERENCE (t) = 1;
|
||||
TREE_ADDRESSABLE (t) = 0;
|
||||
relayout_decl (t);
|
||||
}
|
||||
|
||||
/* If we're a clone, the body is already GIMPLE. */
|
||||
if (DECL_CLONED_FUNCTION_P (fndecl))
|
||||
return;
|
||||
|
|
|
@ -1883,6 +1883,11 @@ aggregate_value_p (tree exp, tree fntype)
|
|||
|
||||
if (TREE_CODE (type) == VOID_TYPE)
|
||||
return 0;
|
||||
/* If the front end has decided that this needs to be passed by
|
||||
reference, do so. */
|
||||
if ((TREE_CODE (exp) == PARM_DECL || TREE_CODE (exp) == RESULT_DECL)
|
||||
&& DECL_BY_REFERENCE (exp))
|
||||
return 1;
|
||||
if (targetm.calls.return_in_memory (type, fntype))
|
||||
return 1;
|
||||
/* Types that are TREE_ADDRESSABLE must be constructed in memory,
|
||||
|
@ -2187,15 +2192,6 @@ assign_parm_find_data_types (struct assign_parm_data_all *all, tree parm,
|
|||
data->passed_pointer = true;
|
||||
passed_mode = nominal_mode = Pmode;
|
||||
}
|
||||
/* See if the frontend wants to pass this by invisible reference. */
|
||||
else if (passed_type != nominal_type
|
||||
&& POINTER_TYPE_P (passed_type)
|
||||
&& TREE_TYPE (passed_type) == nominal_type)
|
||||
{
|
||||
nominal_type = passed_type;
|
||||
data->passed_pointer = 1;
|
||||
passed_mode = nominal_mode = Pmode;
|
||||
}
|
||||
|
||||
/* Find mode as it is passed by the ABI. */
|
||||
promoted_mode = passed_mode;
|
||||
|
@ -3095,9 +3091,14 @@ assign_parms (tree fndecl)
|
|||
rtx addr = DECL_RTL (all.function_result_decl);
|
||||
rtx x;
|
||||
|
||||
addr = convert_memory_address (Pmode, addr);
|
||||
x = gen_rtx_MEM (DECL_MODE (result), addr);
|
||||
set_mem_attributes (x, result, 1);
|
||||
if (DECL_BY_REFERENCE (result))
|
||||
x = addr;
|
||||
else
|
||||
{
|
||||
addr = convert_memory_address (Pmode, addr);
|
||||
x = gen_rtx_MEM (DECL_MODE (result), addr);
|
||||
set_mem_attributes (x, result, 1);
|
||||
}
|
||||
SET_DECL_RTL (result, x);
|
||||
}
|
||||
|
||||
|
@ -4385,17 +4386,22 @@ expand_function_end (void)
|
|||
if (current_function_returns_struct
|
||||
|| current_function_returns_pcc_struct)
|
||||
{
|
||||
rtx value_address
|
||||
= XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
|
||||
rtx value_address = DECL_RTL (DECL_RESULT (current_function_decl));
|
||||
tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
|
||||
rtx outgoing;
|
||||
|
||||
if (DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
|
||||
type = TREE_TYPE (type);
|
||||
else
|
||||
value_address = XEXP (value_address, 0);
|
||||
|
||||
#ifdef FUNCTION_OUTGOING_VALUE
|
||||
rtx outgoing
|
||||
= FUNCTION_OUTGOING_VALUE (build_pointer_type (type),
|
||||
current_function_decl);
|
||||
outgoing = FUNCTION_OUTGOING_VALUE (build_pointer_type (type),
|
||||
current_function_decl);
|
||||
#else
|
||||
rtx outgoing
|
||||
= FUNCTION_VALUE (build_pointer_type (type), current_function_decl);
|
||||
#endif
|
||||
outgoing = FUNCTION_VALUE (build_pointer_type (type),
|
||||
current_function_decl);
|
||||
#endif
|
||||
|
||||
/* Mark this as a function return value so integrate will delete the
|
||||
assignment and USE below when inlining this function. */
|
||||
|
|
|
@ -895,6 +895,9 @@ gimplify_return_expr (tree stmt, tree *pre_p)
|
|||
else
|
||||
{
|
||||
result_decl = TREE_OPERAND (ret_expr, 0);
|
||||
if (TREE_CODE (result_decl) == INDIRECT_REF)
|
||||
/* See through a return by reference. */
|
||||
result_decl = TREE_OPERAND (result_decl, 0);
|
||||
#ifdef ENABLE_CHECKING
|
||||
if ((TREE_CODE (ret_expr) != MODIFY_EXPR
|
||||
&& TREE_CODE (ret_expr) != INIT_EXPR)
|
||||
|
|
|
@ -573,33 +573,6 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (TREE_CODE (*tp) == ADDR_EXPR
|
||||
&& (lang_hooks.tree_inlining.auto_var_in_fn_p
|
||||
(TREE_OPERAND (*tp, 0), fn)))
|
||||
{
|
||||
/* Get rid of &* from inline substitutions. It can occur when
|
||||
someone takes the address of a parm or return slot passed by
|
||||
invisible reference. */
|
||||
tree decl = TREE_OPERAND (*tp, 0), value;
|
||||
splay_tree_node n;
|
||||
|
||||
n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
|
||||
if (n)
|
||||
{
|
||||
value = (tree) n->value;
|
||||
if (TREE_CODE (value) == INDIRECT_REF)
|
||||
{
|
||||
if (!lang_hooks.types_compatible_p
|
||||
(TREE_TYPE (*tp), TREE_TYPE (TREE_OPERAND (value, 0))))
|
||||
*tp = fold_convert (TREE_TYPE (*tp),
|
||||
TREE_OPERAND (value, 0));
|
||||
else
|
||||
*tp = TREE_OPERAND (value, 0);
|
||||
|
||||
return copy_body_r (tp, walk_subtrees, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (TREE_CODE (*tp) == INDIRECT_REF)
|
||||
{
|
||||
/* Get rid of *& from inline substitutions that can happen when a
|
||||
|
@ -861,7 +834,7 @@ declare_return_variable (inline_data *id, tree return_slot_addr,
|
|||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* If there was a return slot, then the return value the the
|
||||
/* If there was a return slot, then the return value is the
|
||||
dereferenced address of that object. */
|
||||
if (return_slot_addr)
|
||||
{
|
||||
|
@ -869,7 +842,10 @@ declare_return_variable (inline_data *id, tree return_slot_addr,
|
|||
a modify expression. */
|
||||
if (modify_dest)
|
||||
abort ();
|
||||
var = build_fold_indirect_ref (return_slot_addr);
|
||||
if (DECL_BY_REFERENCE (result))
|
||||
var = return_slot_addr;
|
||||
else
|
||||
var = build_fold_indirect_ref (return_slot_addr);
|
||||
use = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue