mirror of
git://gcc.gnu.org/git/gcc.git
synced 2024-12-20 04:38:58 +08:00
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
This commit is contained in:
parent
82d26ad03d
commit
46e8c075d0
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -175,7 +175,7 @@ INCLUDES = -I. -I.. -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../config -I$(srcdir)
|
||||
CXX_OBJS = call.o decl.o errfn.o expr.o pt.o typeck2.o \
|
||||
class.o decl2.o error.o lex.o parse.o ptree.o rtti.o spew.o typeck.o cvt.o \
|
||||
except.o friend.o init.o method.o search.o semantics.o tree.o xref.o \
|
||||
repo.o dump.o @extra_cxx_objs@
|
||||
repo.o dump.o optimize.o @extra_cxx_objs@
|
||||
|
||||
# Language-independent object files.
|
||||
OBJS = `cat ../stamp-objlist` ../c-common.o ../c-pragma.o
|
||||
@ -202,12 +202,14 @@ RTL_H = $(srcdir)/../rtl.h $(srcdir)/../rtl.def \
|
||||
TREE_H = $(srcdir)/../tree.h $(srcdir)/../real.h $(srcdir)/../tree.def \
|
||||
$(srcdir)/../machmode.h $(srcdir)/../machmode.def
|
||||
CXX_TREE_H = $(TREE_H) cp-tree.h $(srcdir)/../c-common.h cp-tree.def \
|
||||
$(srcdir)/../function.h $(srcdir)/../varray.h
|
||||
$(srcdir)/../function.h $(srcdir)/../varray.h \
|
||||
$(srcdir)/../../include/splay-tree.h \
|
||||
$(srcdir)/../system.h $(CONFIG_H)
|
||||
PARSE_H = $(srcdir)/parse.h
|
||||
PARSE_C = $(srcdir)/parse.c
|
||||
EXPR_H = $(srcdir)/../expr.h ../insn-codes.h
|
||||
|
||||
parse.o : $(PARSE_C) $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h lex.h \
|
||||
parse.o : $(PARSE_C) $(CXX_TREE_H) $(srcdir)/../flags.h lex.h \
|
||||
$(srcdir)/../except.h $(srcdir)/../output.h $(srcdir)/../system.h \
|
||||
$(srcdir)/../toplev.h $(srcdir)/../ggc.h
|
||||
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(BIG_SWITCHFLAG) \
|
||||
@ -239,64 +241,66 @@ $(srcdir)/hash.h: $(srcdir)/gxx.gperf
|
||||
echo " ftp://sourceware.cygnus.com/pub/egcs/infrastructure/gperf*" >&2 ; \
|
||||
exit 1 )
|
||||
|
||||
spew.o : spew.c $(CONFIG_H) $(CXX_TREE_H) $(PARSE_H) $(srcdir)/../flags.h \
|
||||
lex.h $(srcdir)/../system.h $(srcdir)/../toplev.h
|
||||
lex.o : lex.c $(CONFIG_H) $(CXX_TREE_H) \
|
||||
spew.o : spew.c $(CXX_TREE_H) $(PARSE_H) $(srcdir)/../flags.h \
|
||||
lex.h $(srcdir)/../toplev.h
|
||||
lex.o : lex.c $(CXX_TREE_H) \
|
||||
$(PARSE_H) input.c $(srcdir)/../flags.h hash.h lex.h \
|
||||
$(srcdir)/../c-pragma.h $(srcdir)/../system.h $(srcdir)/../toplev.h \
|
||||
$(srcdir)/../c-pragma.h $(srcdir)/../toplev.h \
|
||||
$(srcdir)/../output.h $(srcdir)/../mbchar.h $(srcdir)/../ggc.h
|
||||
decl.o : decl.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
decl.o : decl.c $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
lex.h decl.h $(srcdir)/../stack.h $(srcdir)/../output.h \
|
||||
$(srcdir)/../except.h $(srcdir)/../system.h $(srcdir)/../toplev.h \
|
||||
$(srcdir)/../except.h $(srcdir)/../toplev.h \
|
||||
$(srcdir)/../hash.h $(srcdir)/../ggc.h $(RTL_H)
|
||||
decl2.o : decl2.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
lex.h decl.h $(EXPR_H) $(srcdir)/../except.h \
|
||||
$(srcdir)/../output.h $(srcdir)/../except.h $(srcdir)/../system.h \
|
||||
decl2.o : decl2.c $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
lex.h decl.h $(EXPR_H) $(srcdir)/../output.h $(srcdir)/../except.h \
|
||||
$(srcdir)/../toplev.h $(srcdir)/../dwarf2out.h $(srcdir)/../dwarfout.h \
|
||||
$(srcdir)/../../include/splay-tree.h $(srcdir)/../ggc.h $(RTL_H)
|
||||
typeck2.o : typeck2.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../output.h
|
||||
typeck.o : typeck.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
|
||||
$(EXPR_H) $(srcdir)/../system.h $(srcdir)/../toplev.h
|
||||
class.o : class.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h \
|
||||
$(srcdir)/../../include/splay-tree.h $(RTL_H)
|
||||
call.o : call.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h $(RTL_H)
|
||||
friend.o : friend.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h
|
||||
init.o : init.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
|
||||
$(EXPR_H) $(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../ggc.h
|
||||
method.o : method.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \
|
||||
$(srcdir)/../ggc.h $(RTL_H)
|
||||
typeck2.o : typeck2.c $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
$(srcdir)/../toplev.h $(srcdir)/../output.h
|
||||
typeck.o : typeck.c $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
|
||||
$(EXPR_H) $(srcdir)/../toplev.h
|
||||
class.o : class.c $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
$(srcdir)/../toplev.h $(RTL_H)
|
||||
call.o : call.c $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
$(srcdir)/../toplev.h $(RTL_H)
|
||||
friend.o : friend.c $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
|
||||
$(srcdir)/../toplev.h
|
||||
init.o : init.c $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
|
||||
$(EXPR_H) $(srcdir)/../toplev.h $(srcdir)/../ggc.h \
|
||||
$(srcdir)/../except.h
|
||||
method.o : method.c $(CXX_TREE_H) \
|
||||
$(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H)
|
||||
cvt.o : cvt.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h decl.h \
|
||||
cvt.o : cvt.c $(CXX_TREE_H) decl.h \
|
||||
$(srcdir)/../flags.h $(srcdir)/../toplev.h $(srcdir)/../convert.h
|
||||
search.o : search.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../stack.h \
|
||||
$(srcdir)/../flags.h $(srcdir)/../system.h $(srcdir)/../toplev.h $(RTL_H)
|
||||
tree.o : tree.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H) \
|
||||
$(srcdir)/../../include/splay-tree.h
|
||||
ptree.o : ptree.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h
|
||||
rtti.o : rtti.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h
|
||||
except.o : except.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
|
||||
$(srcdir)/../except.h $(srcdir)/../system.h $(srcdir)/../toplev.h
|
||||
expr.o : expr.c $(CONFIG_H) $(CXX_TREE_H) $(RTL_H) $(srcdir)/../flags.h \
|
||||
$(EXPR_H) $(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../except.h
|
||||
xref.o : xref.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../input.h \
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h
|
||||
pt.o : pt.c $(CONFIG_H) $(CXX_TREE_H) decl.h $(PARSE_H) lex.h \
|
||||
$(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H)
|
||||
error.o : error.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \
|
||||
search.o : search.c $(CXX_TREE_H) $(srcdir)/../stack.h \
|
||||
$(srcdir)/../flags.h $(srcdir)/../toplev.h $(RTL_H)
|
||||
tree.o : tree.c $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
$(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H) \
|
||||
../insn-config.h $(srcdir)/../integrate.h
|
||||
ptree.o : ptree.c $(CXX_TREE_H) $(srcdir)/../system.h
|
||||
rtti.o : rtti.c $(CXX_TREE_H) $(srcdir)/../flags.h \
|
||||
$(srcdir)/../toplev.h
|
||||
errfn.o : errfn.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \
|
||||
except.o : except.c $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
|
||||
$(srcdir)/../except.h $(srcdir)/../toplev.h
|
||||
expr.o : expr.c $(CXX_TREE_H) $(RTL_H) $(srcdir)/../flags.h \
|
||||
$(EXPR_H) $(srcdir)/../toplev.h $(srcdir)/../except.h
|
||||
xref.o : xref.c $(CXX_TREE_H) $(srcdir)/../input.h \
|
||||
$(srcdir)/../toplev.h
|
||||
repo.o : repo.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \
|
||||
pt.o : pt.c $(CXX_TREE_H) decl.h $(PARSE_H) lex.h \
|
||||
$(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H) \
|
||||
$(srcdir)/../except.h
|
||||
error.o : error.c $(CXX_TREE_H) \
|
||||
$(srcdir)/../toplev.h
|
||||
errfn.o : errfn.c $(CXX_TREE_H) \
|
||||
$(srcdir)/../toplev.h
|
||||
repo.o : repo.c $(CXX_TREE_H) \
|
||||
$(srcdir)/../toplev.h $(srcdir)/../ggc.h
|
||||
semantics.o: semantics.c $(CONFIG_H) $(CXX_TREE_H) lex.h \
|
||||
$(srcdir)/../except.h $(srcdir)/../system.h $(srcdir)/../toplev.h \
|
||||
semantics.o: semantics.c $(CXX_TREE_H) lex.h \
|
||||
$(srcdir)/../except.h $(srcdir)/../toplev.h \
|
||||
$(srcdir)/../flags.h $(srcdir)/../ggc.h
|
||||
dump.o: dump.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h
|
||||
dump.o: dump.c $(CXX_TREE_H)
|
||||
optimize.o: optimize.c $(CXX_TREE_H) \
|
||||
$(srcdir)/../rtl.h $(srcdir)/../integrate.h ../insn-config.h
|
||||
|
||||
#
|
||||
# These exist for maintenance purposes.
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
@ -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"
|
||||
};
|
||||
|
497
gcc/cp/optimize.c
Normal file
497
gcc/cp/optimize.c
Normal file
@ -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);
|
||||
}
|
||||
}
|
@ -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. */
|
||||
|
222
gcc/cp/tree.c
222
gcc/cp/tree.c
@ -28,7 +28,8 @@ Boston, MA 02111-1307, USA. */
|
||||
#include "rtl.h"
|
||||
#include "toplev.h"
|
||||
#include "ggc.h"
|
||||
#include "splay-tree.h"
|
||||
#include "insn-config.h"
|
||||
#include "integrate.h"
|
||||
|
||||
static tree bot_manip PROTO((tree *, int *, void *));
|
||||
static tree bot_replace PROTO((tree *, int *, void *));
|
||||
@ -42,7 +43,10 @@ static cp_lvalue_kind lvalue_p_1 PROTO((tree, int));
|
||||
static tree no_linkage_helper PROTO((tree *, int *, void *));
|
||||
static tree build_srcloc PROTO((char *, int));
|
||||
static void mark_list_hash PROTO ((void *));
|
||||
static tree copy_tree_r PROTO ((tree *, int *, void *));
|
||||
static int statement_code_p PROTO((enum tree_code));
|
||||
static tree mark_local_for_remap_r PROTO((tree *, int *, void *));
|
||||
static tree cp_unsave_r PROTO ((tree *, int *, void *));
|
||||
static void cp_unsave PROTO((tree *));
|
||||
static tree build_target_expr PROTO((tree, tree));
|
||||
|
||||
#define CEIL(x,y) (((x) + (y) - 1) / (y))
|
||||
@ -259,6 +263,7 @@ build_cplus_new (type, init)
|
||||
|
||||
slot = build (VAR_DECL, type);
|
||||
DECL_ARTIFICIAL (slot) = 1;
|
||||
DECL_CONTEXT (slot) = current_function_decl;
|
||||
layout_decl (slot, 0);
|
||||
|
||||
/* We split the CALL_EXPR into its function and its arguments here.
|
||||
@ -1456,6 +1461,45 @@ is_aggr_type_2 (t1, t2)
|
||||
return 0;
|
||||
return IS_AGGR_TYPE (t1) && IS_AGGR_TYPE (t2);
|
||||
}
|
||||
|
||||
/* Returns non-zero if CODE is the code for a statement. */
|
||||
|
||||
static int
|
||||
statement_code_p (code)
|
||||
enum tree_code code;
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case EXPR_STMT:
|
||||
case COMPOUND_STMT:
|
||||
case DECL_STMT:
|
||||
case IF_STMT:
|
||||
case FOR_STMT:
|
||||
case WHILE_STMT:
|
||||
case DO_STMT:
|
||||
case RETURN_STMT:
|
||||
case BREAK_STMT:
|
||||
case CONTINUE_STMT:
|
||||
case SWITCH_STMT:
|
||||
case GOTO_STMT:
|
||||
case LABEL_STMT:
|
||||
case ASM_STMT:
|
||||
case SUBOBJECT:
|
||||
case CLEANUP_STMT:
|
||||
case START_CATCH_STMT:
|
||||
case CTOR_STMT:
|
||||
case SCOPE_STMT:
|
||||
case CTOR_INITIALIZER:
|
||||
case CASE_LABEL:
|
||||
case RETURN_INIT:
|
||||
case TRY_BLOCK:
|
||||
case HANDLER:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define PRINT_RING_SIZE 4
|
||||
|
||||
@ -1594,7 +1638,8 @@ walk_tree (tp, func, data)
|
||||
|
||||
/* Handle commmon cases up front. */
|
||||
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
|
||||
|| TREE_CODE_CLASS (code) == 'r')
|
||||
|| TREE_CODE_CLASS (code) == 'r'
|
||||
|| TREE_CODE_CLASS (code) == 's')
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -1602,6 +1647,11 @@ walk_tree (tp, func, data)
|
||||
for (i = first_rtl_op (code) - 1; i >= 0; --i)
|
||||
WALK_SUBTREE (TREE_OPERAND (*tp, i));
|
||||
|
||||
/* For statements, we also walk the chain so that we cover the
|
||||
entire statement tree. */
|
||||
if (statement_code_p (code))
|
||||
WALK_SUBTREE (TREE_CHAIN (*tp));
|
||||
|
||||
/* We didn't find what we were looking for. */
|
||||
return NULL_TREE;
|
||||
}
|
||||
@ -1706,7 +1756,7 @@ walk_tree (tp, func, data)
|
||||
if (TYPE_PTRMEMFUNC_P (*tp))
|
||||
WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
my_friendly_abort (19990803);
|
||||
}
|
||||
@ -1755,10 +1805,10 @@ no_linkage_check (t)
|
||||
|
||||
/* Passed to walk_tree. Copies the node pointed to, if appropriate. */
|
||||
|
||||
static tree
|
||||
tree
|
||||
copy_tree_r (tp, walk_subtrees, data)
|
||||
tree *tp;
|
||||
int *walk_subtrees ATTRIBUTE_UNUSED;
|
||||
int *walk_subtrees;
|
||||
void *data ATTRIBUTE_UNUSED;
|
||||
{
|
||||
enum tree_code code = TREE_CODE (*tp);
|
||||
@ -1767,6 +1817,7 @@ copy_tree_r (tp, walk_subtrees, data)
|
||||
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
|
||||
|| TREE_CODE_CLASS (code) == 'r'
|
||||
|| TREE_CODE_CLASS (code) == 'c'
|
||||
|| TREE_CODE_CLASS (code) == 's'
|
||||
|| code == PARM_DECL
|
||||
|| code == TREE_LIST
|
||||
|| code == TREE_VEC
|
||||
@ -1781,12 +1832,21 @@ copy_tree_r (tp, walk_subtrees, data)
|
||||
|
||||
/* Now, restore the chain, if appropriate. That will cause
|
||||
walk_tree to walk into the chain as well. */
|
||||
if (code == PARM_DECL || code == TREE_LIST || code == OVERLOAD)
|
||||
if (code == PARM_DECL || code == TREE_LIST || code == OVERLOAD
|
||||
|| statement_code_p (code))
|
||||
TREE_CHAIN (*tp) = chain;
|
||||
|
||||
/* For now, we don't update BLOCKs when we make copies. So, we
|
||||
have to nullify all scope-statements. */
|
||||
if (TREE_CODE (*tp) == SCOPE_STMT)
|
||||
SCOPE_NULLIFIED_P (*tp) = 1;
|
||||
}
|
||||
else if (code == TEMPLATE_TEMPLATE_PARM)
|
||||
/* These must be copied specially. */
|
||||
*tp = copy_template_template_parm (*tp);
|
||||
else if (TREE_CODE_CLASS (code) == 't')
|
||||
/* There's no need to copy types, or anything beneath them. */
|
||||
*walk_subtrees = 0;
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
@ -2605,41 +2665,143 @@ void
|
||||
init_tree ()
|
||||
{
|
||||
make_lang_type_fn = cp_make_lang_type;
|
||||
lang_unsave_expr_now = cplus_unsave_expr_now;
|
||||
lang_unsave = cp_unsave;
|
||||
ggc_add_root (list_hash_table,
|
||||
sizeof (list_hash_table) / sizeof (struct list_hash *),
|
||||
sizeof (struct list_hash *),
|
||||
mark_list_hash);
|
||||
}
|
||||
|
||||
/* The C++ version of unsave_expr_now.
|
||||
See gcc/tree.c:unsave_expr_now for comments. */
|
||||
/* The SAVE_EXPR pointed to by TP is being copied. If ST contains
|
||||
information indicating to what new SAVE_EXPR this one should be
|
||||
mapped, use that one. Otherwise, create a new node and enter it in
|
||||
ST. FN is the function into which the copy will be placed. */
|
||||
|
||||
void
|
||||
cplus_unsave_expr_now (expr)
|
||||
tree expr;
|
||||
remap_save_expr (tp, st, fn)
|
||||
tree *tp;
|
||||
splay_tree st;
|
||||
tree fn;
|
||||
{
|
||||
if (expr == NULL)
|
||||
return;
|
||||
splay_tree_node n;
|
||||
|
||||
else if (TREE_CODE (expr) == AGGR_INIT_EXPR)
|
||||
/* See if we already encountered this SAVE_EXPR. */
|
||||
n = splay_tree_lookup (st, (splay_tree_key) *tp);
|
||||
|
||||
/* If we didn't already remap this SAVE_EXPR, do so now. */
|
||||
if (!n)
|
||||
{
|
||||
unsave_expr_now (TREE_OPERAND (expr,0));
|
||||
if (TREE_OPERAND (expr, 1)
|
||||
&& TREE_CODE (TREE_OPERAND (expr, 1)) == TREE_LIST)
|
||||
{
|
||||
tree exp = TREE_OPERAND (expr, 1);
|
||||
while (exp)
|
||||
{
|
||||
unsave_expr_now (TREE_VALUE (exp));
|
||||
exp = TREE_CHAIN (exp);
|
||||
}
|
||||
}
|
||||
unsave_expr_now (TREE_OPERAND (expr,2));
|
||||
return;
|
||||
tree t = copy_node (*tp);
|
||||
|
||||
/* The SAVE_EXPR is now part of the function into which we
|
||||
are inlining this body. */
|
||||
SAVE_EXPR_CONTEXT (t) = fn;
|
||||
/* And we haven't evaluated it yet. */
|
||||
SAVE_EXPR_RTL (t) = NULL_RTX;
|
||||
/* Remember this SAVE_EXPR. */
|
||||
n = splay_tree_insert (st,
|
||||
(splay_tree_key) *tp,
|
||||
(splay_tree_value) t);
|
||||
}
|
||||
|
||||
else
|
||||
return;
|
||||
/* Replace this SAVE_EXPR with the copy. */
|
||||
*tp = (tree) n->value;
|
||||
}
|
||||
|
||||
/* Called via walk_tree. If *TP points to a DECL_STMT for a local
|
||||
declaration, copies the declaration and enters it in the splay_tree
|
||||
pointed to by DATA (which is really a `splay_tree *'). */
|
||||
|
||||
static tree
|
||||
mark_local_for_remap_r (tp, walk_subtrees, data)
|
||||
tree *tp;
|
||||
int *walk_subtrees ATTRIBUTE_UNUSED;
|
||||
void *data;
|
||||
{
|
||||
tree t = *tp;
|
||||
splay_tree st = (splay_tree) data;
|
||||
|
||||
if ((TREE_CODE (t) == DECL_STMT
|
||||
&& nonstatic_local_decl_p (DECL_STMT_DECL (t)))
|
||||
|| TREE_CODE (t) == LABEL_STMT)
|
||||
{
|
||||
tree decl;
|
||||
tree copy;
|
||||
|
||||
/* Figure out what's being declared. */
|
||||
decl = (TREE_CODE (t) == DECL_STMT
|
||||
? DECL_STMT_DECL (t) : LABEL_STMT_LABEL (t));
|
||||
|
||||
/* Make a copy. */
|
||||
copy = copy_decl_for_inlining (decl,
|
||||
DECL_CONTEXT (decl),
|
||||
DECL_CONTEXT (decl));
|
||||
|
||||
/* Remember the copy. */
|
||||
splay_tree_insert (st,
|
||||
(splay_tree_key) decl,
|
||||
(splay_tree_value) copy);
|
||||
}
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Called via walk_tree when an expression is unsaved. Using the
|
||||
splay_tree pointed to by ST (which is really a `splay_tree *'),
|
||||
remaps all local declarations to appropriate replacements. */
|
||||
|
||||
static tree
|
||||
cp_unsave_r (tp, walk_subtrees, data)
|
||||
tree *tp;
|
||||
int *walk_subtrees;
|
||||
void *data;
|
||||
{
|
||||
splay_tree st = (splay_tree) data;
|
||||
splay_tree_node n;
|
||||
|
||||
/* Only a local declaration (variable or label). */
|
||||
if (nonstatic_local_decl_p (*tp))
|
||||
{
|
||||
/* Lookup the declaration. */
|
||||
n = splay_tree_lookup (st, (splay_tree_key) *tp);
|
||||
|
||||
/* If it's there, remap it. */
|
||||
if (n)
|
||||
*tp = (tree) n->value;
|
||||
}
|
||||
else if (TREE_CODE (*tp) == SAVE_EXPR)
|
||||
remap_save_expr (tp, st, current_function_decl);
|
||||
else
|
||||
{
|
||||
copy_tree_r (tp, walk_subtrees, NULL);
|
||||
|
||||
/* Do whatever unsaving is required. */
|
||||
unsave_expr_1 (*tp);
|
||||
}
|
||||
|
||||
/* Keep iterating. */
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Called by unsave_expr_now whenever an expression (*TP) needs to be
|
||||
unsaved. */
|
||||
|
||||
static void
|
||||
cp_unsave (tp)
|
||||
tree *tp;
|
||||
{
|
||||
splay_tree st;
|
||||
|
||||
/* Create a splay-tree to map old local variable declarations to new
|
||||
ones. */
|
||||
st = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
|
||||
|
||||
/* Walk the tree once figuring out what needs to be remapped. */
|
||||
walk_tree (tp, mark_local_for_remap_r, st);
|
||||
|
||||
/* Walk the tree again, copying, remapping, and unsaving. */
|
||||
walk_tree (tp, cp_unsave_r, st);
|
||||
|
||||
/* Clean up. */
|
||||
splay_tree_delete (st);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user