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:
Mark Mitchell 1999-11-25 20:32:04 +00:00 committed by Mark Mitchell
parent 82d26ad03d
commit 46e8c075d0
16 changed files with 966 additions and 157 deletions

View 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

View 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 \

View 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
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.

View 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"

View 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. */

View 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)

View 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

View 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. */

View 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

View 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

View 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,

View 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

View 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"
};

497
gcc/cp/optimize.c Normal file
View 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);
}
}

View 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. */

View 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;
}
}
#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);
}