langhooks-def.h (LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING, [...]): Remove.

* langhooks-def.h (LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING,
        lhd_tree_inlining_copy_res_decl_for_inlining): Remove.
        * langhooks.c (lhd_tree_inlining_copy_res_decl_for_inlining): Remove.
        * langhooks.h (struct lang_hooks_for_tree_inlining): Remove
        copy_res_decl_for_inlining.

        * tree-inline.c (declare_return_variable): New modify_dest argument.
        Use it as the return value, when possible or manditory.  Handle
        TREE_ADDRESSABLE types.
        (expand_call_inline): Extract MODIFY_EXPR lhs for call.  Simplify
        replacement of CALL_EXPR.

cp/
        * cp-lang.c (LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING): Die.
        * cp-tree.h (cp_copy_res_decl_for_inlining): Remove.
        * tree.c (cp_copy_res_decl_for_inlining): Remove.

From-SVN: r84831
This commit is contained in:
Richard Henderson 2004-07-16 13:51:31 -07:00 committed by Richard Henderson
parent 26e79d1018
commit 7740f00d54
10 changed files with 120 additions and 149 deletions

View File

@ -1,3 +1,17 @@
2004-07-16 Richard Henderson <rth@redhat.com>
* langhooks-def.h (LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING,
lhd_tree_inlining_copy_res_decl_for_inlining): Remove.
* langhooks.c (lhd_tree_inlining_copy_res_decl_for_inlining): Remove.
* langhooks.h (struct lang_hooks_for_tree_inlining): Remove
copy_res_decl_for_inlining.
* tree-inline.c (declare_return_variable): New modify_dest argument.
Use it as the return value, when possible or manditory. Handle
TREE_ADDRESSABLE types.
(expand_call_inline): Extract MODIFY_EXPR lhs for call. Simplify
replacement of CALL_EXPR.
2004-07-16 Richard Henderson <rth@redhat.com>
* tree-flow.h (struct var_ann_d): Remove has_hidden_use.

View File

@ -1,3 +1,9 @@
2004-07-16 Richard Henderson <rth@redhat.com>
* cp-lang.c (LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING): Die.
* cp-tree.h (cp_copy_res_decl_for_inlining): Remove.
* tree.c (cp_copy_res_decl_for_inlining): Remove.
2004-07-16 Nathan Sidwell <nathan@codesourcery.com>
* class.c (finish_struct_bits): Use for loop.

View File

@ -131,9 +131,6 @@ static void cxx_initialize_diagnostics (diagnostic_context *);
#undef LANG_HOOKS_TREE_INLINING_AUTO_VAR_IN_FN_P
#define LANG_HOOKS_TREE_INLINING_AUTO_VAR_IN_FN_P \
cp_auto_var_in_fn_p
#undef LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING
#define LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING \
cp_copy_res_decl_for_inlining
#undef LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P
#define LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P anon_aggr_type_p
#undef LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P

View File

@ -4206,8 +4206,6 @@ extern int cp_cannot_inline_tree_fn (tree*);
extern tree cp_add_pending_fn_decls (void*,tree);
extern int cp_is_overload_p (tree);
extern int cp_auto_var_in_fn_p (tree,tree);
extern tree cp_copy_res_decl_for_inlining (tree, tree, tree, void*,
int*, tree);
extern void cp_update_decl_after_saving (tree, void *);
/* in typeck.c */

View File

@ -10680,8 +10680,8 @@ cxx_push_function_context (struct function * f)
*cp_function_chain = *DECL_SAVED_FUNCTION_DATA (fn);
/* We don't need the saved data anymore. Unless this is an inline
function; we need the named return value info for
cp_copy_res_decl_for_inlining. */
function; we need the named return value info for
declare_return_variable. */
if (! DECL_INLINE (fn))
DECL_SAVED_FUNCTION_DATA (fn) = NULL;
}

View File

