Make-lang.in (cp/decl.o, cp/tree.o): Depend on tree-inline.h.

* Make-lang.in (cp/decl.o, cp/tree.o): Depend on tree-inline.h.
(cp/pt.o, cp/semantics.o, cp/optimize.o): Likewise.
* cp-tree.h (lang_decl): Moved inlined_fns to tree_decl.
(TREE_READONLY_DECL_P, DECL_INLINED_FNS): Moved to ../tree.h.
(flag_inline_trees): Moved declaration to ../tree-inline.h.
(walk_tree): Moved declaration to ../tree-inline.h.
(walk_tree_without_duplicates, copy_tree_r): Likewise.
(remap_save_expr): Likewise.
* decl.c: Include tree-inline.h.
(lang_mark_tree): Don't mark inlined_fns.
* decl2.c (flag_inline_trees): Moved defn to ../tree-inline.c.
* optimize.c: Include tree-inline.h.
(optimize_inline_calls): Move declaration to ../tree.h, as
non-static.
(remap_decl): Use language-independent constructs and hooks.
(remap_block, copy_body_r, declare_return_variable): Likewise.
(inlinable_function_p): Likewise.  Don't test for
DECL_LANG_SPECIFIC before DECL_INLINED_FNS as inlined_fns is
no longer language-specific.
(optimize_inline_calls): Likewise.  Make it non-static.  Moved
call of dump_function to...
(optimize_function): Here...
(clone_body): New function, extracted from...
(maybe_clone_body): ... here.  Build decl_map locally and pass
it on to clone_body.
* pt.c, semantics.c: Include tree-inline.h.
* tree.c: Likewise.
(cp_walk_subtrees): New language-specific hook for tree inlining.
(cp_cannot_inline_tree_fn, cp_add_pending_fn_decls,
cp_is_overload_p, cp_auto_var_in_fn_p,
cp_copy_res_decl_for_inlining): Likewise.
(walk_tree): Move language-specific constructs into...
(cp_walk_subtrees): this new function.
(copy_tree_r): Use language-independent constructs and hooks.
(init_tree): Initialize tree inlining hooks.
(remap_save_expr): Adjust prototype so that the declaration
does not require the definition of splay_tree.

From-SVN: r46020
This commit is contained in:
Alexandre Oliva 2001-10-05 02:48:47 +00:00 committed by Alexandre Oliva
parent ffb0e73a97
commit 25af851255
9 changed files with 385 additions and 190 deletions

View File

@ -1,3 +1,43 @@
2001-10-04 Alexandre Oliva <aoliva@redhat.com>
* Make-lang.in (cp/decl.o, cp/tree.o): Depend on tree-inline.h.
(cp/pt.o, cp/semantics.o, cp/optimize.o): Likewise.
* cp-tree.h (lang_decl): Moved inlined_fns to tree_decl.
(TREE_READONLY_DECL_P, DECL_INLINED_FNS): Moved to ../tree.h.
(flag_inline_trees): Moved declaration to ../tree-inline.h.
(walk_tree): Moved declaration to ../tree-inline.h.
(walk_tree_without_duplicates, copy_tree_r): Likewise.
(remap_save_expr): Likewise.
* decl.c: Include tree-inline.h.
(lang_mark_tree): Don't mark inlined_fns.
* decl2.c (flag_inline_trees): Moved defn to ../tree-inline.c.
* optimize.c: Include tree-inline.h.
(optimize_inline_calls): Move declaration to ../tree.h, as
non-static.
(remap_decl): Use language-independent constructs and hooks.
(remap_block, copy_body_r, declare_return_variable): Likewise.
(inlinable_function_p): Likewise. Don't test for
DECL_LANG_SPECIFIC before DECL_INLINED_FNS as inlined_fns is
no longer language-specific.
(optimize_inline_calls): Likewise. Make it non-static. Moved
call of dump_function to...
(optimize_function): Here...
(clone_body): New function, extracted from...
(maybe_clone_body): ... here. Build decl_map locally and pass
it on to clone_body.
* pt.c, semantics.c: Include tree-inline.h.
* tree.c: Likewise.
(cp_walk_subtrees): New language-specific hook for tree inlining.
(cp_cannot_inline_tree_fn, cp_add_pending_fn_decls,
cp_is_overload_p, cp_auto_var_in_fn_p,
cp_copy_res_decl_for_inlining): Likewise.
(walk_tree): Move language-specific constructs into...
(cp_walk_subtrees): this new function.
(copy_tree_r): Use language-independent constructs and hooks.
(init_tree): Initialize tree inlining hooks.
(remap_save_expr): Adjust prototype so that the declaration
does not require the definition of splay_tree.
2001-10-03 John David Anglin <dave@hiauly1.hia.nrc.ca>
* rtti.c (get_tinfo_decl): Call typeinfo_in_lib_p with the type used

View File

