diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f089e4fffe8..c020d438e6f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,73 @@ +1999-11-25 Mark Mitchell + + * Make-lang.in (CXX_SRCS): Add optimize.c. + * Makefile.in (CXX_OBJS): Add optimize.o. + (CXX_TREE_H): Add splay-tree.h, system.h, and $(CONFIG_H). + (spew.o, lex.o, decl.o, decl2.o, typeck2.o, typeck.o): Adjust. + (class.o, call.o, friend.o, init.o, method.o, cvt.o): Likewise. + (search.o, tree.o, ptree.o, rtti.o, except.o, expr.o): Likewise. + (xref.o, pt.o, error.o, errfn.o, repo.o, semantics.o): Likewise. + (dump.o): Likewise. + (optimize.o): New target. + * class.c: Don't include splay-tree.h. + * cp-tree.def (CTOR_COMPLETE): Rename to CTOR_STMT. + * cp-tree.h: Include splay-tree.h. + (DECL_UNINLINABLE): New macro. + (CTOR_BEGIN_P, CTOR_END_P): New macros. + (flag_inline_trees): New variable. + (local_variable_p): New function. + (nonstatic_local_decl_p): Likewise. + (optimize_function): Likewise. + (cplus_unsave_expr_now): Remove. + (copy_tree_r): Declare. + (remap_save_expr): Likewise. + * decl.c (local_variable_p): Don't + make it static. + (local_variable_p_walkfn): New function. + (make_rtl_for_local_static): Remove code to try to avoid writing + out static constants. + (emit_local_var): Fix indentation. + (nonstatic_local_decl_p): New function. + (check_default_argument): Use local_variable_p_walkfn, not + local_variable_p, when walking the tree. + (start_function): Set the DECL_CONTEXT for automatically generated + labels. + (finish_constructor_body): Use CTOR_STMT to mark the end of a + constructor. + * decl2.c: Don't include splay-tree.h. + (flag_inline_trees): Define. + * dump.c: Don't include + splay-tree.h. + * except.c (expand_end_catch_block): Fix comment formatting. + (expand_end_eh_spec): Set DECL_CONTEXT on temporary variables. + (expand_throw): Tidy comment. + * init.c (build_vec_delete_1): Use create_temporary_var. + * lex.c (cplus_tree_code_type): Make it static. + (cplus_tree_code_length): Likewise. + (cplus_tree_code_name): Likewise. + * optimize.c: New file. + * semantics.c (finish_goto_stmt): Set DECL_UNLINABLE for functions + with computed gotos. + (setup_vtbl_ptr): Mark the beginnings of constructors with + CTOR_STMT. + (expand_stmt): Handle CTOR_STMT, not CTOR_COMPLETE. + (expand_body): Call optimize_function. Save bodies if we're doing + inlining on trees. + * tree.c: Don't include splay-tree.h. Include insn-config.h and + integrate.h. + (copy_tree_r): Make it public. + (statement_code_p): New function. + (mark_local_for_remap_r): Likewise. + (cp_usave_r): Likewise. + (cp_unsave): Likewise. + (build_cplus_new): Set DECL_CONTEXT for temporary variables. + (walk_tree): Walk into `s' class nodes. Walk statement chains. + (copy_tree_r): Handle 's' class nodes. Restore chains for + statements. Nullify scopes. Don't copy types. + (init_tree): Set lang_unsave to cp_unsave. + (remap_save_expr): Define. + * ir.texi: Document CTOR_STMT. + 1999-11-24 Jason Merrill * search.c (note_debug_info_needed): Do perform this optimization diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 3051d910413..ffb1b0c6ab6 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -118,7 +118,7 @@ CXX_SRCS = $(srcdir)/cp/call.c $(srcdir)/cp/decl2.c \ $(srcdir)/cp/error.c $(srcdir)/cp/friend.c $(srcdir)/cp/init.c \ $(srcdir)/cp/parse.y $(srcdir)/cp/typeck2.c \ $(srcdir)/cp/repo.c $(srcdir)/cp/semantics.c \ - $(srcdir)/cp/dump.c + $(srcdir)/cp/dump.c $(srcdir)/cp/optimize.c cc1plus$(exeext): $(P) $(CXX_SRCS) $(LIBDEPS) stamp-objlist c-common.o \ c-pragma.o $(srcdir)/cp/cp-tree.h $(srcdir)/cp/cp-tree.def \ diff --git a/gcc/cp/Makefile.in b/gcc/cp/Makefile.in index 897697d0b65..900823c8e7f 100644 --- a/gcc/cp/Makefile.in +++ b/gcc/cp/Makefile.in @@ -175,7 +175,7 @@ INCLUDES = -I. -I.. -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../config -I$(srcdir) CXX_OBJS = call.o decl.o errfn.o expr.o pt.o typeck2.o \ class.o decl2.o error.o lex.o parse.o ptree.o rtti.o spew.o typeck.o cvt.o \ except.o friend.o init.o method.o search.o semantics.o tree.o xref.o \ - repo.o dump.o @extra_cxx_objs@ + repo.o dump.o optimize.o @extra_cxx_objs@ # Language-independent object files. OBJS = `cat ../stamp-objlist` ../c-common.o ../c-pragma.o @@ -202,12 +202,14 @@ RTL_H = $(srcdir)/../rtl.h $(srcdir)/../rtl.def \ TREE_H = $(srcdir)/../tree.h $(srcdir)/../real.h $(srcdir)/../tree.def \ $(srcdir)/../machmode.h $(srcdir)/../machmode.def CXX_TREE_H = $(TREE_H) cp-tree.h $(srcdir)/../c-common.h cp-tree.def \ - $(srcdir)/../function.h $(srcdir)/../varray.h + $(srcdir)/../function.h $(srcdir)/../varray.h \ + $(srcdir)/../../include/splay-tree.h \ + $(srcdir)/../system.h $(CONFIG_H) PARSE_H = $(srcdir)/parse.h PARSE_C = $(srcdir)/parse.c EXPR_H = $(srcdir)/../expr.h ../insn-codes.h -parse.o : $(PARSE_C) $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h lex.h \ +parse.o : $(PARSE_C) $(CXX_TREE_H) $(srcdir)/../flags.h lex.h \ $(srcdir)/../except.h $(srcdir)/../output.h $(srcdir)/../system.h \ $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(BIG_SWITCHFLAG) \ @@ -239,64 +241,66 @@ $(srcdir)/hash.h: $(srcdir)/gxx.gperf echo " ftp://sourceware.cygnus.com/pub/egcs/infrastructure/gperf*" >&2 ; \ exit 1 ) -spew.o : spew.c $(CONFIG_H) $(CXX_TREE_H) $(PARSE_H) $(srcdir)/../flags.h \ - lex.h $(srcdir)/../system.h $(srcdir)/../toplev.h -lex.o : lex.c $(CONFIG_H) $(CXX_TREE_H) \ +spew.o : spew.c $(CXX_TREE_H) $(PARSE_H) $(srcdir)/../flags.h \ + lex.h $(srcdir)/../toplev.h +lex.o : lex.c $(CXX_TREE_H) \ $(PARSE_H) input.c $(srcdir)/../flags.h hash.h lex.h \ - $(srcdir)/../c-pragma.h $(srcdir)/../system.h $(srcdir)/../toplev.h \ + $(srcdir)/../c-pragma.h $(srcdir)/../toplev.h \ $(srcdir)/../output.h $(srcdir)/../mbchar.h $(srcdir)/../ggc.h -decl.o : decl.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \ +decl.o : decl.c $(CXX_TREE_H) $(srcdir)/../flags.h \ lex.h decl.h $(srcdir)/../stack.h $(srcdir)/../output.h \ - $(srcdir)/../except.h $(srcdir)/../system.h $(srcdir)/../toplev.h \ + $(srcdir)/../except.h $(srcdir)/../toplev.h \ $(srcdir)/../hash.h $(srcdir)/../ggc.h $(RTL_H) -decl2.o : decl2.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \ - lex.h decl.h $(EXPR_H) $(srcdir)/../except.h \ - $(srcdir)/../output.h $(srcdir)/../except.h $(srcdir)/../system.h \ +decl2.o : decl2.c $(CXX_TREE_H) $(srcdir)/../flags.h \ + lex.h decl.h $(EXPR_H) $(srcdir)/../output.h $(srcdir)/../except.h \ $(srcdir)/../toplev.h $(srcdir)/../dwarf2out.h $(srcdir)/../dwarfout.h \ - $(srcdir)/../../include/splay-tree.h $(srcdir)/../ggc.h $(RTL_H) -typeck2.o : typeck2.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \ - $(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../output.h -typeck.o : typeck.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \ - $(EXPR_H) $(srcdir)/../system.h $(srcdir)/../toplev.h -class.o : class.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \ - $(srcdir)/../system.h $(srcdir)/../toplev.h \ - $(srcdir)/../../include/splay-tree.h $(RTL_H) -call.o : call.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \ - $(srcdir)/../system.h $(srcdir)/../toplev.h $(RTL_H) -friend.o : friend.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \ - $(srcdir)/../system.h $(srcdir)/../toplev.h -init.o : init.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \ - $(EXPR_H) $(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../ggc.h -method.o : method.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \ + $(srcdir)/../ggc.h $(RTL_H) +typeck2.o : typeck2.c $(CXX_TREE_H) $(srcdir)/../flags.h \ + $(srcdir)/../toplev.h $(srcdir)/../output.h +typeck.o : typeck.c $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \ + $(EXPR_H) $(srcdir)/../toplev.h +class.o : class.c $(CXX_TREE_H) $(srcdir)/../flags.h \ + $(srcdir)/../toplev.h $(RTL_H) +call.o : call.c $(CXX_TREE_H) $(srcdir)/../flags.h \ + $(srcdir)/../toplev.h $(RTL_H) +friend.o : friend.c $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \ + $(srcdir)/../toplev.h +init.o : init.c $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \ + $(EXPR_H) $(srcdir)/../toplev.h $(srcdir)/../ggc.h \ + $(srcdir)/../except.h +method.o : method.c $(CXX_TREE_H) \ $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H) -cvt.o : cvt.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h decl.h \ +cvt.o : cvt.c $(CXX_TREE_H) decl.h \ $(srcdir)/../flags.h $(srcdir)/../toplev.h $(srcdir)/../convert.h -search.o : search.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../stack.h \ - $(srcdir)/../flags.h $(srcdir)/../system.h $(srcdir)/../toplev.h $(RTL_H) -tree.o : tree.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \ - $(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H) \ - $(srcdir)/../../include/splay-tree.h -ptree.o : ptree.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h -rtti.o : rtti.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \ - $(srcdir)/../system.h $(srcdir)/../toplev.h -except.o : except.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \ - $(srcdir)/../except.h $(srcdir)/../system.h $(srcdir)/../toplev.h -expr.o : expr.c $(CONFIG_H) $(CXX_TREE_H) $(RTL_H) $(srcdir)/../flags.h \ - $(EXPR_H) $(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../except.h -xref.o : xref.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../input.h \ - $(srcdir)/../system.h $(srcdir)/../toplev.h -pt.o : pt.c $(CONFIG_H) $(CXX_TREE_H) decl.h $(PARSE_H) lex.h \ - $(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H) -error.o : error.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \ +search.o : search.c $(CXX_TREE_H) $(srcdir)/../stack.h \ + $(srcdir)/../flags.h $(srcdir)/../toplev.h $(RTL_H) +tree.o : tree.c $(CXX_TREE_H) $(srcdir)/../flags.h \ + $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H) \ + ../insn-config.h $(srcdir)/../integrate.h +ptree.o : ptree.c $(CXX_TREE_H) $(srcdir)/../system.h +rtti.o : rtti.c $(CXX_TREE_H) $(srcdir)/../flags.h \ $(srcdir)/../toplev.h -errfn.o : errfn.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \ +except.o : except.c $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \ + $(srcdir)/../except.h $(srcdir)/../toplev.h +expr.o : expr.c $(CXX_TREE_H) $(RTL_H) $(srcdir)/../flags.h \ + $(EXPR_H) $(srcdir)/../toplev.h $(srcdir)/../except.h +xref.o : xref.c $(CXX_TREE_H) $(srcdir)/../input.h \ $(srcdir)/../toplev.h -repo.o : repo.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \ +pt.o : pt.c $(CXX_TREE_H) decl.h $(PARSE_H) lex.h \ + $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H) \ + $(srcdir)/../except.h +error.o : error.c $(CXX_TREE_H) \ + $(srcdir)/../toplev.h +errfn.o : errfn.c $(CXX_TREE_H) \ + $(srcdir)/../toplev.h +repo.o : repo.c $(CXX_TREE_H) \ $(srcdir)/../toplev.h $(srcdir)/../ggc.h -semantics.o: semantics.c $(CONFIG_H) $(CXX_TREE_H) lex.h \ - $(srcdir)/../except.h $(srcdir)/../system.h $(srcdir)/../toplev.h \ +semantics.o: semantics.c $(CXX_TREE_H) lex.h \ + $(srcdir)/../except.h $(srcdir)/../toplev.h \ $(srcdir)/../flags.h $(srcdir)/../ggc.h -dump.o: dump.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h +dump.o: dump.c $(CXX_TREE_H) +optimize.o: optimize.c $(CXX_TREE_H) \ + $(srcdir)/../rtl.h $(srcdir)/../integrate.h ../insn-config.h # # These exist for maintenance purposes. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 19bd69cf089..a916123ed9b 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -30,7 +30,6 @@ Boston, MA 02111-1307, USA. */ #include "rtl.h" #include "output.h" #include "toplev.h" -#include "splay-tree.h" #include "ggc.h" #include "lex.h" diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 59b14fd298a..6ccc8745ed9 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -237,9 +237,11 @@ DEFTREECODE (ASM_STMT, "asm_stmt", 'e', 5) run if an exception is thrown before the end of the enclosing function. */ DEFTREECODE (SUBOBJECT, "subobject", 'e', 1) -/* A CTOR_COMPLETE statements marks the end of the main body of the - constructor, not including any function try blocks. */ -DEFTREECODE (CTOR_COMPLETE, "ctor_complete", 'e', 0) +/* An CTOR_STMT marks the beginning (if CTOR_BEGIN_P holds) or end of + a contstructor (if CTOR_END_P) holds. At the end of a constructor, + the cleanups associated with any SUBOBJECT_CLEANUPS need no longer + be run. */ +DEFTREECODE (CTOR_STMT, "ctor_stmt", 'e', 0) /* A CLEANUP_STMT marks the point at which a declaration is fully constructed. If, after this point, the CLEANUP_DECL goes out of scope, the CLEANUP_EXPR must be run. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a83744e2876..3b1f402d525 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -21,6 +21,7 @@ Boston, MA 02111-1307, USA. */ #include "c-common.h" #include "function.h" +#include "splay-tree.h" #include "varray.h" #ifndef _CP_TREE_H @@ -40,6 +41,7 @@ Boston, MA 02111-1307, USA. */ CLEANUP_P (in TRY_BLOCK) AGGR_INIT_VIA_CTOR_P (in AGGR_INIT_EXPR) SCOPE_BEGIN_P (in SCOPE_STMT) + CTOR_BEGIN_P (in CTOR_STMT) 1: IDENTIFIER_VIRTUAL_P. TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -2121,6 +2123,10 @@ extern int flag_new_for_scope; #define SET_DECL_C_BIT_FIELD(NODE) \ (DECL_LANG_SPECIFIC (FIELD_DECL_CHECK (NODE))->decl_flags.bitfield = 1) +/* In a FUNCTION_DECL, nonzero if the function cannot be inlined. */ +#define DECL_UNINLINABLE(NODE) \ + (DECL_LANG_SPECIFIC (NODE)->decl_flags.bitfield) + #define INTEGRAL_CODE_P(CODE) \ (CODE == INTEGER_TYPE || CODE == ENUMERAL_TYPE || CODE == BOOLEAN_TYPE) @@ -2691,6 +2697,14 @@ extern int flag_new_for_scope; #define SCOPE_END_P(NODE) \ (!SCOPE_BEGIN_P (SCOPE_STMT_CHECK (NODE))) +/* Nonzero if this CTOR_STMT is for the beginning of a constructor. */ +#define CTOR_BEGIN_P(NODE) \ + (TREE_LANG_FLAG_0 (CTOR_STMT_CHECK (NODE))) + +/* Nonzero if this CTOR_STMT is for the end of a constructor. */ +#define CTOR_END_P(NODE) \ + (!CTOR_BEGIN_P (NODE)) + /* Nonzero for a SCOPE_STMT if there were no variables in this scope. */ #define SCOPE_NULLIFIED_P(NODE) \ (TREE_LANG_FLAG_3 (SCOPE_STMT_CHECK (NODE))) @@ -3107,6 +3121,11 @@ extern int flag_new_abi; extern int flag_honor_std; +/* Nonzero if we should expand functions calls inline at the tree + level, rather than at the RTL level. */ + +extern int flag_inline_trees; + /* Nonzero if we're done parsing and into end-of-file activities. */ extern int at_eof; @@ -3532,6 +3551,8 @@ extern tree maybe_push_decl PROTO((tree)); extern void emit_local_var PROTO((tree)); extern tree build_target_expr_with_type PROTO((tree, tree)); extern void make_rtl_for_local_static PROTO((tree)); +extern int local_variable_p PROTO((tree)); +extern int nonstatic_local_decl_p PROTO((tree)); /* in decl2.c */ extern void init_decl2 PROTO((void)); @@ -3744,6 +3765,9 @@ extern void emit_thunk PROTO((tree)); extern void synthesize_method PROTO((tree)); extern tree get_id_2 PROTO((const char *, tree)); +/* In optimize.c */ +extern void optimize_function PROTO((tree)); + /* in pt.c */ extern void init_pt PROTO ((void)); extern void check_template_shadow PROTO ((tree)); @@ -3960,7 +3984,6 @@ extern tree arbitrate_lookup PROTO((tree, tree, tree)); /* in tree.c */ extern void init_tree PROTO((void)); -extern void cplus_unsave_expr_now PROTO((tree)); extern int pod_type_p PROTO((tree)); extern void unshare_base_binfos PROTO((tree)); extern int member_p PROTO((tree)); @@ -4028,9 +4051,11 @@ extern tree maybe_dummy_object PROTO((tree, tree *)); extern int is_dummy_object PROTO((tree)); typedef tree (*walk_tree_fn) PROTO((tree *, int *, void *)); extern tree walk_tree PROTO((tree *, walk_tree_fn, void *)); +extern tree copy_tree_r PROTO((tree *, int *, void *)); extern int cp_valid_lang_attribute PROTO((tree, tree, tree, tree)); extern tree make_ptrmem_cst PROTO((tree, tree)); extern tree cp_build_qualified_type_real PROTO((tree, int, int)); +extern void remap_save_expr PROTO((tree *, splay_tree, tree)); #define cp_build_qualified_type(TYPE, QUALS) \ cp_build_qualified_type_real ((TYPE), (QUALS), /*complain=*/1) diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index f24bb3f011f..0edcc258c6b 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -141,7 +141,7 @@ static boolean typename_compare PROTO((hash_table_key, hash_table_key)); static void push_binding PROTO((tree, tree, struct binding_level*)); static int add_binding PROTO((tree, tree)); static void pop_binding PROTO((tree, tree)); -static tree local_variable_p PROTO((tree *, int *, void *)); +static tree local_variable_p_walkfn PROTO((tree *, int *, void *)); static tree find_binding PROTO((tree, tree)); static tree select_decl PROTO((tree, int)); static int lookup_flags PROTO((int, int)); @@ -7362,26 +7362,10 @@ make_rtl_for_local_static (decl) tree type = TREE_TYPE (decl); const char *asmspec = NULL; - if (TREE_READONLY (decl) - && DECL_INITIAL (decl) != NULL_TREE - && DECL_INITIAL (decl) != error_mark_node - && ! EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl)) - && ! TREE_SIDE_EFFECTS (decl) - && ! TREE_PUBLIC (decl) - && ! DECL_EXTERNAL (decl) - && ! TYPE_NEEDS_DESTRUCTOR (type) - && ! TREE_ADDRESSABLE (decl) - && DECL_MODE (decl) != BLKmode) - { - /* As an optimization, we try to put register-sized static - constants in a register, rather than writing them out. If we - take the address of the constant later, we'll make RTL for it - at that point. */ - DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl)); - store_expr (DECL_INITIAL (decl), DECL_RTL (decl), 0); - TREE_ASM_WRITTEN (decl) = 1; - return; - } + /* If we inlined this variable, we could see it's declaration + again. */ + if (DECL_RTL (decl)) + return; if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)) { @@ -7543,9 +7527,8 @@ emit_local_var (decl) { /* Create RTL for this variable. */ if (DECL_RTL (decl)) - /* Only a RESULT_DECL should have non-NULL RTL when - arriving here. All other local variables are - assigned RTL in this function. */ + /* Only a RESULT_DECL should have non-NULL RTL when arriving here. + All other local variables are assigned RTL in this function. */ my_friendly_assert (TREE_CODE (decl) == RESULT_DECL, 19990828); else @@ -11141,27 +11124,48 @@ require_complete_types_for_parms (parms) } } -/* Returns *TP if *TP is a local variable (or parameter). Returns - NULL_TREE otherwise. */ +/* Returns non-zero if T is a local variable. */ -static tree -local_variable_p (tp, walk_subtrees, data) - tree *tp; - int *walk_subtrees ATTRIBUTE_UNUSED; - void *data ATTRIBUTE_UNUSED; +int +local_variable_p (t) + tree t; { - tree t = *tp; - if ((TREE_CODE (t) == VAR_DECL /* A VAR_DECL with a context that is a _TYPE is a static data member. */ && !TYPE_P (CP_DECL_CONTEXT (t)) /* Any other non-local variable must be at namespace scope. */ - && TREE_CODE (CP_DECL_CONTEXT (t)) != NAMESPACE_DECL) + && !DECL_NAMESPACE_SCOPE_P (t)) || (TREE_CODE (t) == PARM_DECL)) - return t; + return 1; - return NULL_TREE; + return 0; +} + +/* Returns non-zero if T is an automatic local variable or a label. + (These are the declarations that need to be remapped when the code + containing them is duplicated.) */ + +int +nonstatic_local_decl_p (t) + tree t; +{ + return ((local_variable_p (t) && !TREE_STATIC (t)) + || TREE_CODE (t) == LABEL_DECL + || TREE_CODE (t) == RESULT_DECL); +} + +/* Like local_variable_p, but suitable for use as a tree-walking + function. */ + +static tree +local_variable_p_walkfn (tp, walk_subtrees, data) + tree *tp; + int *walk_subtrees ATTRIBUTE_UNUSED; + void *data ATTRIBUTE_UNUSED; +{ + return ((local_variable_p (*tp) && !DECL_ARTIFICIAL (*tp)) + ? *tp : NULL_TREE); } /* Check that ARG, which is a default-argument expression for a @@ -11230,7 +11234,7 @@ check_default_argument (decl, arg) The keyword `this' shall not be used in a default argument of a member function. */ - var = walk_tree (&arg, local_variable_p, NULL); + var = walk_tree (&arg, local_variable_p_walkfn, NULL); if (var) { cp_error ("default argument `%E' uses local variable `%D'", @@ -13067,9 +13071,15 @@ start_function (declspecs, declarator, attrs, flags) if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1)) && DECL_LANGUAGE (decl1) == lang_cplusplus) - dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + { + dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + DECL_CONTEXT (dtor_label) = current_function_decl; + } else if (DECL_CONSTRUCTOR_P (decl1)) - ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + { + ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + DECL_CONTEXT (ctor_label) = current_function_decl; + } return 1; } @@ -13295,10 +13305,8 @@ finish_constructor_body () /* In check_return_expr we translate an empty return from a constructor to a return of `this'. */ finish_return_stmt (NULL_TREE); - - /* Mark the end of the main constructor body. */ - if (DECL_CONSTRUCTOR_P (current_function_decl)) - add_tree (build_min_nt (CTOR_COMPLETE)); + /* Mark the end of the constructor. */ + add_tree (build_min_nt (CTOR_STMT)); } /* At the end of every destructor we generate code to restore virtual diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 617d85426f5..7759b0a0e3f 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -42,7 +42,6 @@ Boston, MA 02111-1307, USA. */ #include "toplev.h" #include "dwarf2out.h" #include "dwarfout.h" -#include "splay-tree.h" #include "ggc.h" #if USE_CPPLIB @@ -444,6 +443,11 @@ int flag_new_abi; int flag_honor_std; +/* Nonzero if we should expand functions calls inline at the tree + level, rather than at the RTL level. */ + +int flag_inline_trees = 0; + /* Maximum template instantiation depth. Must be at least 17 for ANSI compliance. */ diff --git a/gcc/cp/dump.c b/gcc/cp/dump.c index ef92f182964..6e3fbcceab7 100644 --- a/gcc/cp/dump.c +++ b/gcc/cp/dump.c @@ -23,7 +23,6 @@ Boston, MA 02111-1307, USA. */ #include "system.h" #include "tree.h" #include "cp-tree.h" -#include "splay-tree.h" /* Flags used with queue functions. */ #define DUMP_NONE 0 diff --git a/gcc/cp/except.c b/gcc/cp/except.c index eb8cf0e7c63..62cae27bf59 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -564,7 +564,7 @@ expand_end_catch_block (blocks) /* Cleanup the EH parameter. */ finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_2); - /* Cleanup the EH object. */ + /* Cleanup the EH object. */ finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1); } @@ -615,6 +615,7 @@ expand_end_eh_spec (raises, try_block) decl = build_decl (VAR_DECL, NULL_TREE, tmp); DECL_ARTIFICIAL (decl) = 1; DECL_INITIAL (decl) = types; + DECL_CONTEXT (decl) = current_function_decl; cp_finish_decl (decl, types, NULL_TREE, 0); decl = decay_conversion (decl); @@ -804,12 +805,10 @@ expand_throw (exp) tree object, ptr; /* OK, this is kind of wacky. The WP says that we call - terminate - - when the exception handling mechanism, after completing - evaluation of the expression to be thrown but before the - exception is caught (_except.throw_), calls a user function - that exits via an uncaught exception. + terminate when the exception handling mechanism, after + completing evaluation of the expression to be thrown but + before the exception is caught (_except.throw_), calls a + user function that exits via an uncaught exception. So we have to protect the actual initialization of the exception object with terminate(), but evaluate the expression diff --git a/gcc/cp/init.c b/gcc/cp/init.c index da586e9bc60..1361b9686ee 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2470,7 +2470,7 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete) /* The below is short by BI_header_size */ virtual_size = fold (size_binop (MULT_EXPR, size_exp, maxindex)); - tbase = build_decl (VAR_DECL, NULL_TREE, ptype); + tbase = create_temporary_var (ptype); tbase_init = build_modify_expr (tbase, NOP_EXPR, fold (build (PLUS_EXPR, ptype, base, diff --git a/gcc/cp/ir.texi b/gcc/cp/ir.texi index 09ae98d53fa..b2e6a497270 100644 --- a/gcc/cp/ir.texi +++ b/gcc/cp/ir.texi @@ -1274,9 +1274,11 @@ following the @code{TREE_CHAIN} link from one substatement to the next. Used to represent a @code{continue} statement. There are no additional fields. -@item CTOR_COMPLETE +@item CTOR_STMT -Used to mark the end of the main body of a constructor. +Used to mark the beginning (if @code{CTOR_BEGIN_P} holds) or end (if +@code{CTOR_END_P} holds of the main body of a constructor. See also +@code{SUBOBJECT} for more information on how to use these nodes. @item DECL_STMT @@ -1387,9 +1389,9 @@ equalit) to @code{CATCH_ALL_TYPE} if this handler is for all types. In a constructor, these nodes are used to mark the point at which a subobject of @code{this} is fully constructed. If, after this point, an -exception is thrown before a CTOR_COMPLETE statement is encountered, the -@code{SUBOBJECT_CLEANUP} must be executed. The cleanups must be -executed in the reverse order in which they appear. +exception is thrown before a @code{CTOR_STMT} with @code{CTOR_END_P} set +is encountered, the @code{SUBOBJECT_CLEANUP} must be executed. The +cleanups must be executed in the reverse order in which they appear. @item SWITCH_STMT diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index b7fc18fb819..ae2783f4c1b 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -405,7 +405,7 @@ my_get_run_time () #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE, -char cplus_tree_code_type[] = { +static char cplus_tree_code_type[] = { 'x', #include "cp-tree.def" }; @@ -417,7 +417,7 @@ char cplus_tree_code_type[] = { #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH, -int cplus_tree_code_length[] = { +static int cplus_tree_code_length[] = { 0, #include "cp-tree.def" }; @@ -427,7 +427,7 @@ int cplus_tree_code_length[] = { Used for printing out the tree and error messages. */ #define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME, -const char *cplus_tree_code_name[] = { +static const char *cplus_tree_code_name[] = { "@@dummy", #include "cp-tree.def" }; diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c new file mode 100644 index 00000000000..d81f5448f1f --- /dev/null +++ b/gcc/cp/optimize.c @@ -0,0 +1,497 @@ +/* Perform optimizations on tree structure. + + Copyright (C) 1998, 1999 Free Software Foundation, Inc. + Written by Mark Michell (mark@codesourcery.com). + + This file is part of GNU CC. + + GNU CC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU CC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU CC; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "tree.h" +#include "cp-tree.h" +#include "rtl.h" +#include "insn-config.h" +#include "integrate.h" +#include "varray.h" + +/* To Do: + + o Provide debugging information for inlined function bodies. + + o In order to make inlining-on-trees work, we pessimized + function-local static constants. In particular, they are now + always output, even when not addressed. Fix this by treating + function-local static constants just like global static + constants; the back-end already knows not to output them if they + are not needed. + + o Provide heuristics to clamp inlining of recursive template + calls? */ + +/* Data required for function inlining. */ + +typedef struct inline_data +{ + /* A stack of the functions we are inlining. For example, if we are + compiling `f', which calls `g', which calls `h', and we are + inlining the body of `h', the stack will contain, `h', followed + by `g', followed by `f'. */ + varray_type fns; + /* The top of the FNS stack. */ + size_t fns_top; + /* The label to jump to when a return statement is encountered. */ + tree ret_label; + /* The map from local declarations in the inlined function to + equivalents in the function into which it is being inlined. */ + splay_tree decl_map; +} inline_data; + +/* Prototypes. */ + +static tree initialize_inlined_parameters PROTO((inline_data *, tree)); +static tree declare_return_variable PROTO((inline_data *, tree *)); +static tree copy_body_r PROTO((tree *, int *, void *)); +static tree copy_body PROTO((inline_data *)); +static tree expand_call_inline PROTO((tree *, int *, void *)); +static void expand_calls_inline PROTO((tree *, inline_data *)); +static int inlinable_function_p PROTO((tree, inline_data *)); + +/* Called from copy_body via walk_tree. DATA is really an + `inline_data *'. */ + +static tree +copy_body_r (tp, walk_subtrees, data) + tree *tp; + int *walk_subtrees; + void *data; +{ + inline_data* id; + tree fn; + + /* Set up. */ + id = (inline_data *) data; + fn = VARRAY_TREE (id->fns, id->fns_top - 1); + + /* 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 this is a RETURN_STMT, change it into an EXPR_STMT and a + GOTO_STMT with the RET_LABEL as its target. */ + if (TREE_CODE (*tp) == RETURN_STMT) + { + tree return_stmt = *tp; + tree goto_stmt; + + /* Build the GOTO_STMT. */ + goto_stmt = build_min_nt (GOTO_STMT, id->ret_label); + TREE_CHAIN (goto_stmt) = TREE_CHAIN (return_stmt); + + /* If we're returning something, just turn that into an + assignment into the equivalent of the original + RESULT_DECL. */ + if (RETURN_EXPR (return_stmt)) + { + *tp = build_min_nt (EXPR_STMT, + RETURN_EXPR (return_stmt)); + /* And then jump to the end of the function. */ + TREE_CHAIN (*tp) = goto_stmt; + } + /* If we're not returning anything just do the jump. */ + else + *tp = goto_stmt; + } + /* Local variables and labels need to be replaced by equivalent + 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) + { + splay_tree_node n; + + /* Look up the declaration. */ + n = splay_tree_lookup (id->decl_map, (splay_tree_key) *tp); + + /* If we didn't already have an equivalent for this declaration, + create one now. */ + if (!n) + { + tree t; + + /* Make a copy of the variable or label. */ + t = copy_decl_for_inlining (*tp, fn, + VARRAY_TREE (id->fns, 0)); + /* Remember it, so that if we encounter this local entity + again we can reuse this copy. */ + n = splay_tree_insert (id->decl_map, + (splay_tree_key) *tp, + (splay_tree_value) t); + } + + /* Replace this variable with the copy. */ + *tp = (tree) n->value; + } + else if (TREE_CODE (*tp) == SAVE_EXPR) + remap_save_expr (tp, id->decl_map, VARRAY_TREE (id->fns, 0)); + else if (TREE_CODE (*tp) == UNSAVE_EXPR) + my_friendly_abort (19991113); + /* Otherwise, just copy the node. Note that copy_tree_r already + knows not to copy VAR_DECLs, etc., so this is safe. */ + else + { + copy_tree_r (tp, walk_subtrees, NULL); + + /* The copied TARGET_EXPR has never been expanded, even if the + original node was expanded already. */ + if (TREE_CODE (*tp) == TARGET_EXPR && TREE_OPERAND (*tp, 3)) + TREE_OPERAND (*tp, 1) = TREE_OPERAND (*tp, 3); + /* Similarly, if we're copying a CALL_EXPR, the RTL for the + result is no longer valid. */ + else if (TREE_CODE (*tp) == CALL_EXPR) + CALL_EXPR_RTL (*tp) = NULL_RTX; + } + + /* Keep iterating. */ + return NULL_TREE; +} + +/* Make a copy of the body of FN so that it can be inserted inline in + another function. */ + +static tree +copy_body (id) + inline_data *id; +{ + tree body; + + body = DECL_SAVED_TREE (VARRAY_TREE (id->fns, id->fns_top - 1)); + walk_tree (&body, copy_body_r, id); + + return body; +} + +/* Generate code to initialize the parameters of the function at the + top of the stack in ID from the ARGS (presented as a TREE_LIST). */ + +static tree +initialize_inlined_parameters (id, args) + inline_data *id; + tree args; +{ + tree fn; + tree init_stmts; + tree parms; + tree a; + tree p; + + /* Figure out what the parameters are. */ + fn = VARRAY_TREE (id->fns, id->fns_top - 1); + parms = DECL_ARGUMENTS (fn); + + /* Start with no initializations whatsoever. */ + init_stmts = NULL_TREE; + + /* Loop through the parameter declarations, replacing each with an + equivalent VAR_DECL, appropriately initialized. */ + for (p = parms, a = args; p; a = TREE_CHAIN (a), p = TREE_CHAIN (p)) + { + tree init_stmt; + tree var; + + /* Make an equivalent VAR_DECL. */ + var = copy_decl_for_inlining (p, fn, VARRAY_TREE (id->fns, 0)); + /* Register the VAR_DECL as the equivalent for the PARM_DECL; + that way, when the PARM_DECL is encountered, it will be + automatically replaced by the VAR_DECL. */ + splay_tree_insert (id->decl_map, + (splay_tree_key) p, + (splay_tree_value) var); + /* Initialize this VAR_DECL from the equivalent argument. If + the argument is an object, created via a constructor or copy, + this will not result in an extra copy: the TARGET_EXPR + representing the argument will be bound to VAR, and the + object will be constructed in VAR. */ + init_stmt = build_min_nt (EXPR_STMT, + build (INIT_EXPR, TREE_TYPE (p), + var, TREE_VALUE (a))); + /* Declare this new variable. Note that we do this *after* the + initialization because we are going to reverse all the + initialization statements below. */ + TREE_CHAIN (init_stmt) = build_min_nt (DECL_STMT, var); + /* Add this initialization to the list. */ + TREE_CHAIN (TREE_CHAIN (init_stmt)) = init_stmts; + init_stmts = init_stmt; + } + + /* The initialization statements have been built up in reverse + order. Straighten them out now. */ + return nreverse (init_stmts); +} + +/* Declare a return variable to replace the RESULT_DECL for the + function we are calling. An appropriate DECL_STMT is returned. + The USE_STMT is filled in to contain a use of the declaration to + indicate the return value of the function. */ + +static tree +declare_return_variable (id, use_stmt) + struct inline_data *id; + tree *use_stmt; +{ + tree fn = VARRAY_TREE (id->fns, id->fns_top - 1); + tree result = DECL_RESULT (fn); + tree var; + + /* We don't need to do anything for functions that don't return + anything. */ + if (!result || same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (result)), + void_type_node)) + { + *use_stmt = NULL_TREE; + return NULL_TREE; + } + + /* Make an appropriate copy. */ + var = copy_decl_for_inlining (result, fn, VARRAY_TREE (id->fns, 0)); + /* Register the VAR_DECL as the equivalent for the RESULT_DECL; that + way, when the RESULT_DECL is encountered, it will be + automatically replaced by the VAR_DECL. */ + splay_tree_insert (id->decl_map, + (splay_tree_key) result, + (splay_tree_value) var); + + /* Build the USE_STMT. */ + *use_stmt = build_min_nt (EXPR_STMT, var); + + /* Build the declaration statement. */ + return build_min_nt (DECL_STMT, var); +} + +/* Returns non-zero if FN is a function that can be inlined. */ + +static int +inlinable_function_p (fn, id) + tree fn; + inline_data *id; +{ + int inlinable; + + /* If we've already decided this function shouldn't be inlined, + there's no need to check again. */ + if (DECL_UNINLINABLE (fn)) + return 0; + + /* Assume it is not inlinable. */ + inlinable = 0; + + /* If the function was not declared `inline', then we don't inline + it. */ + if (!DECL_INLINE (fn)) + ; + /* If we don't have the function body available, we can't inline + it. */ + else if (!DECL_SAVED_TREE (fn)) + ; + /* We can't inline varargs functions. */ + else if (varargs_function_p (fn)) + ; + /* All is well. We can inline this function. Traditionally, GCC + has refused to inline functions using setjmp or alloca, or + functions whose values are returned in a PARALLEL, and a few + other such obscure conditions. We are not equally constrained at + the tree level. */ + else + inlinable = 1; + + /* Squirrel away the result so that we don't have to check again. */ + DECL_UNINLINABLE (fn) = !inlinable; + + /* Don't do recursive inlining, either. We don't record this in + DECL_UNLINABLE; we may be able to inline this function later. */ + if (inlinable) + { + size_t i; + + for (i = 0; i < id->fns_top; ++i) + if (VARRAY_TREE (id->fns, i) == fn) + inlinable = 0; + } + + /* We can inline a template instantiation only if its fully + instantiated. */ + if (inlinable + && DECL_TEMPLATE_INFO (fn) + && TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn))) + { + fn = instantiate_decl (fn); + inlinable = !TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn)); + } + + /* Return the result. */ + return inlinable; +} + +/* If *TP is CALL_EXPR, replace it with its inline expansion. */ + +static tree +expand_call_inline (tp, walk_subtrees, data) + tree *tp; + int *walk_subtrees; + void *data; +{ + inline_data *id; + tree t; + tree expr; + tree chain; + tree fn; + tree use_stmt; + splay_tree st; + + /* We're only interested in CALL_EXPRs. */ + t = *tp; + if (TREE_CODE (t) != CALL_EXPR) + return NULL_TREE; + + /* First, see if we can figure out what function is being called. + If we cannot, then there is no hope of inlining the function. */ + fn = get_callee_fndecl (t); + if (!fn) + return NULL_TREE; + + /* Don't try to inline functions that are not well-suited to + inlining. */ + id = (inline_data *) data; + if (!inlinable_function_p (fn, id)) + return NULL_TREE; + + /* Return statements in the function body will be replaced by jumps + to the RET_LABEL. */ + id->ret_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + DECL_CONTEXT (id->ret_label) = VARRAY_TREE (id->fns, 0); + + /* Build a statement-expression containing code to initialize the + arguments, the actual inline expansion of the body, and a label + 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); + + /* Record the function we are about to inline so that we can avoid + recursing into it. */ + if (id->fns_top > id->fns->num_elements) + VARRAY_GROW (id->fns, 2 * id->fns->num_elements); + VARRAY_TREE (id->fns, id->fns_top++) = fn; + + /* Local declarations will be replaced by their equivalents in this + map. */ + st = id->decl_map; + id->decl_map = splay_tree_new (splay_tree_compare_pointers, + NULL, NULL); + + /* Initialize the parameters. */ + STMT_EXPR_STMT (expr) + = initialize_inlined_parameters (id, TREE_OPERAND (t, 1)); + + /* Declare the return variable for the function. */ + STMT_EXPR_STMT (expr) + = chainon (STMT_EXPR_STMT (expr), + declare_return_variable (id, &use_stmt)); + + /* After we've initialized the parameters, we insert the body of the + function itself. */ + STMT_EXPR_STMT (expr) + = chainon (STMT_EXPR_STMT (expr), copy_body (id)); + + /* Finally, mention the returned value so that the value of the + statement-expression is the returned value of the function. */ + STMT_EXPR_STMT (expr) = chainon (STMT_EXPR_STMT (expr), use_stmt); + + /* Clean up. */ + splay_tree_delete (id->decl_map); + id->decl_map = st; + + /* After the body of the function comes the RET_LABEL. */ + STMT_EXPR_STMT (expr) + = chainon (STMT_EXPR_STMT (expr), + build_min_nt (LABEL_STMT, id->ret_label)); + + /* The new expression has side-effects if the old one did. */ + TREE_SIDE_EFFECTS (expr) = TREE_SIDE_EFFECTS (t); + /* If the value of the new expression is ignored, that's OK. We + don't warn about this for CALL_EXPRs, so we shouldn't warn about + the equivalent inlined version either. */ + TREE_USED (expr) = 1; + + /* Replace the call by the inlined body. */ + chain = TREE_CHAIN (*tp); + *tp = expr; + TREE_CHAIN (expr) = chain; + + /* Recurse into the body of the just inlined function. */ + expand_calls_inline (tp, id); + --id->fns_top; + + /* Don't walk into subtrees. We've already handled them above. */ + *walk_subtrees = 0; + + /* Keep iterating. */ + return NULL_TREE; +} + +/* Walk over the entire tree *TP, replacing CALL_EXPRs with inline + expansions as appropriate. */ + +static void +expand_calls_inline (tp, id) + tree *tp; + inline_data *id; +{ + /* Search through *TP, replacing all calls to inline functions by + appropriate equivalents. */ + walk_tree (tp, expand_call_inline, id); +} + +/* Optimize the body of FN. */ + +void +optimize_function (fn) + tree fn; +{ + /* Expand calls to inline functions. */ + if (flag_inline_trees) + { + inline_data id; + + /* Clear out ID. */ + bzero (&id, sizeof (id)); + + /* Don't allow recursion into FN. */ + VARRAY_TREE_INIT (id.fns, 32, "fns"); + VARRAY_TREE (id.fns, id.fns_top++) = fn; + + /* Replace all calls to inline functions with the bodies of those + functions. */ + expand_calls_inline (&DECL_SAVED_TREE (fn), &id); + + /* Clean up. */ + VARRAY_FREE (id.fns); + } +} diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 7a030e696a2..2d70cb9044e 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -658,7 +658,16 @@ finish_goto_stmt (destination) TREE_USED (destination) = 1; if (building_stmt_tree ()) - add_tree (build_min_nt (GOTO_STMT, destination)); + { + if (TREE_CODE (destination) != LABEL_DECL) + /* We don't inline calls to functions with computed gotos. + Those functions are typically up to some funny business, + and may be depending on the labels being at particular + addresses, or some such. */ + DECL_UNINLINABLE (current_function_decl) = 1; + + add_tree (build_min_nt (GOTO_STMT, destination)); + } else { emit_line_note (input_filename, lineno); @@ -1183,7 +1192,17 @@ setup_vtbl_ptr () (CTOR_INITIALIZER, current_member_init_list, current_base_init_list)); else - finish_expr_stmt (emit_base_init (current_class_type)); + { + tree ctor_stmt; + + /* Mark the beginning of the constructor. */ + ctor_stmt = build_min_nt (CTOR_STMT); + CTOR_BEGIN_P (ctor_stmt) = 1; + add_tree (ctor_stmt); + + /* And actually initialize the base-classes and members. */ + finish_expr_stmt (emit_base_init (current_class_type)); + } } else if (DECL_DESTRUCTOR_P (current_function_decl) && !processing_template_decl) @@ -1592,6 +1611,9 @@ finish_label_address_expr (label) TREE_USED (label) = 1; result = build1 (ADDR_EXPR, ptr_type_node, label); TREE_CONSTANT (result) = 1; + /* This function cannot be inlined. All jumps to the addressed + label should wind up at the same point. */ + DECL_UNINLINABLE (current_function_decl) = 1; } return result; @@ -2268,11 +2290,6 @@ expand_stmt (t) finish_expr_stmt (EXPR_STMT_EXPR (t)); break; - case CTOR_COMPLETE: - /* All subobjects have been fully constructed at this point. */ - end_protect_partials (); - break; - case DECL_STMT: { tree decl; @@ -2309,6 +2326,16 @@ expand_stmt (t) begin_catch_block (TREE_TYPE (t)); break; + case CTOR_STMT: + if (CTOR_BEGIN_P (t)) + begin_protect_partials (); + else + /* After this point, any exceptions will cause the + destructor to be executed, so we no longer need to worry + about destroying the various subobjects ourselves. */ + end_protect_partials (); + break; + case FOR_STMT: { tree tmp; @@ -2508,6 +2535,9 @@ expand_body (fn) if (flag_syntax_only) return; + /* Optimize the body of the function before expanding it. */ + optimize_function (fn); + /* Save the current file name and line number. When we expand the body of the function, we'll set LINENO and INPUT_FILENAME so that error-mesages come out in the right places. */ @@ -2538,9 +2568,17 @@ expand_body (fn) /* Generate code for the function. */ finish_function (lineno, 0); - /* We don't need the body any more. Allow it to be garbage - collected. We can't do this if we're going to dump everything. */ - if (!flag_dump_translation_unit) + /* If possible, obliterate the body of the function so that it can + be garbage collected. */ + if (flag_dump_translation_unit) + /* Keep the body; we're going to dump it. */ + ; + else if (DECL_INLINE (fn) && flag_inline_trees) + /* We might need the body of this function so that we can expand + it inline somewhere else. */ + ; + else + /* We don't need the body; blow it away. */ DECL_SAVED_TREE (fn) = NULL_TREE; /* And restore the current source position. */ diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 15f66daf527..93893b3a048 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -28,7 +28,8 @@ Boston, MA 02111-1307, USA. */ #include "rtl.h" #include "toplev.h" #include "ggc.h" -#include "splay-tree.h" +#include "insn-config.h" +#include "integrate.h" static tree bot_manip PROTO((tree *, int *, void *)); static tree bot_replace PROTO((tree *, int *, void *)); @@ -42,7 +43,10 @@ static cp_lvalue_kind lvalue_p_1 PROTO((tree, int)); static tree no_linkage_helper PROTO((tree *, int *, void *)); static tree build_srcloc PROTO((char *, int)); static void mark_list_hash PROTO ((void *)); -static tree copy_tree_r PROTO ((tree *, int *, void *)); +static int statement_code_p PROTO((enum tree_code)); +static tree mark_local_for_remap_r PROTO((tree *, int *, void *)); +static tree cp_unsave_r PROTO ((tree *, int *, void *)); +static void cp_unsave PROTO((tree *)); static tree build_target_expr PROTO((tree, tree)); #define CEIL(x,y) (((x) + (y) - 1) / (y)) @@ -259,6 +263,7 @@ build_cplus_new (type, init) slot = build (VAR_DECL, type); DECL_ARTIFICIAL (slot) = 1; + DECL_CONTEXT (slot) = current_function_decl; layout_decl (slot, 0); /* We split the CALL_EXPR into its function and its arguments here. @@ -1456,6 +1461,45 @@ is_aggr_type_2 (t1, t2) return 0; return IS_AGGR_TYPE (t1) && IS_AGGR_TYPE (t2); } + +/* Returns non-zero if CODE is the code for a statement. */ + +static int +statement_code_p (code) + enum tree_code code; +{ + switch (code) + { + case EXPR_STMT: + case COMPOUND_STMT: + case DECL_STMT: + case IF_STMT: + case FOR_STMT: + case WHILE_STMT: + case DO_STMT: + case RETURN_STMT: + case BREAK_STMT: + case CONTINUE_STMT: + case SWITCH_STMT: + case GOTO_STMT: + case LABEL_STMT: + case ASM_STMT: + case SUBOBJECT: + case CLEANUP_STMT: + case START_CATCH_STMT: + case CTOR_STMT: + case SCOPE_STMT: + case CTOR_INITIALIZER: + case CASE_LABEL: + case RETURN_INIT: + case TRY_BLOCK: + case HANDLER: + return 1; + + default: + return 0; + } +} #define PRINT_RING_SIZE 4 @@ -1594,7 +1638,8 @@ walk_tree (tp, func, data) /* Handle commmon cases up front. */ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)) - || TREE_CODE_CLASS (code) == 'r') + || TREE_CODE_CLASS (code) == 'r' + || TREE_CODE_CLASS (code) == 's') { int i; @@ -1602,6 +1647,11 @@ walk_tree (tp, func, data) for (i = first_rtl_op (code) - 1; i >= 0; --i) WALK_SUBTREE (TREE_OPERAND (*tp, i)); + /* For statements, we also walk the chain so that we cover the + entire statement tree. */ + if (statement_code_p (code)) + WALK_SUBTREE (TREE_CHAIN (*tp)); + /* We didn't find what we were looking for. */ return NULL_TREE; } @@ -1706,7 +1756,7 @@ walk_tree (tp, func, data) if (TYPE_PTRMEMFUNC_P (*tp)) WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp)); break; - + default: my_friendly_abort (19990803); } @@ -1755,10 +1805,10 @@ no_linkage_check (t) /* Passed to walk_tree. Copies the node pointed to, if appropriate. */ -static tree +tree copy_tree_r (tp, walk_subtrees, data) tree *tp; - int *walk_subtrees ATTRIBUTE_UNUSED; + int *walk_subtrees; void *data ATTRIBUTE_UNUSED; { enum tree_code code = TREE_CODE (*tp); @@ -1767,6 +1817,7 @@ copy_tree_r (tp, walk_subtrees, data) if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)) || TREE_CODE_CLASS (code) == 'r' || TREE_CODE_CLASS (code) == 'c' + || TREE_CODE_CLASS (code) == 's' || code == PARM_DECL || code == TREE_LIST || code == TREE_VEC @@ -1781,12 +1832,21 @@ 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 || code == OVERLOAD + || statement_code_p (code)) TREE_CHAIN (*tp) = chain; + + /* For now, we don't update BLOCKs when we make copies. So, we + have to nullify all scope-statements. */ + if (TREE_CODE (*tp) == SCOPE_STMT) + SCOPE_NULLIFIED_P (*tp) = 1; } else if (code == TEMPLATE_TEMPLATE_PARM) /* These must be copied specially. */ *tp = copy_template_template_parm (*tp); + else if (TREE_CODE_CLASS (code) == 't') + /* There's no need to copy types, or anything beneath them. */ + *walk_subtrees = 0; return NULL_TREE; } @@ -2605,41 +2665,143 @@ void init_tree () { make_lang_type_fn = cp_make_lang_type; - lang_unsave_expr_now = cplus_unsave_expr_now; + lang_unsave = cp_unsave; ggc_add_root (list_hash_table, sizeof (list_hash_table) / sizeof (struct list_hash *), sizeof (struct list_hash *), mark_list_hash); } -/* The C++ version of unsave_expr_now. - See gcc/tree.c:unsave_expr_now for comments. */ +/* The SAVE_EXPR pointed to by TP is being copied. If ST contains + information indicating to what new SAVE_EXPR this one should be + mapped, use that one. Otherwise, create a new node and enter it in + ST. FN is the function into which the copy will be placed. */ void -cplus_unsave_expr_now (expr) - tree expr; +remap_save_expr (tp, st, fn) + tree *tp; + splay_tree st; + tree fn; { - if (expr == NULL) - return; + splay_tree_node n; - else if (TREE_CODE (expr) == AGGR_INIT_EXPR) + /* See if we already encountered this SAVE_EXPR. */ + n = splay_tree_lookup (st, (splay_tree_key) *tp); + + /* If we didn't already remap this SAVE_EXPR, do so now. */ + if (!n) { - unsave_expr_now (TREE_OPERAND (expr,0)); - if (TREE_OPERAND (expr, 1) - && TREE_CODE (TREE_OPERAND (expr, 1)) == TREE_LIST) - { - tree exp = TREE_OPERAND (expr, 1); - while (exp) - { - unsave_expr_now (TREE_VALUE (exp)); - exp = TREE_CHAIN (exp); - } - } - unsave_expr_now (TREE_OPERAND (expr,2)); - return; + tree t = copy_node (*tp); + + /* The SAVE_EXPR is now part of the function into which we + are inlining this body. */ + SAVE_EXPR_CONTEXT (t) = fn; + /* And we haven't evaluated it yet. */ + SAVE_EXPR_RTL (t) = NULL_RTX; + /* Remember this SAVE_EXPR. */ + n = splay_tree_insert (st, + (splay_tree_key) *tp, + (splay_tree_value) t); } - else - return; + /* Replace this SAVE_EXPR with the copy. */ + *tp = (tree) n->value; } +/* Called via walk_tree. If *TP points to a DECL_STMT for a local + declaration, copies the declaration and enters it in the splay_tree + pointed to by DATA (which is really a `splay_tree *'). */ + +static tree +mark_local_for_remap_r (tp, walk_subtrees, data) + tree *tp; + int *walk_subtrees ATTRIBUTE_UNUSED; + void *data; +{ + tree t = *tp; + splay_tree st = (splay_tree) data; + + if ((TREE_CODE (t) == DECL_STMT + && nonstatic_local_decl_p (DECL_STMT_DECL (t))) + || TREE_CODE (t) == LABEL_STMT) + { + tree decl; + tree copy; + + /* Figure out what's being declared. */ + decl = (TREE_CODE (t) == DECL_STMT + ? DECL_STMT_DECL (t) : LABEL_STMT_LABEL (t)); + + /* Make a copy. */ + copy = copy_decl_for_inlining (decl, + DECL_CONTEXT (decl), + DECL_CONTEXT (decl)); + + /* Remember the copy. */ + splay_tree_insert (st, + (splay_tree_key) decl, + (splay_tree_value) copy); + } + + return NULL_TREE; +} + +/* Called via walk_tree when an expression is unsaved. Using the + splay_tree pointed to by ST (which is really a `splay_tree *'), + remaps all local declarations to appropriate replacements. */ + +static tree +cp_unsave_r (tp, walk_subtrees, data) + tree *tp; + int *walk_subtrees; + void *data; +{ + splay_tree st = (splay_tree) data; + splay_tree_node n; + + /* Only a local declaration (variable or label). */ + if (nonstatic_local_decl_p (*tp)) + { + /* Lookup the declaration. */ + n = splay_tree_lookup (st, (splay_tree_key) *tp); + + /* If it's there, remap it. */ + if (n) + *tp = (tree) n->value; + } + else if (TREE_CODE (*tp) == SAVE_EXPR) + remap_save_expr (tp, st, current_function_decl); + else + { + copy_tree_r (tp, walk_subtrees, NULL); + + /* Do whatever unsaving is required. */ + unsave_expr_1 (*tp); + } + + /* Keep iterating. */ + return NULL_TREE; +} + +/* Called by unsave_expr_now whenever an expression (*TP) needs to be + unsaved. */ + +static void +cp_unsave (tp) + tree *tp; +{ + splay_tree st; + + /* Create a splay-tree to map old local variable declarations to new + ones. */ + st = splay_tree_new (splay_tree_compare_pointers, NULL, NULL); + + /* Walk the tree once figuring out what needs to be remapped. */ + walk_tree (tp, mark_local_for_remap_r, st); + + /* Walk the tree again, copying, remapping, and unsaving. */ + walk_tree (tp, cp_unsave_r, st); + + /* Clean up. */ + splay_tree_delete (st); +}