@ -2093,48 +2093,6 @@ cp_auto_var_in_fn_p (tree var, tree fn)
&& nonstatic_local_decl_p (var));
}
/* Tell whether a declaration is needed for the RESULT of a function
FN being inlined into CALLER or if the top node of target_exprs is
to be used. */
tree
cp_copy_res_decl_for_inlining (tree result,
tree fn,
tree caller,
void* decl_map_ ATTRIBUTE_UNUSED,
int* need_decl,
tree return_slot_addr)
{
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 gimplify_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 ();
}
/* Otherwise, make an appropriate copy. */
else
var = copy_decl_for_inlining (result, fn, caller);
return var;
}
/* FN body has been duplicated. Update language specific fields. */
void

View File

@ -78,8 +78,6 @@ extern int lhd_tree_inlining_cannot_inline_tree_fn (tree *);
extern int lhd_tree_inlining_disregard_inline_limits (tree);
extern tree lhd_tree_inlining_add_pending_fn_decls (void *, tree);
extern int lhd_tree_inlining_auto_var_in_fn_p (tree, tree);
extern tree lhd_tree_inlining_copy_res_decl_for_inlining (tree, tree, tree,
void *, int *, tree);
extern int lhd_tree_inlining_anon_aggr_type_p (tree);
extern int lhd_tree_inlining_start_inlining (tree);
extern void lhd_tree_inlining_end_inlining (tree);
@ -150,8 +148,6 @@ extern int lhd_gimplify_expr (tree *, tree *, tree *);
lhd_tree_inlining_add_pending_fn_decls
#define LANG_HOOKS_TREE_INLINING_AUTO_VAR_IN_FN_P \
lhd_tree_inlining_auto_var_in_fn_p
#define LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING \
lhd_tree_inlining_copy_res_decl_for_inlining
#define LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P \
lhd_tree_inlining_anon_aggr_type_p
#define LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P \
@ -169,7 +165,6 @@ extern int lhd_gimplify_expr (tree *, tree *, tree *);
LANG_HOOKS_TREE_INLINING_DISREGARD_INLINE_LIMITS, \
LANG_HOOKS_TREE_INLINING_ADD_PENDING_FN_DECLS, \
LANG_HOOKS_TREE_INLINING_AUTO_VAR_IN_FN_P, \
LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING, \
LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P, \
LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P, \
LANG_HOOKS_TREE_INLINING_START_INLINING, \

View File

