This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[basic-improvements] PATCH to make C++ return-in-memory semanticsexplicit
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 13 Dec 2002 17:59:36 -0500
- Subject: [basic-improvements] PATCH to make C++ return-in-memory semanticsexplicit
This patch follows on my recent changes to make C++
pass-by-invisible-reference semantics explicit in the tree structure, in
order to expose C++ semantics to tree optimizers. It does this through a
flag on the CALL_EXPR, which tells expand_call and expand_call_inline to
treat the first argument as the structure value address.
There are a few tangential changes in this patch:
The change to maybe_set_unchanging seems to fix a thinko; I don't see any
good reason to treat decls with no DECL_INITIAL as unchanging.
The change to expand_expr improves generated code for functions which
return a struct in memory because of the processor ABI (as opposed to C++
semantics, like the rest of this patch).
The change to build_cplus_new causes us to stop building up AGGR_INIT_EXPRs
for classes that don't require a copy constructor; we don't need them,
since we can just bitwise copy such classes, and AFAICT
simplify_aggr_init_exprs_r wasn't actually copying the result into the
target slot, so anything which depended on reusing the slot would break.
Applied (soon) to basic-improvements-branch and tree-ssa-branch.
2002-12-13 Jason Merrill <jason@redhat.com>
* tree.h (CALL_EXPR_HAS_RETURN_SLOT_ADDR): New macro.
* calls.c (expand_call): Handle it.
* tree-inline.c (struct inline_data): Remove target_exprs field.
(optimize_inline_calls): Don't initialize it.
(expand_call_inline): Don't modify it. Handle
CALL_EXPR_HAS_RETURN_SLOT_ADDR.
(declare_return_variable): Take return slot addr.
* langhooks.h (copy_res_decl_for_inlining): Change target_exprs parm
to return_slot_addr.
* langhooks-def.h, langhooks.c: Adjust.
* explow.c (maybe_set_unchanging): Don't set RTX_UNCHANGING_P for
a decl with no DECL_INITIAL.
* expr.c (expand_expr): Don't discard the target of a call which
returns in memory.
cp/
* semantics.c (simplify_aggr_init_exprs_r): Also prepend the
return slot for normal functions. Set CALL_EXPR_HAS_RETURN_SLOT_ADDR.
* tree.c (build_cplus_new): If the type isn't TREE_ADDRESSABLE,
don't bother with an AGGR_INIT_EXPR.
(cp_copy_res_decl_for_inlining): If the type isn't TREE_ADDRESSABLE,
just generate a new decl normally. Take return slot parm.
* cp-tree.h: Adjust prototype.
*** ./cp/tree.c.~1~ Fri Dec 13 13:43:23 2002
--- ./cp/tree.c Fri Dec 13 17:22:25 2002
*************** build_cplus_new (type, init)
*** 301,306 ****
--- 301,307 ----
tree fn;
tree slot;
tree rval;
+ int is_ctor;
/* Make sure that we're not trying to create an instance of an
abstract class. */
*************** build_cplus_new (type, init)
*** 309,314 ****
--- 310,320 ----
if (TREE_CODE (init) != CALL_EXPR && TREE_CODE (init) != AGGR_INIT_EXPR)
return convert (type, init);
+ fn = TREE_OPERAND (init, 0);
+ is_ctor = (TREE_CODE (fn) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
+ && DECL_CONSTRUCTOR_P (TREE_OPERAND (fn, 0)));
+
slot = build (VAR_DECL, type);
DECL_ARTIFICIAL (slot) = 1;
DECL_CONTEXT (slot) = current_function_decl;
*************** build_cplus_new (type, init)
*** 322,334 ****
replaces every AGGR_INIT_EXPR with a copy that uses a fresh
temporary slot. Then, expand_expr builds up a call-expression
using the new slot. */
! fn = TREE_OPERAND (init, 0);
! rval = build (AGGR_INIT_EXPR, type, fn, TREE_OPERAND (init, 1), slot);
! TREE_SIDE_EFFECTS (rval) = 1;
! AGGR_INIT_VIA_CTOR_P (rval)
! = (TREE_CODE (fn) == ADDR_EXPR
! && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
! && DECL_CONSTRUCTOR_P (TREE_OPERAND (fn, 0)));
rval = build_target_expr (slot, rval);
return rval;
--- 328,345 ----
replaces every AGGR_INIT_EXPR with a copy that uses a fresh
temporary slot. Then, expand_expr builds up a call-expression
using the new slot. */
!
! /* If we don't need to use a constructor to create an object of this
! type, don't mess with AGGR_INIT_EXPR. */
! if (is_ctor || TREE_ADDRESSABLE (type))
! {
! rval = build (AGGR_INIT_EXPR, type, fn, TREE_OPERAND (init, 1), slot);
! TREE_SIDE_EFFECTS (rval) = 1;
! AGGR_INIT_VIA_CTOR_P (rval) = is_ctor;
! }
! else
! rval = init;
!
rval = build_target_expr (slot, rval);
return rval;
*************** cp_auto_var_in_fn_p (var, fn)
*** 2313,2345 ****
tree
cp_copy_res_decl_for_inlining (result, fn, caller, decl_map_,
! need_decl, target_exprs)
tree result, fn, caller;
void *decl_map_;
int *need_decl;
! void *target_exprs;
{
splay_tree decl_map = (splay_tree)decl_map_;
- varray_type *texps = (varray_type *)target_exprs;
tree var;
- int aggregate_return_p;
! /* Figure out whether or not FN returns an aggregate. */
! aggregate_return_p = IS_AGGR_TYPE (TREE_TYPE (result));
! *need_decl = ! aggregate_return_p;
!
! /* If FN returns an aggregate then the caller will always create the
! temporary (using a TARGET_EXPR) and the call will be the
! initializing expression for the TARGET_EXPR. If we were just to
create a new VAR_DECL here, then the result of this function
would be copied (bitwise) into the variable initialized by the
TARGET_EXPR. That's incorrect, so we must transform any
references to the RESULT into references to the target. */
! if (aggregate_return_p)
{
! if (VARRAY_ACTIVE_SIZE (*texps) == 0)
! abort ();
! var = TREE_OPERAND (VARRAY_TOP_TREE (*texps), 0);
if (! same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (var),
TREE_TYPE (result)))
abort ();
--- 2324,2355 ----
tree
cp_copy_res_decl_for_inlining (result, fn, caller, decl_map_,
! need_decl, return_slot_addr)
tree result, fn, caller;
void *decl_map_;
int *need_decl;
! tree return_slot_addr;
{
splay_tree decl_map = (splay_tree)decl_map_;
tree var;
! /* If FN returns an aggregate then the caller will always pass the
! address of the return slot explicitly. If we were just to
create a new VAR_DECL here, then the result of this function
would be copied (bitwise) into the variable initialized by the
TARGET_EXPR. That's incorrect, so we must transform any
references to the RESULT into references to the target. */
!
! /* We should have an explicit return slot iff the return type is
! TREE_ADDRESSABLE. See simplify_aggr_init_expr. */
! if (TREE_ADDRESSABLE (TREE_TYPE (result))
! != (return_slot_addr != NULL_TREE))
! abort ();
!
! *need_decl = !return_slot_addr;
! if (return_slot_addr)
{
! var = build_indirect_ref (return_slot_addr, "");
if (! same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (var),
TREE_TYPE (result)))
abort ();
*** ./cp/semantics.c.~1~ Fri Dec 13 13:43:22 2002
--- ./cp/semantics.c Fri Dec 13 17:56:52 2002
*************** simplify_aggr_init_exprs_r (tp, walk_sub
*** 2190,2196 ****
tree args;
tree slot;
tree type;
! int copy_from_buffer_p;
aggr_init_expr = *tp;
/* We don't need to walk into types; there's nothing in a type that
--- 2190,2196 ----
tree args;
tree slot;
tree type;
! enum style_t { ctor, arg, pcc } style;
aggr_init_expr = *tp;
/* We don't need to walk into types; there's nothing in a type that
*************** simplify_aggr_init_exprs_r (tp, walk_sub
*** 2212,2259 ****
args = TREE_OPERAND (aggr_init_expr, 1);
slot = TREE_OPERAND (aggr_init_expr, 2);
type = TREE_TYPE (aggr_init_expr);
if (AGGR_INIT_VIA_CTOR_P (aggr_init_expr))
{
! /* Replace the first argument with the address of the third
! argument to the AGGR_INIT_EXPR. */
cxx_mark_addressable (slot);
args = tree_cons (NULL_TREE,
build1 (ADDR_EXPR,
build_pointer_type (TREE_TYPE (slot)),
slot),
! TREE_CHAIN (args));
}
call_expr = build (CALL_EXPR,
TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
fn, args, NULL_TREE);
TREE_SIDE_EFFECTS (call_expr) = 1;
! /* If we're using the non-reentrant PCC calling convention, then we
! need to copy the returned value out of the static buffer into the
! SLOT. */
! copy_from_buffer_p = 0;
! #ifdef PCC_STATIC_STRUCT_RETURN
! if (!AGGR_INIT_VIA_CTOR_P (aggr_init_expr) && aggregate_value_p (type))
{
int old_ac = flag_access_control;
flag_access_control = 0;
call_expr = build_aggr_init (slot, call_expr,
DIRECT_BIND | LOOKUP_ONLYCONVERTING);
flag_access_control = old_ac;
- copy_from_buffer_p = 1;
}
- #endif
! /* If this AGGR_INIT_EXPR indicates the value returned by a
! function, then we want to use the value of the initialized
! location as the result. */
! if (AGGR_INIT_VIA_CTOR_P (aggr_init_expr) || copy_from_buffer_p)
! {
! call_expr = build (COMPOUND_EXPR, type,
! call_expr, slot);
! TREE_SIDE_EFFECTS (call_expr) = 1;
! }
/* Replace the AGGR_INIT_EXPR with the CALL_EXPR. */
TREE_CHAIN (call_expr) = TREE_CHAIN (aggr_init_expr);
--- 2212,2277 ----
args = TREE_OPERAND (aggr_init_expr, 1);
slot = TREE_OPERAND (aggr_init_expr, 2);
type = TREE_TYPE (aggr_init_expr);
+
if (AGGR_INIT_VIA_CTOR_P (aggr_init_expr))
+ style = ctor;
+ #ifdef PCC_STATIC_STRUCT_RETURN
+ else if (1)
+ style = pcc;
+ #endif
+ else if (TREE_ADDRESSABLE (type))
+ style = arg;
+ else
+ /* We shouldn't build an AGGR_INIT_EXPR if we don't need any special
+ handling. See build_cplus_new. */
+ abort ();
+
+ if (style == ctor || style == arg)
{
! /* Pass the address of the slot. If this is a constructor, we
! replace the first argument; otherwise, we tack on a new one. */
! if (style == ctor)
! args = TREE_CHAIN (args);
!
cxx_mark_addressable (slot);
args = tree_cons (NULL_TREE,
build1 (ADDR_EXPR,
build_pointer_type (TREE_TYPE (slot)),
slot),
! args);
}
+
call_expr = build (CALL_EXPR,
TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
fn, args, NULL_TREE);
TREE_SIDE_EFFECTS (call_expr) = 1;
! if (style == arg)
{
+ /* Tell the backend that we've added our return slot to the argument
+ list. */
+ CALL_EXPR_HAS_RETURN_SLOT_ADDR (call_expr) = 1;
+ /* And don't let anyone use the value of the call directly in a
+ larger expression. */
+ TREE_TYPE (call_expr) = void_type_node;
+ }
+ else if (style == pcc)
+ {
+ /* If we're using the non-reentrant PCC calling convention, then we
+ need to copy the returned value out of the static buffer into the
+ SLOT. */
int old_ac = flag_access_control;
flag_access_control = 0;
call_expr = build_aggr_init (slot, call_expr,
DIRECT_BIND | LOOKUP_ONLYCONVERTING);
flag_access_control = old_ac;
}
! /* We want to use the value of the initialized location as the
! result. */
! call_expr = build (COMPOUND_EXPR, type,
! call_expr, slot);
/* Replace the AGGR_INIT_EXPR with the CALL_EXPR. */
TREE_CHAIN (call_expr) = TREE_CHAIN (aggr_init_expr);
*** ./cp/cp-tree.h.~1~ Fri Dec 13 13:43:16 2002
--- ./cp/cp-tree.h Fri Dec 13 14:52:12 2002
*************** extern tree cp_add_pending_fn_decls PARA
*** 4304,4310 ****
extern int cp_is_overload_p PARAMS ((tree));
extern int cp_auto_var_in_fn_p PARAMS ((tree,tree));
extern tree cp_copy_res_decl_for_inlining PARAMS ((tree, tree, tree, void*,
! int*, void*));
extern int cp_start_inlining PARAMS ((tree));
extern void cp_end_inlining PARAMS ((tree));
--- 4304,4310 ----
extern int cp_is_overload_p PARAMS ((tree));
extern int cp_auto_var_in_fn_p PARAMS ((tree,tree));
extern tree cp_copy_res_decl_for_inlining PARAMS ((tree, tree, tree, void*,
! int*, tree));
extern int cp_start_inlining PARAMS ((tree));
extern void cp_end_inlining PARAMS ((tree));
*** ./calls.c.~1~ Fri Dec 13 13:40:44 2002
--- ./calls.c Fri Dec 13 17:56:00 2002
*************** expand_call (exp, target, ignore)
*** 2248,2254 ****
{
struct_value_size = int_size_in_bytes (TREE_TYPE (exp));
! if (target && GET_CODE (target) == MEM)
structure_value_addr = XEXP (target, 0);
else
{
--- 2248,2257 ----
{
struct_value_size = int_size_in_bytes (TREE_TYPE (exp));
! if (CALL_EXPR_HAS_RETURN_SLOT_ADDR (exp))
! /* The structure value address arg is already in actparms. */
! structure_value_addr_parm = 1;
! else if (target && GET_CODE (target) == MEM)
structure_value_addr = XEXP (target, 0);
else
{
*** ./tree.h.~1~ Fri Dec 13 13:41:26 2002
--- ./tree.h Fri Dec 13 14:52:12 2002
*************** struct tree_common GTY(())
*** 202,207 ****
--- 202,209 ----
TREE_LIST or TREE_VEC
TREE_PRIVATE in
..._DECL
+ CALL_EXPR_HAS_RETURN_SLOT_ADDR in
+ CALL_EXPR
protected_flag:
*************** extern void tree_vec_elt_check_failed PA
*** 638,643 ****
--- 640,649 ----
an exception. In a CALL_EXPR, nonzero means the call cannot throw. */
#define TREE_NOTHROW(NODE) ((NODE)->common.nothrow_flag)
+ /* In a CALL_EXPR, means that the address of the return slot is part of the
+ argument list. */
+ #define CALL_EXPR_HAS_RETURN_SLOT_ADDR(NODE) ((NODE)->common.private_flag)
+
/* In a type, nonzero means that all objects of the type are guaranteed by the
language or front-end to be properly aligned, so we can indicate that a MEM
of this type is aligned at least to the alignment of the type, even if it
*** ./tree-inline.c.~1~ Fri Dec 13 13:41:25 2002
--- ./tree-inline.c Fri Dec 13 14:52:12 2002
*************** typedef struct inline_data
*** 90,97 ****
/* Nonzero if we are currently within the cleanup for a
TARGET_EXPR. */
int in_target_cleanup_p;
- /* A stack of the TARGET_EXPRs that we are currently processing. */
- varray_type target_exprs;
/* A list of the functions current function has inlined. */
varray_type inlined_fns;
/* The approximate number of statements we have inlined in the
--- 90,95 ----
*************** typedef struct inline_data
*** 109,115 ****
/* Prototypes. */
! static tree declare_return_variable PARAMS ((inline_data *, tree *));
static tree copy_body_r PARAMS ((tree *, int *, void *));
static tree copy_body PARAMS ((inline_data *));
static tree expand_call_inline PARAMS ((tree *, int *, void *));
--- 107,113 ----
/* Prototypes. */
! static tree declare_return_variable PARAMS ((inline_data *, tree, tree *));
static tree copy_body_r PARAMS ((tree *, int *, void *));
static tree copy_body PARAMS ((inline_data *));
static tree expand_call_inline PARAMS ((tree *, int *, void *));
*************** initialize_inlined_parameters (id, args,
*** 779,791 ****
#ifndef INLINER_FOR_JAVA
static tree
! declare_return_variable (id, use_stmt)
struct inline_data *id;
tree *use_stmt;
#else /* INLINER_FOR_JAVA */
static tree
! declare_return_variable (id, var)
struct inline_data *id;
tree *var;
#endif /* INLINER_FOR_JAVA */
{
--- 777,791 ----
#ifndef INLINER_FOR_JAVA
static tree
! declare_return_variable (id, return_slot_addr, use_stmt)
struct inline_data *id;
+ tree return_slot_addr;
tree *use_stmt;
#else /* INLINER_FOR_JAVA */
static tree
! declare_return_variable (id, return_slot_addr, var)
struct inline_data *id;
+ tree return_slot_addr;
tree *var;
#endif /* INLINER_FOR_JAVA */
{
*************** declare_return_variable (id, var)
*** 811,817 ****
#ifndef INLINER_FOR_JAVA
var = ((*lang_hooks.tree_inlining.copy_res_decl_for_inlining)
(result, fn, VARRAY_TREE (id->fns, 0), id->decl_map,
! &need_return_decl, &id->target_exprs));
/* Register the VAR_DECL as the equivalent for the RESULT_DECL; that
way, when the RESULT_DECL is encountered, it will be
--- 811,817 ----
#ifndef INLINER_FOR_JAVA
var = ((*lang_hooks.tree_inlining.copy_res_decl_for_inlining)
(result, fn, VARRAY_TREE (id->fns, 0), id->decl_map,
! &need_return_decl, return_slot_addr));
/* Register the VAR_DECL as the equivalent for the RESULT_DECL; that
way, when the RESULT_DECL is encountered, it will be
*************** declare_return_variable (id, var)
*** 837,843 ****
#else /* INLINER_FOR_JAVA */
*var = ((*lang_hooks.tree_inlining.copy_res_decl_for_inlining)
(result, fn, VARRAY_TREE (id->fns, 0), id->decl_map,
! &need_return_decl, NULL_TREE));
splay_tree_insert (id->decl_map,
(splay_tree_key) result,
--- 837,843 ----
#else /* INLINER_FOR_JAVA */
*var = ((*lang_hooks.tree_inlining.copy_res_decl_for_inlining)
(result, fn, VARRAY_TREE (id->fns, 0), id->decl_map,
! &need_return_decl, return_slot_addr));
splay_tree_insert (id->decl_map,
(splay_tree_key) result,
*************** expand_call_inline (tp, walk_subtrees, d
*** 1025,1030 ****
--- 1025,1032 ----
tree arg_inits;
tree *inlined_body;
splay_tree st;
+ tree args;
+ tree return_slot_addr;
/* See what we've got. */
id = (inline_data *) data;
*************** expand_call_inline (tp, walk_subtrees, d
*** 1040,1048 ****
/* We're walking our own subtrees. */
*walk_subtrees = 0;
- /* Push *TP on the stack of pending TARGET_EXPRs. */
- VARRAY_PUSH_TREE (id->target_exprs, *tp);
-
/* Actually walk over them. This loop is the body of
walk_trees, omitting the case where the TARGET_EXPR
itself is handled. */
--- 1042,1047 ----
*************** expand_call_inline (tp, walk_subtrees, d
*** 1056,1064 ****
--id->in_target_cleanup_p;
}
- /* We're done with this TARGET_EXPR now. */
- VARRAY_POP (id->target_exprs);
-
return NULL_TREE;
#else /* INLINER_FOR_JAVA */
abort ();
--- 1055,1060 ----
*************** expand_call_inline (tp, walk_subtrees, d
*** 1134,1141 ****
NULL, NULL);
/* Initialize the parameters. */
#ifndef INLINER_FOR_JAVA
! arg_inits = initialize_inlined_parameters (id, TREE_OPERAND (t, 1), fn);
/* Expand any inlined calls in the initializers. Do this before we
push FN on the stack of functions we are inlining; we want to
inline calls to FN that appear in the initializers for the
--- 1130,1145 ----
NULL, NULL);
/* Initialize the parameters. */
+ args = TREE_OPERAND (t, 1);
+ return_slot_addr = NULL_TREE;
+ if (CALL_EXPR_HAS_RETURN_SLOT_ADDR (t))
+ {
+ return_slot_addr = TREE_VALUE (args);
+ args = TREE_CHAIN (args);
+ }
+
#ifndef INLINER_FOR_JAVA
! arg_inits = initialize_inlined_parameters (id, args, fn);
/* Expand any inlined calls in the initializers. Do this before we
push FN on the stack of functions we are inlining; we want to
inline calls to FN that appear in the initializers for the
*************** expand_call_inline (tp, walk_subtrees, d
*** 1144,1150 ****
/* And add them to the tree. */
COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY (stmt), arg_inits);
#else /* INLINER_FOR_JAVA */
! arg_inits = initialize_inlined_parameters (id, TREE_OPERAND (t, 1), fn, expr);
if (arg_inits)
{
/* Expand any inlined calls in the initializers. Do this before we
--- 1148,1154 ----
/* And add them to the tree. */
COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY (stmt), arg_inits);
#else /* INLINER_FOR_JAVA */
! arg_inits = initialize_inlined_parameters (id, args, fn, expr);
if (arg_inits)
{
/* Expand any inlined calls in the initializers. Do this before we
*************** expand_call_inline (tp, walk_subtrees, d
*** 1205,1215 ****
/* Declare the return variable for the function. */
COMPOUND_BODY (stmt)
= chainon (COMPOUND_BODY (stmt),
! declare_return_variable (id, &use_stmt));
#else /* INLINER_FOR_JAVA */
{
/* Declare the return variable for the function. */
! tree decl = declare_return_variable (id, &retvar);
if (retvar)
{
tree *next = &BLOCK_VARS (expr);
--- 1209,1219 ----
/* Declare the return variable for the function. */
COMPOUND_BODY (stmt)
= chainon (COMPOUND_BODY (stmt),
! declare_return_variable (id, return_slot_addr, &use_stmt));
#else /* INLINER_FOR_JAVA */
{
/* Declare the return variable for the function. */
! tree decl = declare_return_variable (id, return_slot_addr, &retvar);
if (retvar)
{
tree *next = &BLOCK_VARS (expr);
*************** optimize_inline_calls (fn)
*** 1377,1385 ****
prev_fn = ((*lang_hooks.tree_inlining.add_pending_fn_decls)
(&id.fns, prev_fn));
- /* Create the stack of TARGET_EXPRs. */
- VARRAY_TREE_INIT (id.target_exprs, 32, "target_exprs");
-
/* Create the list of functions this call will inline. */
VARRAY_TREE_INIT (id.inlined_fns, 32, "inlined_fns");
--- 1381,1386 ----
*** ./langhooks.h.~1~ Mon Oct 28 14:47:06 2002
--- ./langhooks.h Fri Dec 13 14:52:12 2002
*************** struct lang_hooks_for_tree_inlining
*** 48,54 ****
union tree_node *,
union tree_node *,
void *, int *,
! void *));
int (*anon_aggr_type_p) PARAMS ((union tree_node *));
bool (*var_mod_type_p) PARAMS ((union tree_node *));
int (*start_inlining) PARAMS ((union tree_node *));
--- 48,54 ----
union tree_node *,
union tree_node *,
void *, int *,
! tree));
int (*anon_aggr_type_p) PARAMS ((union tree_node *));
bool (*var_mod_type_p) PARAMS ((union tree_node *));
int (*start_inlining) PARAMS ((union tree_node *));
*** ./langhooks.c.~1~ Fri Dec 13 13:41:08 2002
--- ./langhooks.c Fri Dec 13 14:52:12 2002
*************** lhd_tree_inlining_auto_var_in_fn_p (var,
*** 356,368 ****
tree
lhd_tree_inlining_copy_res_decl_for_inlining (res, fn, caller,
! dm, ndp, texps)
tree res, fn, caller;
void *dm ATTRIBUTE_UNUSED;
int *ndp ATTRIBUTE_UNUSED;
! void *texps ATTRIBUTE_UNUSED;
{
! return copy_decl_for_inlining (res, fn, caller);
}
/* lang_hooks.tree_inlining.anon_aggr_type_p determines whether T is a
--- 356,372 ----
tree
lhd_tree_inlining_copy_res_decl_for_inlining (res, fn, caller,
! dm, ndp, return_slot_addr)
tree res, fn, caller;
void *dm ATTRIBUTE_UNUSED;
int *ndp ATTRIBUTE_UNUSED;
! tree return_slot_addr ATTRIBUTE_UNUSED;
{
! if (return_slot_addr)
! return build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (return_slot_addr)),
! return_slot_addr);
! else
! return copy_decl_for_inlining (res, fn, caller);
}
/* lang_hooks.tree_inlining.anon_aggr_type_p determines whether T is a
*** ./langhooks-def.h.~1~ Fri Dec 13 13:41:08 2002
--- ./langhooks-def.h Fri Dec 13 14:52:12 2002
*************** int lhd_tree_inlining_tree_chain_matters
*** 76,82 ****
int lhd_tree_inlining_auto_var_in_fn_p PARAMS ((tree, tree));
tree lhd_tree_inlining_copy_res_decl_for_inlining PARAMS ((tree, tree,
tree, void *,
! int *, void *));
int lhd_tree_inlining_anon_aggr_type_p PARAMS ((tree));
int lhd_tree_inlining_start_inlining PARAMS ((tree));
void lhd_tree_inlining_end_inlining PARAMS ((tree));
--- 76,82 ----
int lhd_tree_inlining_auto_var_in_fn_p PARAMS ((tree, tree));
tree lhd_tree_inlining_copy_res_decl_for_inlining PARAMS ((tree, tree,
tree, void *,
! int *, tree));
int lhd_tree_inlining_anon_aggr_type_p PARAMS ((tree));
int lhd_tree_inlining_start_inlining PARAMS ((tree));
void lhd_tree_inlining_end_inlining PARAMS ((tree));
*** ./explow.c.~1~ Fri Dec 13 13:40:55 2002
--- ./explow.c Fri Dec 13 16:35:40 2002
*************** maybe_set_unchanging (ref, t)
*** 660,667 ****
first case, and decls with TREE_CONSTANT initializers in the second. */
if ((TREE_READONLY (t) && DECL_P (t)
&& (TREE_CODE (t) == PARM_DECL
! || DECL_INITIAL (t) == NULL_TREE
! || TREE_CONSTANT (DECL_INITIAL (t))))
|| TREE_CODE_CLASS (TREE_CODE (t)) == 'c')
RTX_UNCHANGING_P (ref) = 1;
}
--- 660,666 ----
first case, and decls with TREE_CONSTANT initializers in the second. */
if ((TREE_READONLY (t) && DECL_P (t)
&& (TREE_CODE (t) == PARM_DECL
! || (DECL_INITIAL (t) && TREE_CONSTANT (DECL_INITIAL (t)))))
|| TREE_CODE_CLASS (TREE_CODE (t)) == 'c')
RTX_UNCHANGING_P (ref) = 1;
}
*** ./expr.c.~1~ Fri Dec 13 13:40:55 2002
--- ./expr.c Fri Dec 13 16:35:40 2002
*************** expand_expr (exp, target, tmode, modifie
*** 6552,6563 ****
/* If will do cse, generate all results into pseudo registers
since 1) that allows cse to find more things
and 2) otherwise cse could produce an insn the machine
! cannot support. And exception is a CONSTRUCTOR into a multi-word
! MEM: that's much more likely to be most efficient into the MEM. */
if (! cse_not_expected && mode != BLKmode && target
&& (GET_CODE (target) != REG || REGNO (target) < FIRST_PSEUDO_REGISTER)
! && ! (code == CONSTRUCTOR && GET_MODE_SIZE (mode) > UNITS_PER_WORD))
target = subtarget;
switch (code)
--- 6552,6565 ----
/* If will do cse, generate all results into pseudo registers
since 1) that allows cse to find more things
and 2) otherwise cse could produce an insn the machine
! cannot support. An exception is a CONSTRUCTOR into a multi-word
! MEM: that's much more likely to be most efficient into the MEM.
! Another is a CALL_EXPR which must return in memory. */
if (! cse_not_expected && mode != BLKmode && target
&& (GET_CODE (target) != REG || REGNO (target) < FIRST_PSEUDO_REGISTER)
! && ! (code == CONSTRUCTOR && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
! && ! (code == CALL_EXPR && aggregate_value_p (exp)))
target = subtarget;
switch (code)