@ -243,7 +243,7 @@ cp/lex.o: cp/lex.c $(CXX_TREE_H) cp/parse.h flags.h cp/lex.h c-pragma.h \
$(TM_P_H)
cp/decl.o: cp/decl.c $(CXX_TREE_H) flags.h cp/lex.h cp/decl.h stack.h \
output.h $(EXPR_H) except.h toplev.h hash.h $(GGC_H) $(RTL_H) \
cp/operators.def $(TM_P_H)
cp/operators.def $(TM_P_H) tree-inline.h
cp/decl2.o: cp/decl2.c $(CXX_TREE_H) flags.h cp/lex.h cp/decl.h $(EXPR_H) \
output.h except.h toplev.h $(GGC_H) $(RTL_H)
cp/typeck2.o: cp/typeck2.c $(CXX_TREE_H) flags.h toplev.h output.h $(TM_P_H) \
@ -261,7 +261,7 @@ cp/method.o: cp/method.c $(CXX_TREE_H) toplev.h $(GGC_H) $(RTL_H) $(EXPR_H) \
cp/cvt.o: cp/cvt.c $(CXX_TREE_H) cp/decl.h flags.h toplev.h convert.h
cp/search.o: cp/search.c $(CXX_TREE_H) stack.h flags.h toplev.h $(RTL_H)
cp/tree.o: cp/tree.c $(CXX_TREE_H) flags.h toplev.h $(GGC_H) $(RTL_H) \
insn-config.h integrate.h
insn-config.h integrate.h tree-inline.h
cp/ptree.o: cp/ptree.c $(CXX_TREE_H) $(SYSTEM_H)
cp/rtti.o: cp/rtti.c $(CXX_TREE_H) flags.h toplev.h
cp/except.o: cp/except.c $(CXX_TREE_H) flags.h $(RTL_H) except.h toplev.h \
@ -270,14 +270,15 @@ cp/expr.o: cp/expr.c $(CXX_TREE_H) $(RTL_H) flags.h $(EXPR_H) toplev.h \
except.h $(TM_P_H)
cp/xref.o: cp/xref.c $(CXX_TREE_H) input.h toplev.h
cp/pt.o: cp/pt.c $(CXX_TREE_H) cp/decl.h cp/parse.h cp/lex.h toplev.h \
$(GGC_H) $(RTL_H) except.h
$(GGC_H) $(RTL_H) except.h tree-inline.h
cp/error.o: cp/error.c $(CXX_TREE_H) toplev.h diagnostic.h flags.h real.h
cp/repo.o: cp/repo.c $(CXX_TREE_H) toplev.h $(GGC_H) diagnostic.h
cp/semantics.o: cp/semantics.c $(CXX_TREE_H) cp/lex.h except.h toplev.h \
flags.h $(GGC_H) debug.h output.h $(RTL_H) $(TIMEVAR_H) $(EXPR_H)
flags.h $(GGC_H) debug.h output.h $(RTL_H) $(TIMEVAR_H) $(EXPR_H) \
tree-inline.h
cp/dump.o: cp/dump.c $(CXX_TREE_H) c-dump.h
cp/optimize.o: cp/optimize.c $(CXX_TREE_H) rtl.h integrate.h insn-config.h \
input.h $(PARAMS_H) debug.h
input.h $(PARAMS_H) debug.h tree-inline.h
cp/mangle.o: cp/mangle.c $(CXX_TREE_H) toplev.h
cp/parse.o: cp/parse.c $(CXX_TREE_H) flags.h cp/lex.h except.h output.h \

View File