@ -362,28 +362,6 @@ lhd_tree_inlining_auto_var_in_fn_p (tree var, tree fn)
|| TREE_CODE (var) == RESULT_DECL));
}
/* lang_hooks.tree_inlining.copy_res_decl_for_inlining should return a
declaration for the result RES of function FN to be inlined into
CALLER. NDP points to an integer that should be set in case a new
declaration wasn't created (presumably because RES was of aggregate
type, such that a TARGET_EXPR is used for the result). TEXPS is a
pointer to a varray with the stack of TARGET_EXPRs seen while
inlining functions into caller; the top of TEXPS is supposed to
match RES. */
tree
lhd_tree_inlining_copy_res_decl_for_inlining (tree res, tree fn, tree 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
type node representing an anonymous aggregate (union, struct, etc),
i.e., one whose members are in the same scope as the union itself. */

View File

@ -40,8 +40,6 @@ struct lang_hooks_for_tree_inlining
int (*disregard_inline_limits) (tree);
tree (*add_pending_fn_decls) (void *, tree);
int (*auto_var_in_fn_p) (tree, tree);
tree (*copy_res_decl_for_inlining) (tree, tree, tree,
void *, int *, tree);
int (*anon_aggr_type_p) (tree);
bool (*var_mod_type_p) (tree, tree);
int (*start_inlining) (tree);

View File

@ -122,7 +122,6 @@ typedef struct inline_data
decisions about when a function is too big to inline. */
#define INSNS_PER_STMT (10)
static tree declare_return_variable (inline_data *, tree, tree *);
static tree copy_body_r (tree *, int *, void *);
static tree copy_body (inline_data *);
static tree expand_call_inline (tree *, int *, void *);
@ -851,35 +850,102 @@ initialize_inlined_parameters (inline_data *id, tree args, tree static_chain,
return init_stmts;
}
/* Declare a return variable to replace the RESULT_DECL for the
function we are calling. An appropriate decl is returned.
??? Needs documentation of parameters. */
/* Declare a return variable to replace the RESULT_DECL for the function we
are calling. RETURN_SLOT_ADDR, if non-null, was a fake parameter that
took the address of the result. MODIFY_DEST, if non-null, was the LHS of
the MODIFY_EXPR to which this call is the RHS.
The return value is a (possibly null) value that is the result of the
function as seen by the callee. *USE_P is a (possibly null) value that
holds the result as seen by the caller. */
static tree
declare_return_variable (inline_data *id, tree return_slot_addr, tree *use_p)
declare_return_variable (inline_data *id, tree return_slot_addr,
tree modify_dest, tree *use_p)
{
tree fn = VARRAY_TOP_TREE (id->fns);
tree result = DECL_RESULT (fn);
int need_return_decl = 1;
tree var;
tree callee = VARRAY_TOP_TREE (id->fns);
tree caller = VARRAY_TREE (id->fns, 0);
tree result = DECL_RESULT (callee);
tree callee_type = TREE_TYPE (result);
tree caller_type = TREE_TYPE (TREE_TYPE (callee));
tree var, use;
/* We don't need to do anything for functions that don't return
anything. */
if (!result || VOID_TYPE_P (TREE_TYPE (result)))
if (!result || VOID_TYPE_P (callee_type))
{
*use_p = NULL_TREE;
return NULL_TREE;
}
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));
/* If there was a return slot, then the return value the the
dereferenced address of that object. */
if (return_slot_addr)
{
/* The front end shouldn't have used both return_slot_addr and
a modify expression. */
if (modify_dest)
abort ();
var = build_fold_indirect_ref (return_slot_addr);
use = NULL;
goto done;
}
/* All types requiring non-trivial constructors should have been handled. */
if (TREE_ADDRESSABLE (callee_type))
abort ();
/* Attempt to avoid creating a new temporary variable. */
if (modify_dest)
{
bool use_it = false;
/* We can't use MODIFY_DEST if there's type promotion involved. */
if (!lang_hooks.types_compatible_p (caller_type, callee_type))
use_it = false;
/* ??? If we're assigning to a variable sized type, then we must
reuse the destination variable, because we've no good way to
create variable sized temporaries at this point. */
else if (TREE_CODE (TYPE_SIZE_UNIT (caller_type)) != INTEGER_CST)
use_it = true;
/* If the callee cannot possibly modify MODIFY_DEST, then we can
reuse it as the result of the call directly. Don't do this if
it would promote MODIFY_DEST to addressable. */
else if (!TREE_STATIC (modify_dest)
&& !TREE_ADDRESSABLE (modify_dest)
&& !TREE_ADDRESSABLE (result))
use_it = true;
if (use_it)
{
var = modify_dest;
use = NULL;
goto done;
}
}
if (TREE_CODE (TYPE_SIZE_UNIT (callee_type)) != INTEGER_CST)
abort ();
var = copy_decl_for_inlining (result, callee, caller);
DECL_SEEN_IN_BIND_EXPR_P (var) = 1;
DECL_STRUCT_FUNCTION (caller)->unexpanded_var_list
= tree_cons (NULL_TREE, var,
DECL_STRUCT_FUNCTION (caller)->unexpanded_var_list);
/* Do not have the rest of GCC warn about this variable as it should
not be visible to the user. */
TREE_NO_WARNING (var) = 1;
/* Build the use expr. If the return type of the function was
promoted, convert it back to the expected type. */
use = var;
if (!lang_hooks.types_compatible_p (TREE_TYPE (var), caller_type))
use = fold_convert (caller_type, var);
done:
/* Register the VAR_DECL as the equivalent for the RESULT_DECL; that
way, when the RESULT_DECL is encountered, it will be
automatically replaced by the VAR_DECL. */
@ -888,30 +954,8 @@ declare_return_variable (inline_data *id, tree return_slot_addr, tree *use_p)
/* Remember this so we can ignore it in remap_decls. */
id->retvar = var;
/* Build the use expr. If the return type of the function was
promoted, convert it back to the expected type. */
if (return_slot_addr)
/* The function returns through an explicit return slot, not a normal
return value. */
*use_p = NULL_TREE;
else if (TREE_TYPE (var) == TREE_TYPE (TREE_TYPE (fn)))
*use_p = var;
else if (TREE_CODE (var) == INDIRECT_REF)
*use_p = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (fn)),
TREE_OPERAND (var, 0));
else if (TREE_ADDRESSABLE (TREE_TYPE (var)))
abort ();
else
*use_p = build1 (NOP_EXPR, TREE_TYPE (TREE_TYPE (fn)), var);
/* Build the declaration statement if FN does not return an
aggregate. */
if (need_return_decl)
return var;
/* If FN does return an aggregate, there's no need to declare the
return variable; we're using a variable in our caller's frame. */
else
return NULL_TREE;
*use_p = use;
return var;
}
/* Returns nonzero if a function can be inlined as a tree. */
@ -1385,10 +1429,10 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
tree fn;
tree arg_inits;
tree *inlined_body;
tree inline_result;
splay_tree st;
tree args;
tree return_slot_addr;
tree modify_dest;
location_t saved_location;
struct cgraph_edge *edge;
const char *reason;
@ -1517,7 +1561,7 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
statements within the function to jump to. The type of the
statement expression is the return type of the function call. */
stmt = NULL;
expr = build (BIND_EXPR, TREE_TYPE (TREE_TYPE (fn)), NULL_TREE,
expr = build (BIND_EXPR, void_type_node, NULL_TREE,
stmt, make_node (BLOCK));
BLOCK_ABSTRACT_ORIGIN (BIND_EXPR_BLOCK (expr)) = fn;
@ -1586,10 +1630,16 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
|| TREE_CODE (DECL_INITIAL (fn)) != BLOCK)
abort ();
/* Find the lhs to which the result of this call is assigned. */
modify_dest = tsi_stmt (id->tsi);
if (TREE_CODE (modify_dest) == MODIFY_EXPR)
modify_dest = TREE_OPERAND (modify_dest, 0);
else
modify_dest = NULL;
/* Declare the return variable for the function. */
decl = declare_return_variable (id, return_slot_addr, &use_retvar);
if (decl)
declare_inline_vars (expr, decl);
decl = declare_return_variable (id, return_slot_addr,
modify_dest, &use_retvar);
/* After we've initialized the parameters, we insert the body of the
function itself. */
@ -1611,12 +1661,6 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
append_to_statement_list (label, &BIND_EXPR_BODY (expr));
}
/* Finally, mention the returned value so that the value of the
statement-expression is the returned value of the function. */
if (use_retvar)
/* Set TREE_TYPE on BIND_EXPR? */
append_to_statement_list_force (use_retvar, &BIND_EXPR_BODY (expr));
/* Clean up. */
splay_tree_delete (id->decl_map);
id->decl_map = st;
@ -1624,28 +1668,16 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
/* The new expression has side-effects if the old one did. */
TREE_SIDE_EFFECTS (expr) = TREE_SIDE_EFFECTS (t);
/* We want to create a new variable to hold the result of the inlined
body. This new variable needs to be added to the function which we
are inlining into, thus the saving and restoring of
current_function_decl. */
{
tree save_decl = current_function_decl;
current_function_decl = id->node->decl;
inline_result = voidify_wrapper_expr (expr, NULL);
current_function_decl = save_decl;
}
tsi_link_before (&id->tsi, expr, TSI_SAME_STMT);
/* If the inlined function returns a result that we care about,
then we're going to need to splice in a MODIFY_EXPR. Otherwise
the call was a standalone statement and we can just replace it
with the BIND_EXPR inline representation of the called function. */
if (TREE_CODE (tsi_stmt (id->tsi)) != CALL_EXPR)
{
tsi_link_before (&id->tsi, expr, TSI_SAME_STMT);
*tp = inline_result;
}
if (!use_retvar || !modify_dest)
*tsi_stmt_ptr (id->tsi) = build_empty_stmt ();
else
*tp = expr;
*tp = use_retvar;
/* When we gimplify a function call, we may clear TREE_SIDE_EFFECTS on
the call if it is to a "const" function. Thus the copy of
@ -1660,11 +1692,6 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
the toplevel expression. */
recalculate_side_effects (expr);
/* If the value of the new expression is ignored, that's OK. We
don't warn about this for CALL_EXPRs, so we shouldn't warn about
the equivalent inlined version either. */
TREE_USED (*tp) = 1;
/* Update callgraph if needed. */
cgraph_remove_node (edge->callee);