From 25af8512559873d4b6e67d27a07f504a585b6037 Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Fri, 5 Oct 2001 02:48:47 +0000 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 40 +++++++ gcc/cp/Make-lang.in | 11 +- gcc/cp/cp-tree.h | 28 ----- gcc/cp/decl.c | 2 +- gcc/cp/decl2.c | 7 -- gcc/cp/optimize.c | 213 ++++++++++++++++------------------ gcc/cp/pt.c | 2 +- gcc/cp/semantics.c | 1 + gcc/cp/tree.c | 271 ++++++++++++++++++++++++++++++++++++++------ 9 files changed, 385 insertions(+), 190 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c23768ee078..2926e129494 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,43 @@ +2001-10-04 Alexandre Oliva + + * 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 * rtti.c (get_tinfo_decl): Call typeinfo_in_lib_p with the type used diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 4fe7e8752b4..65a16063eb6 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -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 \ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b4fc016f46c..98e747da6ff 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.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)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 905784e59fe..0dfd8d65d32 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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 diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index ee8f37900f1..0ab9299244e 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -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. */ diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index 95d02b70c34..bbc555bf6a9 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -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); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 292513fb43e..e29a738d361 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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" diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 6564f8e4169..ec7b968f046 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -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" diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 32783adc728..ec51eaa7e41 100644 --- a/gcc/cp/tree.c +++ b/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. */