@ -1758,10 +1758,6 @@ struct lang_decl
/* In a FUNCTION_DECL, this is DECL_CLONED_FUNCTION. */
tree cloned_function;
/* In a FUNCTION_DECL, these are function data which is to be kept
as long as FUNCTION_DECL is kept. */
tree inlined_fns;
union
{
tree sorted_fields;
@ -1778,10 +1774,6 @@ struct lang_decl
#define DEFARG_POINTER(NODE) (DEFAULT_ARG_CHECK(NODE)->identifier.id.str)
/* Non-zero if NODE is a _DECL with TREE_READONLY set. */
#define TREE_READONLY_DECL_P(NODE) \
(TREE_READONLY (NODE) && DECL_P (NODE))
/* DECL_NEEDED_P holds of a declaration when we need to emit its
definition. This is true when the back-end tells us that
the symbol has been referenced in the generated code. If, however,
@ -1888,10 +1880,6 @@ struct lang_decl
#define DECL_CLONED_FUNCTION(NODE) \
(DECL_LANG_SPECIFIC (NODE)->cloned_function)
/* List of FUNCION_DECLs inlined into this function's body. */
#define DECL_INLINED_FNS(NODE) \
(DECL_LANG_SPECIFIC (NODE)->inlined_fns)
/* Nonzero if NODE has DECL_DISCRIMINATOR and not DECL_ACCESS. */
#define DECL_DISCRIMINATOR_P(NODE) \
(TREE_CODE (NODE) == VAR_DECL \
@ -3262,13 +3250,6 @@ extern int flag_implicit_templates;
extern int flag_weak;
/* 0 if we should not perform inlining.
1 if we should expand functions calls inline at the tree level.
2 if we should consider *all* functions to be inline
candidates. */
extern int flag_inline_trees;
/* Nonzero if we're done parsing and into end-of-file activities. */
extern int at_eof;
@ -4197,18 +4178,9 @@ extern void debug_binfo PARAMS ((tree));
extern tree build_dummy_object PARAMS ((tree));
extern tree maybe_dummy_object PARAMS ((tree, tree *));
extern int is_dummy_object PARAMS ((tree));
extern tree walk_tree PARAMS ((tree *,
walk_tree_fn,
void *,
htab_t));
extern tree walk_tree_without_duplicates PARAMS ((tree *,
walk_tree_fn,
void *));
extern tree copy_tree_r PARAMS ((tree *, int *, void *));
extern const struct attribute_spec cp_attribute_table[];
extern tree make_ptrmem_cst PARAMS ((tree, tree));
extern tree cp_build_qualified_type_real PARAMS ((tree, int, int));
extern void remap_save_expr PARAMS ((tree *, splay_tree, tree, int *));
#define cp_build_qualified_type(TYPE, QUALS) \
cp_build_qualified_type_real ((TYPE), (QUALS), /*complain=*/1)
extern tree build_shared_int_cst PARAMS ((int));

View File

@ -35,6 +35,7 @@ Boston, MA 02111-1307, USA. */
#include "expr.h"
#include "flags.h"
#include "cp-tree.h"
#include "tree-inline.h"
#include "decl.h"
#include "lex.h"
#include "output.h"
@ -14479,7 +14480,6 @@ lang_mark_tree (t)
ggc_mark_tree (ld->befriending_classes);
ggc_mark_tree (ld->context);
ggc_mark_tree (ld->cloned_function);
ggc_mark_tree (ld->inlined_fns);
if (TREE_CODE (t) == TYPE_DECL)
ggc_mark_tree (ld->u.sorted_fields);
else if (TREE_CODE (t) == FUNCTION_DECL

View File

@ -378,13 +378,6 @@ int flag_weak = 1;
int flag_use_cxa_atexit;
/* 0 if we should not perform inlining.
1 if we should expand functions calls inline at the tree level.
2 if we should consider *all* functions to be inline
candidates. */
int flag_inline_trees = 0;
/* Maximum template instantiation depth. This limit is rather
arbitrary, but it exists to limit the time it takes to notice
infinite template instantiations. */

View File

@ -33,6 +33,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "params.h"
#include "hashtab.h"
#include "debug.h"
#include "tree-inline.h"
/* To Do:
@ -99,7 +100,6 @@ static int inlinable_function_p PARAMS ((tree, inline_data *));
static tree remap_decl PARAMS ((tree, inline_data *));
static void remap_block PARAMS ((tree, tree, inline_data *));
static void copy_scope_stmt PARAMS ((tree *, int *, inline_data *));
static void optimize_inline_calls PARAMS ((tree));
static tree calls_setjmp_r PARAMS ((tree *, int *, void *));
static void update_cloned_parm PARAMS ((tree, tree));
static void dump_function PARAMS ((enum tree_dump_index, tree));
@ -121,7 +121,7 @@ remap_decl (decl, id)
/* We only remap local variables in the current function. */
fn = VARRAY_TOP_TREE (id->fns);
if (!nonstatic_local_decl_p (decl) || DECL_CONTEXT (decl) != fn)
if (! LANG_AUTO_VAR_IN_FN_P (decl, fn))
return NULL_TREE;
/* See if we have remapped this declaration. */
@ -151,8 +151,8 @@ remap_decl (decl, id)
copy_body_r, id, NULL);
}
if (!DECL_NAME (t) && TREE_TYPE (t)
&& ANON_AGGR_TYPE_P (TREE_TYPE ((t))))
if (! DECL_NAME (t) && TREE_TYPE (t)
&& LANG_ANON_AGGR_TYPE_P (TREE_TYPE (t)))
{
/* For a VAR_DECL of anonymous type, we must also copy the
member VAR_DECLS here and rechain the
@ -165,7 +165,8 @@ remap_decl (decl, id)
{
tree member = remap_decl (TREE_VALUE (src), id);
my_friendly_assert (!TREE_PURPOSE (src), 20010529);
if (TREE_PURPOSE (src))
abort ();
members = tree_cons (NULL, member, members);
}
DECL_ANON_UNION_ELEMS (t) = nreverse (members);
@ -277,7 +278,8 @@ remap_block (scope_stmt, decls, id)
/* Find this block in the table of remapped things. */
n = splay_tree_lookup (id->decl_map,
(splay_tree_key) SCOPE_STMT_BLOCK (scope_stmt));
my_friendly_assert (n != NULL, 19991203);
if (! n)
abort ();
SCOPE_STMT_BLOCK (scope_stmt) = (tree) n->value;
}
}
@ -322,12 +324,14 @@ copy_body_r (tp, walk_subtrees, data)
id = (inline_data *) data;
fn = VARRAY_TOP_TREE (id->fns);
#if 0
/* All automatic variables should have a DECL_CONTEXT indicating
what function they come from. */
if ((TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == LABEL_DECL)
&& DECL_NAMESPACE_SCOPE_P (*tp))
my_friendly_assert (DECL_EXTERNAL (*tp) || TREE_STATIC (*tp),
19991113);
if (! DECL_EXTERNAL (*tp) && ! TREE_STATIC (*tp))
abort ();
#endif
/* If this is a RETURN_STMT, change it into an EXPR_STMT and a
GOTO_STMT with the RET_LABEL as its target. */
@ -359,26 +363,29 @@ copy_body_r (tp, walk_subtrees, data)
variables. We don't want to copy static variables; there's only
one of those, no matter how many times we inline the containing
function. */
else if (nonstatic_local_decl_p (*tp) && DECL_CONTEXT (*tp) == fn)
else if (LANG_AUTO_VAR_IN_FN_P (*tp, fn))
{
tree new_decl;
/* Remap the declaration. */
new_decl = remap_decl (*tp, id);
my_friendly_assert (new_decl != NULL_TREE, 19991203);
if (! new_decl)
abort ();
/* Replace this variable with the copy. */
STRIP_TYPE_NOPS (new_decl);
*tp = new_decl;
}
#if 0
else if (nonstatic_local_decl_p (*tp)
&& DECL_CONTEXT (*tp) != VARRAY_TREE (id->fns, 0))
my_friendly_abort (0);
abort ();
#endif
else if (TREE_CODE (*tp) == SAVE_EXPR)
remap_save_expr (tp, id->decl_map, VARRAY_TREE (id->fns, 0),
walk_subtrees);
else if (TREE_CODE (*tp) == UNSAVE_EXPR)
/* UNSAVE_EXPRs should not be generated until expansion time. */
my_friendly_abort (19991113);
abort ();
/* For a SCOPE_STMT, we must copy the associated block so that we
can write out debugging information for the inlined variables. */
else if (TREE_CODE (*tp) == SCOPE_STMT && !id->in_target_cleanup_p)
@ -398,8 +405,7 @@ copy_body_r (tp, walk_subtrees, data)
}
else if (TREE_CODE (*tp) == MODIFY_EXPR
&& TREE_OPERAND (*tp, 0) == TREE_OPERAND (*tp, 1)
&& nonstatic_local_decl_p (TREE_OPERAND (*tp, 0))
&& DECL_CONTEXT (TREE_OPERAND (*tp, 0)) == fn)
&& LANG_AUTO_VAR_IN_FN_P (TREE_OPERAND (*tp, 0), fn))
{
/* Some assignments VAR = VAR; don't generate any rtl code
and thus don't count as variable modification. Avoid
@ -561,7 +567,7 @@ declare_return_variable (id, use_stmt)
tree fn = VARRAY_TOP_TREE (id->fns);
tree result = DECL_RESULT (fn);
tree var;
int aggregate_return_p;
int need_return_decl = 1;
/* We don't need to do anything for functions that don't return
anything. */
@ -571,29 +577,9 @@ declare_return_variable (id, use_stmt)
return NULL_TREE;
}
/* Figure out whether or not FN returns an aggregate. */
aggregate_return_p = IS_AGGR_TYPE (TREE_TYPE (result));
/* 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)
{
my_friendly_assert (VARRAY_ACTIVE_SIZE (id->target_exprs) != 0,
20000430);
var = TREE_OPERAND (VARRAY_TOP_TREE (id->target_exprs), 0);
my_friendly_assert
(same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (var),
TREE_TYPE (result)),
20000430);
}
/* Otherwise, make an appropriate copy. */
else
var = copy_decl_for_inlining (result, fn, VARRAY_TREE (id->fns, 0));
var = LANG_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
@ -602,29 +588,12 @@ declare_return_variable (id, use_stmt)
(splay_tree_key) result,
(splay_tree_value) var);
if (DECL_SAVED_FUNCTION_DATA (fn))
{
tree nrv = DECL_SAVED_FUNCTION_DATA (fn)->x_return_value;
if (nrv)
{
/* We have a named return value; copy the name and source
position so we can get reasonable debugging information, and
register the return variable as its equivalent. */
DECL_NAME (var) = DECL_NAME (nrv);
DECL_SOURCE_FILE (var) = DECL_SOURCE_FILE (nrv);
DECL_SOURCE_LINE (var) = DECL_SOURCE_LINE (nrv);
splay_tree_insert (id->decl_map,
(splay_tree_key) nrv,
(splay_tree_value) var);
}
}
/* Build the USE_STMT. */
*use_stmt = build_stmt (EXPR_STMT, var);
/* Build the declaration statement if FN does not return an
aggregate. */
if (!aggregate_return_p)
if (need_return_decl)
return build_stmt (DECL_STMT, 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. */
@ -656,12 +625,11 @@ inlinable_function_p (fn, id)
it. */
else if (!DECL_INLINE (fn))
;
/* We can't inline varargs functions. */
else if (varargs_function_p (fn))
;
/* We can't inline functions that are too big.
* Only allow a single function to eat up half of our budget. */
else if (DECL_NUM_STMTS (fn) * INSNS_PER_STMT > MAX_INLINE_INSNS / 2)
/* We can't inline functions that are too big. Only allow a single
function to eat up half of our budget. Make special allowance
for extern inline functions, though. */
else if (! LANG_DISREGARD_INLINE_LIMITS (fn)
&& DECL_NUM_STMTS (fn) * INSNS_PER_STMT > MAX_INLINE_INSNS / 2)
;
/* All is well. We can inline this function. Traditionally, GCC
has refused to inline functions using alloca, or functions whose
@ -675,27 +643,26 @@ inlinable_function_p (fn, id)
/* Even if this function is not itself too big to inline, it might
be that we've done so much inlining already that we don't want to
risk too much inlining any more and thus halve the acceptable size. */
if ((DECL_NUM_STMTS (fn) + id->inlined_stmts) * INSNS_PER_STMT
> MAX_INLINE_INSNS
risk too much inlining any more and thus halve the acceptable
size. */
if (! LANG_DISREGARD_INLINE_LIMITS (fn)
&& ((DECL_NUM_STMTS (fn) + id->inlined_stmts) * INSNS_PER_STMT
> MAX_INLINE_INSNS)
&& DECL_NUM_STMTS (fn) * INSNS_PER_STMT > MAX_INLINE_INSNS / 4)
inlinable = 0;
/* We can inline a template instantiation only if it's fully
instantiated. */
if (inlinable
&& DECL_TEMPLATE_INFO (fn)
&& TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn)))
{
fn = instantiate_decl (fn, /*defer_ok=*/0);
inlinable = !TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn));
}
if (inlinable && LANG_CANNOT_INLINE_TREE_FN (&fn))
inlinable = 0;
/* If we don't have the function body available, we can't inline
it. */
if (!DECL_SAVED_TREE (fn))
inlinable = 0;
/* Check again, language hooks may have modified it. */
if (! inlinable || DECL_UNINLINABLE (fn))
return 0;
/* Don't do recursive inlining, either. We don't record this in
DECL_UNINLINABLE; we may be able to inline this function later. */
if (inlinable)
@ -706,7 +673,7 @@ inlinable_function_p (fn, id)
if (VARRAY_TREE (id->fns, i) == fn)
return 0;
if (inlinable && DECL_LANG_SPECIFIC (fn) && DECL_INLINED_FNS (fn))
if (inlinable && DECL_INLINED_FNS (fn))
{
int j;
tree inlined_fns = DECL_INLINED_FNS (fn);
@ -808,7 +775,7 @@ expand_call_inline (tp, walk_subtrees, data)
for the return statements within the function to jump to. The
type of the statement expression is the return type of the
function call. */
expr = build_min (STMT_EXPR, TREE_TYPE (TREE_TYPE (fn)), NULL_TREE);
expr = build1 (STMT_EXPR, TREE_TYPE (TREE_TYPE (fn)), NULL_TREE);
/* Local declarations will be replaced by their equivalents in this
map. */
@ -832,7 +799,7 @@ expand_call_inline (tp, walk_subtrees, data)
/* Record the function we are about to inline if optimize_function
has not been called on it yet and we don't have it in the list. */
if (DECL_LANG_SPECIFIC (fn) && !DECL_INLINED_FNS (fn))
if (! DECL_INLINED_FNS (fn))
{
int i;
@ -878,9 +845,9 @@ expand_call_inline (tp, walk_subtrees, data)
/* Close the block for the parameters. */
scope_stmt = build_stmt (SCOPE_STMT, DECL_INITIAL (fn));
SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;
my_friendly_assert (DECL_INITIAL (fn)
&& TREE_CODE (DECL_INITIAL (fn)) == BLOCK,
19991203);
if (! DECL_INITIAL (fn)
|| TREE_CODE (DECL_INITIAL (fn)) != BLOCK)
abort ();
remap_block (scope_stmt, NULL_TREE, id);
STMT_EXPR_STMT (expr)
= chainon (STMT_EXPR_STMT (expr), scope_stmt);
@ -957,13 +924,12 @@ expand_calls_inline (tp, id)
/* Expand calls to inline functions in the body of FN. */
static void
void
optimize_inline_calls (fn)
tree fn;
{
inline_data id;
tree prev_fn;
struct saved_scope *s;
/* Clear out ID. */
memset (&id, 0, sizeof (id));
@ -978,12 +944,8 @@ optimize_inline_calls (fn)
VARRAY_PUSH_TREE (id.fns, current_function_decl);
prev_fn = current_function_decl;
}
for (s = scope_chain; s; s = s->prev)
if (s->function_decl && s->function_decl != prev_fn)
{
VARRAY_PUSH_TREE (id.fns, s->function_decl);
prev_fn = s->function_decl;
}
prev_fn = LANG_ADD_PENDING_FN_DECLS (&id.fns, prev_fn);
/* Create the stack of TARGET_EXPRs. */
VARRAY_TREE_INIT (id.target_exprs, 32, "target_exprs");
@ -1014,8 +976,6 @@ optimize_inline_calls (fn)
DECL_INLINED_FNS (fn) = ifn;
}
VARRAY_FREE (id.inlined_fns);
dump_function (TDI_inlined, fn);
}
/* Optimize the body of FN. */
@ -1043,7 +1003,11 @@ optimize_function (fn)
optimization, (c) virtual functions are rarely inlineable,
and (d) ASM_OUTPUT_MI_THUNK is there to DTRT anyway. */
&& !DECL_THUNK_P (fn))
optimize_inline_calls (fn);
{
optimize_inline_calls (fn);
dump_function (TDI_inlined, fn);
}
/* Undo the call to ggc_push_context above. */
--function_depth;
@ -1106,6 +1070,38 @@ update_cloned_parm (parm, cloned_parm)
DECL_SOURCE_LINE (cloned_parm) = DECL_SOURCE_LINE (parm);
}
/* FN is a function that has a complete body, and CLONE is a function
whose body is to be set to a copy of FN, mapping argument
declarations according to the ARG_MAP splay_tree. */
void
clone_body (clone, fn, arg_map)
tree clone, fn;
void *arg_map;
{
inline_data id;
/* Clone the body, as if we were making an inline call. But, remap
the parameters in the callee to the parameters of caller. If
there's an in-charge parameter, map it to an appropriate
constant. */
memset (&id, 0, sizeof (id));
VARRAY_TREE_INIT (id.fns, 2, "fns");
VARRAY_PUSH_TREE (id.fns, clone);
VARRAY_PUSH_TREE (id.fns, fn);
id.decl_map = (splay_tree)arg_map;
/* Cloning is treated slightly differently from inlining. Set
CLONING_P so that it's clear which operation we're performing. */
id.cloning_p = true;
/* Actually copy the body. */
TREE_CHAIN (DECL_SAVED_TREE (clone)) = copy_body (&id);
/* Clean up. */
VARRAY_FREE (id.fns);
}
/* FN is a function that has a complete body. Clone the body as
necessary. Returns non-zero if there's no longer any need to
process the main body. */
@ -1114,7 +1110,6 @@ int
maybe_clone_body (fn)
tree fn;
{
inline_data id;
tree clone;
int first = 1;
@ -1135,6 +1130,7 @@ maybe_clone_body (fn)
tree parm;
tree clone_parm;
int parmno;
splay_tree decl_map;
/* Update CLONE's source position information to match FN's. */
DECL_SOURCE_FILE (clone) = DECL_SOURCE_FILE (fn);
@ -1178,22 +1174,8 @@ maybe_clone_body (fn)
push_to_top_level ();
start_function (NULL_TREE, clone, NULL_TREE, SF_PRE_PARSED);
/* Just clone the body, as if we were making an inline call.
But, remap the parameters in the callee to the parameters of
caller. If there's an in-charge parameter, map it to an
appropriate constant. */
memset (&id, 0, sizeof (id));
VARRAY_TREE_INIT (id.fns, 2, "fns");
VARRAY_PUSH_TREE (id.fns, clone);
VARRAY_PUSH_TREE (id.fns, fn);
/* Cloning is treated slightly differently from inlining. Set
CLONING_P so that its clear which operation we're performing. */
id.cloning_p = true;
/* Remap the parameters. */
id.decl_map = splay_tree_new (splay_tree_compare_pointers,
NULL, NULL);
decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
for (parmno = 0,
parm = DECL_ARGUMENTS (fn),
clone_parm = DECL_ARGUMENTS (clone);
@ -1206,7 +1188,7 @@ maybe_clone_body (fn)
{
tree in_charge;
in_charge = in_charge_arg_for_name (DECL_NAME (clone));
splay_tree_insert (id.decl_map,
splay_tree_insert (decl_map,
(splay_tree_key) parm,
(splay_tree_value) in_charge);
}
@ -1219,7 +1201,7 @@ maybe_clone_body (fn)
if (DECL_HAS_VTT_PARM_P (clone))
{
DECL_ABSTRACT_ORIGIN (clone_parm) = parm;
splay_tree_insert (id.decl_map,
splay_tree_insert (decl_map,
(splay_tree_key) parm,
(splay_tree_value) clone_parm);
clone_parm = TREE_CHAIN (clone_parm);
@ -1227,7 +1209,7 @@ maybe_clone_body (fn)
/* Otherwise, map the VTT parameter to `NULL'. */
else
{
splay_tree_insert (id.decl_map,
splay_tree_insert (decl_map,
(splay_tree_key) parm,
(splay_tree_value) null_pointer_node);
}
@ -1236,23 +1218,22 @@ maybe_clone_body (fn)
function. */
else
{
splay_tree_insert (id.decl_map,
splay_tree_insert (decl_map,
(splay_tree_key) parm,
(splay_tree_value) clone_parm);
clone_parm = TREE_CHAIN (clone_parm);
}
}
/* Actually copy the body. */
TREE_CHAIN (DECL_SAVED_TREE (clone)) = copy_body (&id);
/* Clone the body. */
clone_body (clone, fn, decl_map);
/* There are as many statements in the clone as in the
original. */
DECL_NUM_STMTS (clone) = DECL_NUM_STMTS (fn);
/* Clean up. */
splay_tree_delete (id.decl_map);
VARRAY_FREE (id.fns);
splay_tree_delete (decl_map);
/* Now, expand this function into RTL, if appropriate. */
finish_function (0);

View File

@ -29,10 +29,10 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
#include "system.h"
#include "obstack.h"
#include "tree.h"
#include "flags.h"
#include "cp-tree.h"
#include "tree-inline.h"
#include "decl.h"
#include "parse.h"
#include "lex.h"

View File

@ -28,6 +28,7 @@
#include "system.h"
#include "tree.h"
#include "cp-tree.h"
#include "tree-inline.h"
#include "except.h"
#include "lex.h"
#include "toplev.h"

View File

@ -31,6 +31,7 @@ Boston, MA 02111-1307, USA. */
#include "ggc.h"
#include "insn-config.h"
#include "integrate.h"
#include "tree-inline.h"
static tree bot_manip PARAMS ((tree *, int *, void *));
static tree bot_replace PARAMS ((tree *, int *, void *));
@ -49,6 +50,12 @@ static tree count_trees_r PARAMS ((tree *, int *, void *));
static tree verify_stmt_tree_r PARAMS ((tree *, int *, void *));
static tree find_tree_r PARAMS ((tree *, int *, void *));
extern int cp_statement_code_p PARAMS ((enum tree_code));
static treeopt_walk_subtrees_type cp_walk_subtrees;
static treeopt_cannot_inline_tree_fn_type cp_cannot_inline_tree_fn;
static treeopt_add_pending_fn_decls_type cp_add_pending_fn_decls;
static treeopt_tree_chain_matters_p_type cp_is_overload_p;
static treeopt_auto_var_in_fn_p_type cp_auto_var_in_fn_p;
static treeopt_copy_res_decl_for_inlining_type cp_copy_res_decl_for_inlining;
static tree handle_java_interface_attribute PARAMS ((tree *, tree, tree, int, bool *));
static tree handle_com_interface_attribute PARAMS ((tree *, tree, tree, int, bool *));
@ -1154,12 +1161,13 @@ bind_template_template_parm (t, newargs)
once. */
tree
walk_tree (tp, func, data, htab)
walk_tree (tp, func, data, htab_)
tree *tp;
walk_tree_fn func;
void *data;
htab_t htab;
void *htab_;
{
htab_t htab = (htab_t) htab_;
enum tree_code code;
int walk_subtrees;
tree result;
@ -1204,7 +1212,8 @@ walk_tree (tp, func, data, htab)
interesting below this point in the tree. */
if (!walk_subtrees)
{
if (statement_code_p (code) || code == TREE_LIST || code == OVERLOAD)
if (statement_code_p (code) || code == TREE_LIST
|| LANG_TREE_CHAIN_MATTERS_P (*tp))
/* But we still need to check our siblings. */
return walk_tree (&TREE_CHAIN (*tp), func, data, htab);
else
@ -1268,6 +1277,10 @@ walk_tree (tp, func, data, htab)
return NULL_TREE;
}
result = LANG_WALK_SUBTREES (tp, &walk_subtrees, func, data, htab);
if (result || ! walk_subtrees)
return result;
/* Not one of the easy cases. We must explicitly go through the
children. */
switch (code)
@ -1277,47 +1290,29 @@ walk_tree (tp, func, data, htab)
case INTEGER_CST:
case REAL_CST:
case STRING_CST:
case DEFAULT_ARG:
case TEMPLATE_TEMPLATE_PARM:
case BOUND_TEMPLATE_TEMPLATE_PARM:
case TEMPLATE_PARM_INDEX:
case TEMPLATE_TYPE_PARM:
case REAL_TYPE:
case COMPLEX_TYPE:
case VECTOR_TYPE:
case VOID_TYPE:
case BOOLEAN_TYPE:
case TYPENAME_TYPE:
case UNION_TYPE:
case ENUMERAL_TYPE:
case TYPEOF_TYPE:
case BLOCK:
case RECORD_TYPE:
/* None of thse have subtrees other than those already walked
above. */
break;
case PTRMEM_CST:
WALK_SUBTREE (TREE_TYPE (*tp));
break;
case POINTER_TYPE:
case REFERENCE_TYPE:
WALK_SUBTREE (TREE_TYPE (*tp));
break;
case TREE_LIST:
/* A BASELINK_P's TREE_PURPOSE is a BINFO, and hence circular. */
if (!BASELINK_P (*tp))
WALK_SUBTREE (TREE_PURPOSE (*tp));
WALK_SUBTREE (TREE_VALUE (*tp));
WALK_SUBTREE (TREE_CHAIN (*tp));
break;
case OVERLOAD:
WALK_SUBTREE (OVL_FUNCTION (*tp));
WALK_SUBTREE (OVL_CHAIN (*tp));
break;
case TREE_VEC:
{
int len = TREE_VEC_LENGTH (*tp);
@ -1365,13 +1360,8 @@ walk_tree (tp, func, data, htab)
WALK_SUBTREE (TYPE_OFFSET_BASETYPE (*tp));
break;
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (*tp))
WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
break;
default:
my_friendly_abort (19990803);
abort ();
}
/* We didn't find what we were looking for. */
@ -1539,7 +1529,7 @@ copy_tree_r (tp, walk_subtrees, data)
|| TREE_CODE_CLASS (code) == 's'
|| code == TREE_LIST
|| code == TREE_VEC
|| code == OVERLOAD)
|| LANG_TREE_CHAIN_MATTERS_P (*tp))
{
/* Because the chain gets clobbered when we make a copy, we save it
here. */
@ -1550,7 +1540,8 @@ copy_tree_r (tp, walk_subtrees, data)
/* Now, restore the chain, if appropriate. That will cause
walk_tree to walk into the chain as well. */
if (code == PARM_DECL || code == TREE_LIST || code == OVERLOAD
if (code == PARM_DECL || code == TREE_LIST
|| LANG_TREE_CHAIN_MATTERS_P (*tp)
|| statement_code_p (code))
TREE_CHAIN (*tp) = chain;
@ -2344,12 +2335,227 @@ make_ptrmem_cst (type, member)
return ptrmem_cst;
}
/* Apply FUNC to all language-specific sub-trees of TP in a pre-order
traversal. Called from walk_tree(). */
static tree
cp_walk_subtrees (tp, walk_subtrees_p, func, data, htab)
tree *tp;
int *walk_subtrees_p;
walk_tree_fn func;
void *data;
void *htab;
{
enum tree_code code = TREE_CODE (*tp);
tree result;
#define WALK_SUBTREE(NODE) \
do \
{ \
result = walk_tree (&(NODE), func, data, htab); \
if (result) \
return result; \
} \
while (0)
/* Not one of the easy cases. We must explicitly go through the
children. */
switch (code)
{
case DEFAULT_ARG:
case TEMPLATE_TEMPLATE_PARM:
case BOUND_TEMPLATE_TEMPLATE_PARM:
case TEMPLATE_PARM_INDEX:
case TEMPLATE_TYPE_PARM:
case TYPENAME_TYPE:
case TYPEOF_TYPE:
/* None of thse have subtrees other than those already walked
above. */
*walk_subtrees_p = 0;
break;
case PTRMEM_CST:
WALK_SUBTREE (TREE_TYPE (*tp));
*walk_subtrees_p = 0;
break;
case TREE_LIST:
/* A BASELINK_P's TREE_PURPOSE is a BINFO, and hence circular. */
if (!BASELINK_P (*tp))
WALK_SUBTREE (TREE_PURPOSE (*tp));
break;
case OVERLOAD:
WALK_SUBTREE (OVL_FUNCTION (*tp));
WALK_SUBTREE (OVL_CHAIN (*tp));
*walk_subtrees_p = 0;
break;
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (*tp))
WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
break;
default:
break;
}
/* We didn't find what we were looking for. */
return NULL_TREE;
#undef WALK_SUBTREE
}
/* Decide whether there are language-specific reasons to not inline a
function as a tree. */
static int
cp_cannot_inline_tree_fn (fnp)
tree *fnp;
{
tree fn = *fnp;
/* We can inline a template instantiation only if it's fully
instantiated. */
if (DECL_TEMPLATE_INFO (fn)
&& TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn)))
{
fn = *fnp = instantiate_decl (fn, /*defer_ok=*/0);
return TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn));
}
if (varargs_function_p (fn))
{
DECL_UNINLINABLE (fn) = 1;
return 1;
}
if (! function_attribute_inlinable_p (fn))
{
DECL_UNINLINABLE (fn) = 1;
return 1;
}
return 0;
}
/* Add any pending functions other than the current function (already
handled by the caller), that thus cannot be inlined, to FNS_P, then
return the latest function added to the array, PREV_FN. */
static tree
cp_add_pending_fn_decls (fns_p, prev_fn)
void *fns_p;
tree prev_fn;
{
varray_type *fnsp = (varray_type *)fns_p;
struct saved_scope *s;
for (s = scope_chain; s; s = s->prev)
if (s->function_decl && s->function_decl != prev_fn)
{
VARRAY_PUSH_TREE (*fnsp, s->function_decl);
prev_fn = s->function_decl;
}
return prev_fn;
}
/* Determine whether a tree node is an OVERLOAD node. Used to decide
whether to copy a node or to preserve its chain when inlining a
function. */
static int
cp_is_overload_p (t)
tree t;
{
return TREE_CODE (t) == OVERLOAD;
}
/* Determine whether VAR is a declaration of an automatic variable in
function FN. */
static int
cp_auto_var_in_fn_p (var, fn)
tree var, fn;
{
return (DECL_P (var) && DECL_CONTEXT (var) == 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. */
static 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 ();
}
/* Otherwise, make an appropriate copy. */
else
var = copy_decl_for_inlining (result, fn, caller);
if (DECL_SAVED_FUNCTION_DATA (fn))
{
tree nrv = DECL_SAVED_FUNCTION_DATA (fn)->x_return_value;
if (nrv)
{
/* We have a named return value; copy the name and source
position so we can get reasonable debugging information, and
register the return variable as its equivalent. */
DECL_NAME (var) = DECL_NAME (nrv);
DECL_SOURCE_FILE (var) = DECL_SOURCE_FILE (nrv);
DECL_SOURCE_LINE (var) = DECL_SOURCE_LINE (nrv);
splay_tree_insert (decl_map,
(splay_tree_key) nrv,
(splay_tree_value) var);
}
}
return var;
}
/* Initialize tree.c. */
void
init_tree ()
{
make_lang_type_fn = cp_make_lang_type;
lang_walk_subtrees = cp_walk_subtrees;
lang_cannot_inline_tree_fn = cp_cannot_inline_tree_fn;
lang_add_pending_fn_decls = cp_add_pending_fn_decls;
lang_tree_chain_matters_p = cp_is_overload_p;
lang_auto_var_in_fn_p = cp_auto_var_in_fn_p;
lang_copy_res_decl_for_inlining = cp_copy_res_decl_for_inlining;
lang_unsave = cp_unsave;
lang_statement_code_p = cp_statement_code_p;
lang_set_decl_assembler_name = mangle_decl;
@ -2365,12 +2571,13 @@ init_tree ()
ST. FN is the function into which the copy will be placed. */
void
remap_save_expr (tp, st, fn, walk_subtrees)
remap_save_expr (tp, st_, fn, walk_subtrees)
tree *tp;
splay_tree st;
void *st_;
tree fn;
int *walk_subtrees;
{
splay_tree st = (splay_tree) st_;
splay_tree_node n;
/* See if we already encountered this SAVE_EXPR. */