aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>1999-11-25 20:32:04 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>1999-11-25 20:32:04 +0000
commit46e8c075d018b365ce2a7ebba396ebcf3235c6d5 (patch)
tree6a30aa313c71b882f0e7584378a69d423e4e3c9b
parent82d26ad03d70cfdccf19a9f97bf9d58fcebaba95 (diff)
downloadgcc-46e8c075d018b365ce2a7ebba396ebcf3235c6d5.zip
gcc-46e8c075d018b365ce2a7ebba396ebcf3235c6d5.tar.gz
gcc-46e8c075d018b365ce2a7ebba396ebcf3235c6d5.tar.bz2
Make-lang.in (CXX_SRCS): Add optimize.c.
1999-11-25 Mark Mitchell <mark@codesourcery.com> * 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. From-SVN: r30669
-rw-r--r--gcc/cp/ChangeLog70
-rw-r--r--gcc/cp/Make-lang.in2
-rw-r--r--gcc/cp/Makefile.in104
-rw-r--r--gcc/cp/class.c1
-rw-r--r--gcc/cp/cp-tree.def8
-rw-r--r--gcc/cp/cp-tree.h27
-rw-r--r--gcc/cp/decl.c94
-rw-r--r--gcc/cp/decl2.c6
-rw-r--r--gcc/cp/dump.c1
-rw-r--r--gcc/cp/except.c13
-rw-r--r--gcc/cp/init.c2
-rw-r--r--gcc/cp/ir.texi12
-rw-r--r--gcc/cp/lex.c6
-rw-r--r--gcc/cp/optimize.c497
-rw-r--r--gcc/cp/semantics.c58
-rw-r--r--gcc/cp/tree.c220
16 files changed, 965 insertions, 156 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index f089e4f..c020d43 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,73 @@
+1999-11-25 Mark Mitchell <mark@codesourcery.com>
+
+ * 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 <jason@casey.cygnus.com>
* 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 3051d91..ffb1b0c 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 897697d..900823c 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
+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
+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 $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \
+errfn.o : errfn.c $(CXX_TREE_H) \
$(srcdir)/../toplev.h
-repo.o : repo.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.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 19bd69c..a916123 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 59b14fd..6ccc874 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 a83744e..3b1f402 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 f24bb3f..0edcc25 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 617d854..7759b0a 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 ef92f18..6e3fbcc 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 eb8cf0e..62cae27 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 da586e9..1361b96 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 09ae98d..b2e6a49 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 b7fc18f..ae2783f 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 0000000..d81f544
--- /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 7a030e6..2d70cb9 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 15f66da..93893b3 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);
+ }
+
+ /* 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
- return;
+ {
+ 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);
+}