C++ PATCH for inlining-on-trees
Mark Mitchell
mark@codesourcery.com
Thu Nov 25 12:31:00 GMT 1999
Here's the inlining-on-trees patch. The functionality is disabled,
and there is not command-line switch to turn it on. Such things will
be added when the functionality is a little more complete. At this
point, the only real limitation is that debugging information inlined
functions is wrong. If you want to play with the code, set
flag_inline_trees to 1 in decl2.c.
That will enable inlining-on-trees even without -O. The resulting
compiler passes the regression test-suite on i686-pc-linux-gnu.
At this point, inlining-on-trees doesn't really do much good (although
we do now inline `f<int>' in:
template <class T> inline void f(){};
template void f<int>();
void g() { f<int>(); }
which we did not before, oddly.) The real win when will come with the
next phase of this work, where we will not even bother to generate RTL
for a function until we know it needs to be written out. That should
enable considerable memory savings, especially because the tree-based
inliner knows that given:
inline void f() {}
inline void g() { f(); }
inline void h() { g(); }
there is no need to inline f into g; instead, we can just directly
inline both into h. This doesn't fire yet because we are still
generating RTL for g, so we need to inline f at that point.
After that phase is done, I'll do the debugging information bit, turn
this on by default (with -O2) in the C++ front-end, and write
something for the web-page.
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
1999-11-22 Mark Mitchell <mark@codesourcery.com>
* cp-tree.def (FUNCTION_NAME): New tree node.
* cp-tree.h (current_function_name_declared): Tweak documentation.
(lang_decl_flags): Add pretty_function_p, adjust dummy.
(DECL_PRETTY_FUNCTION_P): New macro.
* decl.c (cp_finish_decl): Handle declarations of __FUNCTION__,
etc., in a template function. Use at_function_scope_p instead of
expanding it inline.
* pt.c (tsubst_decl): Handle DECL_PRETTY_FUNCTION_P declarations
specially.
(tsubst): Handle FUNCTION_NAME.
(tsubst_copy): Likewise.
(instantiate_decl): Prevent redeclarations of __PRETTY_FUNCTION__,
etc. in instantiation.
* semantics.c (begin_compound_stmt): Declare __FUNCTION__, etc.,
even in template functions.
(setup_vtbl_ptr): Don't declare __PRETTY_FUNCTION in the
conditional scope at the top of a destructor.
* error.c (dump_function_decl): Use `[ with ... ]' syntax for
specializations too.
Index: Make-lang.in
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/Make-lang.in,v
retrieving revision 1.40
diff -c -p -r1.40 Make-lang.in
*** Make-lang.in 1999/09/13 03:57:39 1.40
--- Make-lang.in 1999/11/25 19:42:49
*************** CXX_SRCS = $(srcdir)/cp/call.c $(srcdir)
*** 118,124 ****
$(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
cc1plus$(exeext): $(P) $(CXX_SRCS) $(LIBDEPS) stamp-objlist c-common.o \
c-pragma.o $(srcdir)/cp/cp-tree.h $(srcdir)/cp/cp-tree.def \
--- 118,124 ----
$(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/optimize.c
cc1plus$(exeext): $(P) $(CXX_SRCS) $(LIBDEPS) stamp-objlist c-common.o \
c-pragma.o $(srcdir)/cp/cp-tree.h $(srcdir)/cp/cp-tree.def \
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/Makefile.in,v
retrieving revision 1.75
diff -c -p -r1.75 Makefile.in
*** Makefile.in 1999/11/05 09:21:53 1.75
--- Makefile.in 1999/11/25 19:42:49
*************** INCLUDES = -I. -I.. -I$(srcdir) -I$(srcd
*** 175,181 ****
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@
# Language-independent object files.
OBJS = `cat ../stamp-objlist` ../c-common.o ../c-pragma.o
--- 175,181 ----
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 optimize.o @extra_cxx_objs@
# Language-independent object files.
OBJS = `cat ../stamp-objlist` ../c-common.o ../c-pragma.o
*************** RTL_H = $(srcdir)/../rtl.h $(srcdir)/../
*** 202,213 ****
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
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 \
$(srcdir)/../except.h $(srcdir)/../output.h $(srcdir)/../system.h \
$(srcdir)/../toplev.h $(srcdir)/../ggc.h
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(BIG_SWITCHFLAG) \
--- 202,215 ----
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)/../../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) $(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) \
*************** $(srcdir)/hash.h: $(srcdir)/gxx.gperf
*** 239,302 ****
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) \
$(PARSE_H) input.c $(srcdir)/../flags.h hash.h lex.h \
! $(srcdir)/../c-pragma.h $(srcdir)/../system.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 \
lex.h decl.h $(srcdir)/../stack.h $(srcdir)/../output.h \
! $(srcdir)/../except.h $(srcdir)/../system.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 \
$(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)/../toplev.h $(srcdir)/../ggc.h $(RTL_H)
! cvt.o : cvt.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.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 \
$(srcdir)/../toplev.h
! errfn.o : errfn.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \
$(srcdir)/../toplev.h
! repo.o : repo.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.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 \
$(srcdir)/../flags.h $(srcdir)/../ggc.h
! dump.o: dump.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h
#
# These exist for maintenance purposes.
--- 241,306 ----
echo " ftp://sourceware.cygnus.com/pub/egcs/infrastructure/gperf* " >&2 ; \
exit 1 )
! 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)/../toplev.h \
$(srcdir)/../output.h $(srcdir)/../mbchar.h $(srcdir)/../ggc.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)/../toplev.h \
$(srcdir)/../hash.h $(srcdir)/../ggc.h $(RTL_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)/../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 $(CXX_TREE_H) decl.h \
$(srcdir)/../flags.h $(srcdir)/../toplev.h $(srcdir)/../convert.h
! search.o : search.c $(CXX_TREE_H) $(srcdir)/../stack.h \
! $(srcdir)/../flags.h $(srcdir)/../toplev.h $(RTL_H)
! tree.o : tree.c $(CXX_TREE_H) $(srcdir)/../flags.h \
! $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H) \
! ../insn-config.h $(srcdir)/../integrate.h
! ptree.o : ptree.c $(CXX_TREE_H) $(srcdir)/../system.h
! rtti.o : rtti.c $(CXX_TREE_H) $(srcdir)/../flags.h \
! $(srcdir)/../toplev.h
! except.o : except.c $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
! $(srcdir)/../except.h $(srcdir)/../toplev.h
! expr.o : expr.c $(CXX_TREE_H) $(RTL_H) $(srcdir)/../flags.h \
! $(EXPR_H) $(srcdir)/../toplev.h $(srcdir)/../except.h
! xref.o : xref.c $(CXX_TREE_H) $(srcdir)/../input.h \
! $(srcdir)/../toplev.h
! pt.o : pt.c $(CXX_TREE_H) decl.h $(PARSE_H) lex.h \
! $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H) \
! $(srcdir)/../except.h
! error.o : error.c $(CXX_TREE_H) \
$(srcdir)/../toplev.h
! errfn.o : errfn.c $(CXX_TREE_H) \
$(srcdir)/../toplev.h
! repo.o : repo.c $(CXX_TREE_H) \
$(srcdir)/../toplev.h $(srcdir)/../ggc.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 $(CXX_TREE_H)
! optimize.o: optimize.c $(CXX_TREE_H) \
! $(srcdir)/../rtl.h $(srcdir)/../integrate.h ../insn-config.h
#
# These exist for maintenance purposes.
Index: class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.201
diff -c -p -r1.201 class.c
*** class.c 1999/11/16 01:37:38 1.201
--- class.c 1999/11/25 19:42:52
*************** Boston, MA 02111-1307, USA. */
*** 30,36 ****
#include "rtl.h"
#include "output.h"
#include "toplev.h"
- #include "splay-tree.h"
#include "ggc.h"
#include "lex.h"
--- 30,35 ----
Index: cp-tree.def
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.def,v
retrieving revision 1.41
diff -c -p -r1.41 cp-tree.def
*** cp-tree.def 1999/11/23 07:31:07 1.41
--- cp-tree.def 1999/11/25 19:42:52
*************** DEFTREECODE (ASM_STMT, "asm_stmt", 'e',
*** 237,245 ****
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)
/* 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. */
--- 237,247 ----
run if an exception is thrown before the end of the enclosing
function. */
DEFTREECODE (SUBOBJECT, "subobject", 'e', 1)
! /* An CTOR_STMT marks the beginning (if CTOR_BEGIN_P holds) or end of
! a contstructor (if CTOR_END_P) holds. At the end of a constructor,
! the cleanups associated with any SUBOBJECT_CLEANUPS need no longer
! be run. */
! DEFTREECODE (CTOR_STMT, "ctor_stmt", 'e', 0)
/* A CLEANUP_STMT marks the point at which a declaration is fully
constructed. If, after this point, the CLEANUP_DECL goes out of
scope, the CLEANUP_EXPR must be run. */
Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.354
diff -c -p -r1.354 cp-tree.h
*** cp-tree.h 1999/11/23 08:08:53 1.354
--- cp-tree.h 1999/11/25 19:42:55
*************** Boston, MA 02111-1307, USA. */
*** 21,26 ****
--- 21,27 ----
#include "c-common.h"
#include "function.h"
+ #include "splay-tree.h"
#include "varray.h"
#ifndef _CP_TREE_H
*************** Boston, MA 02111-1307, USA. */
*** 40,45 ****
--- 41,47 ----
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.
*************** extern int flag_new_for_scope;
*** 2121,2126 ****
--- 2123,2132 ----
#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)
*************** extern int flag_new_for_scope;
*** 2691,2696 ****
--- 2697,2710 ----
#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)))
*************** extern int flag_new_abi;
*** 3107,3112 ****
--- 3121,3131 ----
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;
*************** extern tree maybe_push_decl
*** 3532,3537 ****
--- 3551,3558 ----
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));
*************** extern void emit_thunk PROTO((tree));
*** 3744,3749 ****
--- 3765,3773 ----
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));
*************** extern tree arbitrate_lookup PROTO((tr
*** 3960,3966 ****
/* 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));
--- 3984,3989 ----
*************** extern tree maybe_dummy_object PROTO((
*** 4028,4036 ****
--- 4051,4061 ----
extern int is_dummy_object PROTO((tree));
typedef tree (*walk_tree_fn) PROTO((tree *, int *, void *));
extern tree walk_tree PROTO((tree *, walk_tree_fn, void *));
+ extern tree copy_tree_r PROTO((tree *, int *, void *));
extern int cp_valid_lang_attribute PROTO((tree, tree, tree, tree));
extern tree make_ptrmem_cst PROTO((tree, tree));
extern tree cp_build_qualified_type_real PROTO((tree, int, int));
+ extern void remap_save_expr PROTO((tree *, splay_tree, tree));
#define cp_build_qualified_type(TYPE, QUALS) \
cp_build_qualified_type_real ((TYPE), (QUALS), /*complain=*/1)
Index: decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.509
diff -c -p -r1.509 decl.c
*** decl.c 1999/11/23 16:17:52 1.509
--- decl.c 1999/11/25 19:43:04
*************** static boolean typename_compare PROTO((h
*** 141,147 ****
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 find_binding PROTO((tree, tree));
static tree select_decl PROTO((tree, int));
static int lookup_flags PROTO((int, int));
--- 141,147 ----
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_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));
*************** make_rtl_for_local_static (decl)
*** 7362,7387 ****
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 (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
{
--- 7362,7371 ----
tree type = TREE_TYPE (decl);
const char *asmspec = NULL;
! /* 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))
{
*************** emit_local_var (decl)
*** 7543,7551 ****
{
/* 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. */
my_friendly_assert (TREE_CODE (decl) == RESULT_DECL,
19990828);
else
--- 7527,7534 ----
{
/* 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. */
my_friendly_assert (TREE_CODE (decl) == RESULT_DECL,
19990828);
else
*************** require_complete_types_for_parms (parms)
*** 11141,11167 ****
}
}
! /* Returns *TP if *TP is a local variable (or parameter). Returns
! NULL_TREE otherwise. */
! static tree
! local_variable_p (tp, walk_subtrees, data)
! tree *tp;
! int *walk_subtrees ATTRIBUTE_UNUSED;
! void *data ATTRIBUTE_UNUSED;
{
- 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)
|| (TREE_CODE (t) == PARM_DECL))
! return t;
! return NULL_TREE;
}
/* Check that ARG, which is a default-argument expression for a
--- 11124,11171 ----
}
}
! /* Returns non-zero if T is a local variable. */
! int
! local_variable_p (t)
! tree t;
{
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. */
! && !DECL_NAMESPACE_SCOPE_P (t))
|| (TREE_CODE (t) == PARM_DECL))
! return 1;
! 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
*************** check_default_argument (decl, arg)
*** 11230,11236 ****
The keyword `this' shall not be used in a default argument of a
member function. */
! var = walk_tree (&arg, local_variable_p, NULL);
if (var)
{
cp_error ("default argument `%E' uses local variable `%D'",
--- 11234,11240 ----
The keyword `this' shall not be used in a default argument of a
member function. */
! var = walk_tree (&arg, local_variable_p_walkfn, NULL);
if (var)
{
cp_error ("default argument `%E' uses local variable `%D'",
*************** start_function (declspecs, declarator, a
*** 13067,13075 ****
if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1))
&& DECL_LANGUAGE (decl1) == lang_cplusplus)
! dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
else if (DECL_CONSTRUCTOR_P (decl1))
! ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
return 1;
}
--- 13071,13085 ----
if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1))
&& DECL_LANGUAGE (decl1) == lang_cplusplus)
! {
! 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);
! DECL_CONTEXT (ctor_label) = current_function_decl;
! }
return 1;
}
*************** finish_constructor_body ()
*** 13295,13304 ****
/* 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));
}
/* At the end of every destructor we generate code to restore virtual
--- 13305,13312 ----
/* 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 constructor. */
! add_tree (build_min_nt (CTOR_STMT));
}
/* At the end of every destructor we generate code to restore virtual
Index: decl2.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl2.c,v
retrieving revision 1.283
diff -c -p -r1.283 decl2.c
*** decl2.c 1999/11/25 01:56:13 1.283
--- decl2.c 1999/11/25 19:43:08
*************** Boston, MA 02111-1307, USA. */
*** 42,48 ****
#include "toplev.h"
#include "dwarf2out.h"
#include "dwarfout.h"
- #include "splay-tree.h"
#include "ggc.h"
#if USE_CPPLIB
--- 42,47 ----
*************** int flag_new_abi;
*** 443,448 ****
--- 442,452 ----
/* Nonzero to not ignore namespace std. */
int flag_honor_std;
+
+ /* Nonzero if we should expand functions calls inline at the tree
+ level, rather than at the RTL level. */
+
+ int flag_inline_trees = 0;
/* Maximum template instantiation depth. Must be at least 17 for ANSI
compliance. */
Index: dump.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/dump.c,v
retrieving revision 1.26
diff -c -p -r1.26 dump.c
*** dump.c 1999/11/03 06:54:37 1.26
--- dump.c 1999/11/25 19:43:08
*************** Boston, MA 02111-1307, USA. */
*** 23,29 ****
#include "system.h"
#include "tree.h"
#include "cp-tree.h"
- #include "splay-tree.h"
/* Flags used with queue functions. */
#define DUMP_NONE 0
--- 23,28 ----
Index: except.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/except.c,v
retrieving revision 1.89
diff -c -p -r1.89 except.c
*** except.c 1999/11/18 17:52:27 1.89
--- except.c 1999/11/25 19:43:09
*************** expand_end_catch_block (blocks)
*** 564,570 ****
/* Cleanup the EH parameter. */
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_2);
! /* Cleanup the EH object. */
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
}
--- 564,570 ----
/* Cleanup the EH parameter. */
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_2);
! /* Cleanup the EH object. */
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
}
*************** expand_end_eh_spec (raises, try_block)
*** 615,620 ****
--- 615,621 ----
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);
*************** expand_throw (exp)
*** 804,815 ****
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.
So we have to protect the actual initialization of the
exception object with terminate(), but evaluate the expression
--- 805,814 ----
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.
So we have to protect the actual initialization of the
exception object with terminate(), but evaluate the expression
Index: init.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/init.c,v
retrieving revision 1.152
diff -c -p -r1.152 init.c
*** init.c 1999/11/21 17:44:34 1.152
--- init.c 1999/11/25 19:43:11
*************** build_vec_delete_1 (base, maxindex, type
*** 2470,2476 ****
/* 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_init = build_modify_expr (tbase, NOP_EXPR,
fold (build (PLUS_EXPR, ptype,
base,
--- 2470,2476 ----
/* The below is short by BI_header_size */
virtual_size = fold (size_binop (MULT_EXPR, size_exp, maxindex));
! tbase = create_temporary_var (ptype);
tbase_init = build_modify_expr (tbase, NOP_EXPR,
fold (build (PLUS_EXPR, ptype,
base,
Index: ir.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/ir.texi,v
retrieving revision 1.21
diff -c -p -r1.21 ir.texi
*** ir.texi 1999/11/23 07:31:07 1.21
--- ir.texi 1999/11/25 19:43:13
*************** following the @code{TREE_CHAIN} link fro
*** 1274,1282 ****
Used to represent a @code{continue} statement. There are no additional
fields.
! @item CTOR_COMPLETE
! Used to mark the end of the main body of a constructor.
@item DECL_STMT
--- 1274,1284 ----
Used to represent a @code{continue} statement. There are no additional
fields.
! @item CTOR_STMT
! 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
*************** equalit) to @code{CATCH_ALL_TYPE} if thi
*** 1387,1395 ****
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.
@item SWITCH_STMT
--- 1389,1397 ----
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 @code{CTOR_STMT} with @code{CTOR_END_P} set
! is encountered, the @code{SUBOBJECT_CLEANUP} must be executed. The
! cleanups must be executed in the reverse order in which they appear.
@item SWITCH_STMT
Index: lex.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/lex.c,v
retrieving revision 1.164
diff -c -p -r1.164 lex.c
*** lex.c 1999/11/23 16:17:52 1.164
--- lex.c 1999/11/25 19:43:15
*************** my_get_run_time ()
*** 405,411 ****
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
! char cplus_tree_code_type[] = {
'x',
#include "cp-tree.def"
};
--- 405,411 ----
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
! static char cplus_tree_code_type[] = {
'x',
#include "cp-tree.def"
};
*************** char cplus_tree_code_type[] = {
*** 417,423 ****
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
! int cplus_tree_code_length[] = {
0,
#include "cp-tree.def"
};
--- 417,423 ----
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
! static int cplus_tree_code_length[] = {
0,
#include "cp-tree.def"
};
*************** int cplus_tree_code_length[] = {
*** 427,433 ****
Used for printing out the tree and error messages. */
#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
! const char *cplus_tree_code_name[] = {
"@@dummy",
#include "cp-tree.def"
};
--- 427,433 ----
Used for printing out the tree and error messages. */
#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
! static const char *cplus_tree_code_name[] = {
"@@dummy",
#include "cp-tree.def"
};
Index: optimize.c
===================================================================
RCS file: optimize.c
diff -N optimize.c
*** /dev/null Tue May 5 13:32:27 1998
--- optimize.c Thu Nov 25 11:43:16 1999
***************
*** 0 ****
--- 1,497 ----
+ /* Perform optimizations on tree structure.
+
+ Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ Written by Mark Michell (mark@codesourcery.com).
+
+ This file is part of GNU CC.
+
+ GNU CC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU CC is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU CC; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
+
+ #include "config.h"
+ #include "system.h"
+ #include "tree.h"
+ #include "cp-tree.h"
+ #include "rtl.h"
+ #include "insn-config.h"
+ #include "integrate.h"
+ #include "varray.h"
+
+ /* To Do:
+
+ o Provide debugging information for inlined function bodies.
+
+ o In order to make inlining-on-trees work, we pessimized
+ function-local static constants. In particular, they are now
+ always output, even when not addressed. Fix this by treating
+ function-local static constants just like global static
+ constants; the back-end already knows not to output them if they
+ are not needed.
+
+ o Provide heuristics to clamp inlining of recursive template
+ calls? */
+
+ /* Data required for function inlining. */
+
+ typedef struct inline_data
+ {
+ /* A stack of the functions we are inlining. For example, if we are
+ compiling `f', which calls `g', which calls `h', and we are
+ inlining the body of `h', the stack will contain, `h', followed
+ by `g', followed by `f'. */
+ varray_type fns;
+ /* The top of the FNS stack. */
+ size_t fns_top;
+ /* The label to jump to when a return statement is encountered. */
+ tree ret_label;
+ /* The map from local declarations in the inlined function to
+ equivalents in the function into which it is being inlined. */
+ splay_tree decl_map;
+ } inline_data;
+
+ /* Prototypes. */
+
+ static tree initialize_inlined_parameters PROTO((inline_data *, tree));
+ static tree declare_return_variable PROTO((inline_data *, tree *));
+ static tree copy_body_r PROTO((tree *, int *, void *));
+ static tree copy_body PROTO((inline_data *));
+ static tree expand_call_inline PROTO((tree *, int *, void *));
+ static void expand_calls_inline PROTO((tree *, inline_data *));
+ static int inlinable_function_p PROTO((tree, inline_data *));
+
+ /* Called from copy_body via walk_tree. DATA is really an
+ `inline_data *'. */
+
+ static tree
+ copy_body_r (tp, walk_subtrees, data)
+ tree *tp;
+ int *walk_subtrees;
+ void *data;
+ {
+ inline_data* id;
+ tree fn;
+
+ /* Set up. */
+ id = (inline_data *) data;
+ fn = VARRAY_TREE (id->fns, id->fns_top - 1);
+
+ /* All automatic variables should have a DECL_CONTEXT indicating
+ what function they come from. */
+ if ((TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == LABEL_DECL)
+ && DECL_NAMESPACE_SCOPE_P (*tp))
+ my_friendly_assert (DECL_EXTERNAL (*tp) || TREE_STATIC (*tp),
+ 19991113);
+
+ /* If this is a RETURN_STMT, change it into an EXPR_STMT and a
+ GOTO_STMT with the RET_LABEL as its target. */
+ if (TREE_CODE (*tp) == RETURN_STMT)
+ {
+ tree return_stmt = *tp;
+ tree goto_stmt;
+
+ /* Build the GOTO_STMT. */
+ goto_stmt = build_min_nt (GOTO_STMT, id->ret_label);
+ TREE_CHAIN (goto_stmt) = TREE_CHAIN (return_stmt);
+
+ /* If we're returning something, just turn that into an
+ assignment into the equivalent of the original
+ RESULT_DECL. */
+ if (RETURN_EXPR (return_stmt))
+ {
+ *tp = build_min_nt (EXPR_STMT,
+ RETURN_EXPR (return_stmt));
+ /* And then jump to the end of the function. */
+ TREE_CHAIN (*tp) = goto_stmt;
+ }
+ /* If we're not returning anything just do the jump. */
+ else
+ *tp = goto_stmt;
+ }
+ /* Local variables and labels need to be replaced by equivalent
+ variables. We don't want to copy static variables; there's only
+ one of those, no matter how many times we inline the containing
+ function. */
+ else if (nonstatic_local_decl_p (*tp) && DECL_CONTEXT (*tp) == fn)
+ {
+ splay_tree_node n;
+
+ /* Look up the declaration. */
+ n = splay_tree_lookup (id->decl_map, (splay_tree_key) *tp);
+
+ /* If we didn't already have an equivalent for this declaration,
+ create one now. */
+ if (!n)
+ {
+ tree t;
+
+ /* Make a copy of the variable or label. */
+ t = copy_decl_for_inlining (*tp, fn,
+ VARRAY_TREE (id->fns, 0));
+ /* Remember it, so that if we encounter this local entity
+ again we can reuse this copy. */
+ n = splay_tree_insert (id->decl_map,
+ (splay_tree_key) *tp,
+ (splay_tree_value) t);
+ }
+
+ /* Replace this variable with the copy. */
+ *tp = (tree) n->value;
+ }
+ else if (TREE_CODE (*tp) == SAVE_EXPR)
+ remap_save_expr (tp, id->decl_map, VARRAY_TREE (id->fns, 0));
+ else if (TREE_CODE (*tp) == UNSAVE_EXPR)
+ my_friendly_abort (19991113);
+ /* Otherwise, just copy the node. Note that copy_tree_r already
+ knows not to copy VAR_DECLs, etc., so this is safe. */
+ else
+ {
+ copy_tree_r (tp, walk_subtrees, NULL);
+
+ /* The copied TARGET_EXPR has never been expanded, even if the
+ original node was expanded already. */
+ if (TREE_CODE (*tp) == TARGET_EXPR && TREE_OPERAND (*tp, 3))
+ TREE_OPERAND (*tp, 1) = TREE_OPERAND (*tp, 3);
+ /* Similarly, if we're copying a CALL_EXPR, the RTL for the
+ result is no longer valid. */
+ else if (TREE_CODE (*tp) == CALL_EXPR)
+ CALL_EXPR_RTL (*tp) = NULL_RTX;
+ }
+
+ /* Keep iterating. */
+ return NULL_TREE;
+ }
+
+ /* Make a copy of the body of FN so that it can be inserted inline in
+ another function. */
+
+ static tree
+ copy_body (id)
+ inline_data *id;
+ {
+ tree body;
+
+ body = DECL_SAVED_TREE (VARRAY_TREE (id->fns, id->fns_top - 1));
+ walk_tree (&body, copy_body_r, id);
+
+ return body;
+ }
+
+ /* Generate code to initialize the parameters of the function at the
+ top of the stack in ID from the ARGS (presented as a TREE_LIST). */
+
+ static tree
+ initialize_inlined_parameters (id, args)
+ inline_data *id;
+ tree args;
+ {
+ tree fn;
+ tree init_stmts;
+ tree parms;
+ tree a;
+ tree p;
+
+ /* Figure out what the parameters are. */
+ fn = VARRAY_TREE (id->fns, id->fns_top - 1);
+ parms = DECL_ARGUMENTS (fn);
+
+ /* Start with no initializations whatsoever. */
+ init_stmts = NULL_TREE;
+
+ /* Loop through the parameter declarations, replacing each with an
+ equivalent VAR_DECL, appropriately initialized. */
+ for (p = parms, a = args; p; a = TREE_CHAIN (a), p = TREE_CHAIN (p))
+ {
+ tree init_stmt;
+ tree var;
+
+ /* Make an equivalent VAR_DECL. */
+ var = copy_decl_for_inlining (p, fn, VARRAY_TREE (id->fns, 0));
+ /* Register the VAR_DECL as the equivalent for the PARM_DECL;
+ that way, when the PARM_DECL is encountered, it will be
+ automatically replaced by the VAR_DECL. */
+ splay_tree_insert (id->decl_map,
+ (splay_tree_key) p,
+ (splay_tree_value) var);
+ /* Initialize this VAR_DECL from the equivalent argument. If
+ the argument is an object, created via a constructor or copy,
+ this will not result in an extra copy: the TARGET_EXPR
+ representing the argument will be bound to VAR, and the
+ object will be constructed in VAR. */
+ init_stmt = build_min_nt (EXPR_STMT,
+ build (INIT_EXPR, TREE_TYPE (p),
+ var, TREE_VALUE (a)));
+ /* Declare this new variable. Note that we do this *after* the
+ initialization because we are going to reverse all the
+ initialization statements below. */
+ TREE_CHAIN (init_stmt) = build_min_nt (DECL_STMT, var);
+ /* Add this initialization to the list. */
+ TREE_CHAIN (TREE_CHAIN (init_stmt)) = init_stmts;
+ init_stmts = init_stmt;
+ }
+
+ /* The initialization statements have been built up in reverse
+ order. Straighten them out now. */
+ return nreverse (init_stmts);
+ }
+
+ /* Declare a return variable to replace the RESULT_DECL for the
+ function we are calling. An appropriate DECL_STMT is returned.
+ The USE_STMT is filled in to contain a use of the declaration to
+ indicate the return value of the function. */
+
+ static tree
+ declare_return_variable (id, use_stmt)
+ struct inline_data *id;
+ tree *use_stmt;
+ {
+ tree fn = VARRAY_TREE (id->fns, id->fns_top - 1);
+ tree result = DECL_RESULT (fn);
+ tree var;
+
+ /* We don't need to do anything for functions that don't return
+ anything. */
+ if (!result || same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (result)),
+ void_type_node))
+ {
+ *use_stmt = NULL_TREE;
+ return NULL_TREE;
+ }
+
+ /* Make an appropriate copy. */
+ var = copy_decl_for_inlining (result, fn, VARRAY_TREE (id->fns, 0));
+ /* Register the VAR_DECL as the equivalent for the RESULT_DECL; that
+ way, when the RESULT_DECL is encountered, it will be
+ automatically replaced by the VAR_DECL. */
+ splay_tree_insert (id->decl_map,
+ (splay_tree_key) result,
+ (splay_tree_value) var);
+
+ /* Build the USE_STMT. */
+ *use_stmt = build_min_nt (EXPR_STMT, var);
+
+ /* Build the declaration statement. */
+ return build_min_nt (DECL_STMT, var);
+ }
+
+ /* Returns non-zero if FN is a function that can be inlined. */
+
+ static int
+ inlinable_function_p (fn, id)
+ tree fn;
+ inline_data *id;
+ {
+ int inlinable;
+
+ /* If we've already decided this function shouldn't be inlined,
+ there's no need to check again. */
+ if (DECL_UNINLINABLE (fn))
+ return 0;
+
+ /* Assume it is not inlinable. */
+ inlinable = 0;
+
+ /* If the function was not declared `inline', then we don't inline
+ it. */
+ if (!DECL_INLINE (fn))
+ ;
+ /* If we don't have the function body available, we can't inline
+ it. */
+ else if (!DECL_SAVED_TREE (fn))
+ ;
+ /* We can't inline varargs functions. */
+ else if (varargs_function_p (fn))
+ ;
+ /* All is well. We can inline this function. Traditionally, GCC
+ has refused to inline functions using setjmp or alloca, or
+ functions whose values are returned in a PARALLEL, and a few
+ other such obscure conditions. We are not equally constrained at
+ the tree level. */
+ else
+ inlinable = 1;
+
+ /* Squirrel away the result so that we don't have to check again. */
+ DECL_UNINLINABLE (fn) = !inlinable;
+
+ /* Don't do recursive inlining, either. We don't record this in
+ DECL_UNLINABLE; we may be able to inline this function later. */
+ if (inlinable)
+ {
+ size_t i;
+
+ for (i = 0; i < id->fns_top; ++i)
+ if (VARRAY_TREE (id->fns, i) == fn)
+ inlinable = 0;
+ }
+
+ /* We can inline a template instantiation only if its fully
+ instantiated. */
+ if (inlinable
+ && DECL_TEMPLATE_INFO (fn)
+ && TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn)))
+ {
+ fn = instantiate_decl (fn);
+ inlinable = !TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn));
+ }
+
+ /* Return the result. */
+ return inlinable;
+ }
+
+ /* If *TP is CALL_EXPR, replace it with its inline expansion. */
+
+ static tree
+ expand_call_inline (tp, walk_subtrees, data)
+ tree *tp;
+ int *walk_subtrees;
+ void *data;
+ {
+ inline_data *id;
+ tree t;
+ tree expr;
+ tree chain;
+ tree fn;
+ tree use_stmt;
+ splay_tree st;
+
+ /* We're only interested in CALL_EXPRs. */
+ t = *tp;
+ if (TREE_CODE (t) != CALL_EXPR)
+ return NULL_TREE;
+
+ /* First, see if we can figure out what function is being called.
+ If we cannot, then there is no hope of inlining the function. */
+ fn = get_callee_fndecl (t);
+ if (!fn)
+ return NULL_TREE;
+
+ /* Don't try to inline functions that are not well-suited to
+ inlining. */
+ id = (inline_data *) data;
+ if (!inlinable_function_p (fn, id))
+ return NULL_TREE;
+
+ /* Return statements in the function body will be replaced by jumps
+ to the RET_LABEL. */
+ id->ret_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+ DECL_CONTEXT (id->ret_label) = VARRAY_TREE (id->fns, 0);
+
+ /* Build a statement-expression containing code to initialize the
+ arguments, the actual inline expansion of the body, and a label
+ for the return statements within the function to jump to. The
+ type of the statement expression is the return type of the
+ function call. */
+ expr = build_min (STMT_EXPR, TREE_TYPE (TREE_TYPE (fn)), NULL_TREE);
+
+ /* Record the function we are about to inline so that we can avoid
+ recursing into it. */
+ if (id->fns_top > id->fns->num_elements)
+ VARRAY_GROW (id->fns, 2 * id->fns->num_elements);
+ VARRAY_TREE (id->fns, id->fns_top++) = fn;
+
+ /* Local declarations will be replaced by their equivalents in this
+ map. */
+ st = id->decl_map;
+ id->decl_map = splay_tree_new (splay_tree_compare_pointers,
+ NULL, NULL);
+
+ /* Initialize the parameters. */
+ STMT_EXPR_STMT (expr)
+ = initialize_inlined_parameters (id, TREE_OPERAND (t, 1));
+
+ /* Declare the return variable for the function. */
+ STMT_EXPR_STMT (expr)
+ = chainon (STMT_EXPR_STMT (expr),
+ declare_return_variable (id, &use_stmt));
+
+ /* After we've initialized the parameters, we insert the body of the
+ function itself. */
+ STMT_EXPR_STMT (expr)
+ = chainon (STMT_EXPR_STMT (expr), copy_body (id));
+
+ /* Finally, mention the returned value so that the value of the
+ statement-expression is the returned value of the function. */
+ STMT_EXPR_STMT (expr) = chainon (STMT_EXPR_STMT (expr), use_stmt);
+
+ /* Clean up. */
+ splay_tree_delete (id->decl_map);
+ id->decl_map = st;
+
+ /* After the body of the function comes the RET_LABEL. */
+ STMT_EXPR_STMT (expr)
+ = chainon (STMT_EXPR_STMT (expr),
+ build_min_nt (LABEL_STMT, id->ret_label));
+
+ /* The new expression has side-effects if the old one did. */
+ TREE_SIDE_EFFECTS (expr) = TREE_SIDE_EFFECTS (t);
+ /* If the value of the new expression is ignored, that's OK. We
+ don't warn about this for CALL_EXPRs, so we shouldn't warn about
+ the equivalent inlined version either. */
+ TREE_USED (expr) = 1;
+
+ /* Replace the call by the inlined body. */
+ chain = TREE_CHAIN (*tp);
+ *tp = expr;
+ TREE_CHAIN (expr) = chain;
+
+ /* Recurse into the body of the just inlined function. */
+ expand_calls_inline (tp, id);
+ --id->fns_top;
+
+ /* Don't walk into subtrees. We've already handled them above. */
+ *walk_subtrees = 0;
+
+ /* Keep iterating. */
+ return NULL_TREE;
+ }
+
+ /* Walk over the entire tree *TP, replacing CALL_EXPRs with inline
+ expansions as appropriate. */
+
+ static void
+ expand_calls_inline (tp, id)
+ tree *tp;
+ inline_data *id;
+ {
+ /* Search through *TP, replacing all calls to inline functions by
+ appropriate equivalents. */
+ walk_tree (tp, expand_call_inline, id);
+ }
+
+ /* Optimize the body of FN. */
+
+ void
+ optimize_function (fn)
+ tree fn;
+ {
+ /* Expand calls to inline functions. */
+ if (flag_inline_trees)
+ {
+ inline_data id;
+
+ /* Clear out ID. */
+ bzero (&id, sizeof (id));
+
+ /* Don't allow recursion into FN. */
+ VARRAY_TREE_INIT (id.fns, 32, "fns");
+ VARRAY_TREE (id.fns, id.fns_top++) = fn;
+
+ /* Replace all calls to inline functions with the bodies of those
+ functions. */
+ expand_calls_inline (&DECL_SAVED_TREE (fn), &id);
+
+ /* Clean up. */
+ VARRAY_FREE (id.fns);
+ }
+ }
Index: semantics.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/semantics.c,v
retrieving revision 1.109
diff -c -p -r1.109 semantics.c
*** semantics.c 1999/11/23 07:31:07 1.109
--- semantics.c 1999/11/25 19:43:17
*************** finish_goto_stmt (destination)
*** 658,664 ****
TREE_USED (destination) = 1;
if (building_stmt_tree ())
! add_tree (build_min_nt (GOTO_STMT, destination));
else
{
emit_line_note (input_filename, lineno);
--- 658,673 ----
TREE_USED (destination) = 1;
if (building_stmt_tree ())
! {
! 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);
*************** setup_vtbl_ptr ()
*** 1183,1189 ****
(CTOR_INITIALIZER,
current_member_init_list, current_base_init_list));
else
! finish_expr_stmt (emit_base_init (current_class_type));
}
else if (DECL_DESTRUCTOR_P (current_function_decl)
&& !processing_template_decl)
--- 1192,1208 ----
(CTOR_INITIALIZER,
current_member_init_list, current_base_init_list));
else
! {
! 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)
*************** finish_label_address_expr (label)
*** 1592,1597 ****
--- 1611,1619 ----
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;
*************** expand_stmt (t)
*** 2268,2278 ****
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;
--- 2290,2295 ----
*************** expand_stmt (t)
*** 2309,2314 ****
--- 2326,2341 ----
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;
*************** expand_body (fn)
*** 2508,2513 ****
--- 2535,2543 ----
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. */
*************** expand_body (fn)
*** 2538,2546 ****
/* 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)
DECL_SAVED_TREE (fn) = NULL_TREE;
/* And restore the current source position. */
--- 2568,2584 ----
/* Generate code for the function. */
finish_function (lineno, 0);
! /* If possible, obliterate the body of the function so that it can
! be garbage collected. */
! if (flag_dump_translation_unit)
! /* Keep the body; we're going to dump it. */
! ;
! else if (DECL_INLINE (fn) && flag_inline_trees)
! /* We might need the body of this function so that we can expand
! it inline somewhere else. */
! ;
! else
! /* We don't need the body; blow it away. */
DECL_SAVED_TREE (fn) = NULL_TREE;
/* And restore the current source position. */
Index: tree.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/tree.c,v
retrieving revision 1.161
diff -c -p -r1.161 tree.c
*** tree.c 1999/11/14 20:29:06 1.161
--- tree.c 1999/11/25 19:43:18
*************** Boston, MA 02111-1307, USA. */
*** 28,34 ****
#include "rtl.h"
#include "toplev.h"
#include "ggc.h"
! #include "splay-tree.h"
static tree bot_manip PROTO((tree *, int *, void *));
static tree bot_replace PROTO((tree *, int *, void *));
--- 28,35 ----
#include "rtl.h"
#include "toplev.h"
#include "ggc.h"
! #include "insn-config.h"
! #include "integrate.h"
static tree bot_manip PROTO((tree *, int *, void *));
static tree bot_replace PROTO((tree *, int *, void *));
*************** static cp_lvalue_kind lvalue_p_1 PROTO((
*** 42,48 ****
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 tree build_target_expr PROTO((tree, tree));
#define CEIL(x,y) (((x) + (y) - 1) / (y))
--- 43,52 ----
static tree no_linkage_helper PROTO((tree *, int *, void *));
static tree build_srcloc PROTO((char *, int));
static void mark_list_hash PROTO ((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))
*************** build_cplus_new (type, init)
*** 259,264 ****
--- 263,269 ----
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.
*************** is_aggr_type_2 (t1, t2)
*** 1456,1461 ****
--- 1461,1505 ----
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
*************** walk_tree (tp, func, data)
*** 1594,1600 ****
/* Handle commmon cases up front. */
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
! || TREE_CODE_CLASS (code) == 'r')
{
int i;
--- 1638,1645 ----
/* Handle commmon cases up front. */
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
! || TREE_CODE_CLASS (code) == 'r'
! || TREE_CODE_CLASS (code) == 's')
{
int i;
*************** walk_tree (tp, func, data)
*** 1602,1607 ****
--- 1647,1657 ----
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;
}
*************** walk_tree (tp, func, data)
*** 1706,1712 ****
if (TYPE_PTRMEMFUNC_P (*tp))
WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
break;
!
default:
my_friendly_abort (19990803);
}
--- 1756,1762 ----
if (TYPE_PTRMEMFUNC_P (*tp))
WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
break;
!
default:
my_friendly_abort (19990803);
}
*************** no_linkage_check (t)
*** 1755,1764 ****
/* Passed to walk_tree. Copies the node pointed to, if appropriate. */
! static tree
copy_tree_r (tp, walk_subtrees, data)
tree *tp;
! int *walk_subtrees ATTRIBUTE_UNUSED;
void *data ATTRIBUTE_UNUSED;
{
enum tree_code code = TREE_CODE (*tp);
--- 1805,1814 ----
/* Passed to walk_tree. Copies the node pointed to, if appropriate. */
! tree
copy_tree_r (tp, walk_subtrees, data)
tree *tp;
! int *walk_subtrees;
void *data ATTRIBUTE_UNUSED;
{
enum tree_code code = TREE_CODE (*tp);
*************** copy_tree_r (tp, walk_subtrees, data)
*** 1767,1772 ****
--- 1817,1823 ----
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
*************** copy_tree_r (tp, walk_subtrees, data)
*** 1781,1792 ****
/* 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)
TREE_CHAIN (*tp) = chain;
}
else if (code == TEMPLATE_TEMPLATE_PARM)
/* These must be copied specially. */
*tp = copy_template_template_parm (*tp);
return NULL_TREE;
}
--- 1832,1852 ----
/* 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
! || 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;
}
*************** void
*** 2605,2645 ****
init_tree ()
{
make_lang_type_fn = cp_make_lang_type;
! lang_unsave_expr_now = cplus_unsave_expr_now;
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. */
void
! cplus_unsave_expr_now (expr)
! tree expr;
{
! if (expr == NULL)
! return;
! else if (TREE_CODE (expr) == AGGR_INIT_EXPR)
{
! 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;
}
else
! return;
}
--- 2665,2807 ----
init_tree ()
{
make_lang_type_fn = cp_make_lang_type;
! 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 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
! remap_save_expr (tp, st, fn)
! tree *tp;
! splay_tree st;
! tree fn;
{
! splay_tree_node n;
! /* 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)
{
! tree t = copy_node (*tp);
!
! /* The SAVE_EXPR is now part of the function into which we
! are inlining this body. */
! SAVE_EXPR_CONTEXT (t) = fn;
! /* And we haven't evaluated it yet. */
! SAVE_EXPR_RTL (t) = NULL_RTX;
! /* Remember this SAVE_EXPR. */
! n = splay_tree_insert (st,
! (splay_tree_key) *tp,
! (splay_tree_value) t);
}
+ /* Replace this SAVE_EXPR with the copy. */
+ *tp = (tree) n->value;
+ }
+
+ /* Called via walk_tree. If *TP points to a DECL_STMT for a local
+ declaration, copies the declaration and enters it in the splay_tree
+ pointed to by DATA (which is really a `splay_tree *'). */
+
+ static tree
+ mark_local_for_remap_r (tp, walk_subtrees, data)
+ tree *tp;
+ int *walk_subtrees ATTRIBUTE_UNUSED;
+ void *data;
+ {
+ tree t = *tp;
+ splay_tree st = (splay_tree) data;
+
+ if ((TREE_CODE (t) == DECL_STMT
+ && nonstatic_local_decl_p (DECL_STMT_DECL (t)))
+ || TREE_CODE (t) == LABEL_STMT)
+ {
+ tree decl;
+ tree copy;
+
+ /* Figure out what's being declared. */
+ decl = (TREE_CODE (t) == DECL_STMT
+ ? DECL_STMT_DECL (t) : LABEL_STMT_LABEL (t));
+
+ /* Make a copy. */
+ copy = copy_decl_for_inlining (decl,
+ DECL_CONTEXT (decl),
+ DECL_CONTEXT (decl));
+
+ /* Remember the copy. */
+ splay_tree_insert (st,
+ (splay_tree_key) decl,
+ (splay_tree_value) copy);
+ }
+
+ return NULL_TREE;
+ }
+
+ /* Called via walk_tree when an expression is unsaved. Using the
+ splay_tree pointed to by ST (which is really a `splay_tree *'),
+ remaps all local declarations to appropriate replacements. */
+
+ static tree
+ cp_unsave_r (tp, walk_subtrees, data)
+ tree *tp;
+ int *walk_subtrees;
+ void *data;
+ {
+ splay_tree st = (splay_tree) data;
+ splay_tree_node n;
+
+ /* Only a local declaration (variable or label). */
+ if (nonstatic_local_decl_p (*tp))
+ {
+ /* Lookup the declaration. */
+ n = splay_tree_lookup (st, (splay_tree_key) *tp);
+
+ /* If it's there, remap it. */
+ if (n)
+ *tp = (tree) n->value;
+ }
+ else if (TREE_CODE (*tp) == SAVE_EXPR)
+ remap_save_expr (tp, st, current_function_decl);
else
! {
! 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);
+ }
More information about the Gcc-patches
mailing list