1999-11-25 Mark Mitchell <mark@codesourcery.com>
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 25 Nov 1999 20:32:04 +0000 (20:32 +0000)
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 25 Nov 1999 20:32:04 +0000 (20:32 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@30669 138bc75d-0d04-0410-961f-82ee72b054a4

16 files changed:
gcc/cp/ChangeLog
gcc/cp/Make-lang.in
gcc/cp/Makefile.in
gcc/cp/class.c
gcc/cp/cp-tree.def
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/dump.c
gcc/cp/except.c
gcc/cp/init.c
gcc/cp/ir.texi
gcc/cp/lex.c
gcc/cp/optimize.c [new file with mode: 0644]
gcc/cp/semantics.c
gcc/cp/tree.c

index f089e4f..c020d43 100644 (file)
@@ -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
index 3051d91..ffb1b0c 100644 (file)
@@ -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 \
index 897697d..900823c 100644 (file)
@@ -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
 
 #\f
 # These exist for maintenance purposes.
index 19bd69c..a916123 100644 (file)
@@ -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"
 
index 59b14fd..6ccc874 100644 (file)
@@ -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.  */
index a83744e..3b1f402 100644 (file)
@@ -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)
 
index f24bb3f..0edcc25 100644 (file)
@@ -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
index 617d854..7759b0a 100644 (file)
@@ -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. */
 
index ef92f18..6e3fbcc 100644 (file)
@@ -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
index eb8cf0e..62cae27 100644 (file)
@@ -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
index da586e9..1361b96 100644 (file)
@@ -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,
index 09ae98d..b2e6a49 100644 (file)
@@ -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
 
index b7fc18f..ae2783f 100644 (file)
@@ -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 (file)
index 0000000..d81f544
--- /dev/null
@@ -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);
+    }
+}
index 7a030e6..2d70cb9 100644 (file)
@@ -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.  */
index 15f66da..93893b3 100644 (file)
@@ -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;
+    }
+}
 \f
 #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);
+}