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:
parent
ffb0e73a97
commit
25af851255
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
271
gcc/cp/tree.c
271
gcc/cp/tree.c
|
@ -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. */
|
||||
|
|
Loading…
Reference in New Issue