This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Tree inlining for the C front end (part 1 of 3)


I've been working on tree inlining for other languages, particularly
the C front end.  To that extent, I started modifying functions that I
perceived as useful for language-independent tree inlining (*) so that
they didn't rely on internals of the C++ front-end.  Where
C++-specific behavior was necessary, I introduce language-specific
hooks, for whose names I'm open to suggestions.

This is the purpose of this first patch of a series of 3.  While I was
at it, I moved some tree declaration members to the generic tree
structure, as an incentive for other front-ends to adopt tree
inlining.  The alternative was to introduce yet another
language-specific hook, an idea I was not fond of.

This patch shouldn't introduce any functional changes, fact that was
verified by bootstrapping GCC on athlon-pc-linux-gnu and verifying
that there were no regressions in the testsuite.


The second patch of the series (that I'll only post after I get this
one reviewed) will solely move the selected functions to
tree-inline.c.  No change at all will be made to the functions in that
patch.


The third patch will finally enable tree inlining in the C front-end.


Is this first patch ok to install?

Index: gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* Makefile.in (OBJS): Added tree-inline.o.
	(c-common.o): Depend on tree-inline.h.
	(tree-inline.o): New target.
	* c-common.c: Include tree-inline.h.
	(c_mark_lang_decl): Don't mark saved_tree.
	(c_common_lang_init): Set lang_anon_aggr_type_p.
	* c-common.h (walk_tree_fn, DECL_SAVED_TREE): Moved to tree.h.
	(struct c_lang_decl): Moved saved_tree to tree_decl.
	* ggc-common.o: Mark saved_tree and inlined_fns of FUNCTION_DECLs.
	* tree-inline.c: New file.  Define variables declared in...
	* tree-inline.h: New file.  Declare functions to be moved to
	tree-inline.c.  Define macros and declare types and hooks for
	language-specific tree inlining.
	(flag_inline_trees): Moved definition from cp/decl2.c.
	* tree.h (walk_tree_fn, DECL_SAVED_TREE): Moved from c-common.h.
	(TREE_READONLY_DECL_P, DECL_INLINED_FNS): Moved from cp/cp-tree.h.
	(struct tree_decl): Moved saved_tree from c_lang_decl and
	inlined_fns from C++'s lang_decl.

Index: gcc/cp/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* Make-lang.in (cp/decl.o, cp/tree.o): Depend on tree-inline.h.
	(cp/semantics.o, cp/optimize.o): Likewise.
	* cp-tree.h (lang_decl): Moved inlined_fns to tree_decl.
	(TREE_READONLY_DECL_P, DECL_INLINED_FNS): Moved to ../tree.h.
	(flag_inline_trees): Moved declaration to ../tree-inline.h.
	(walk_tree): Moved declaration to ../tree-inline.h.
	(walk_tree_without_duplicates, copy_tree_r): Likewise.
	(remap_save_expr): Likewise.
	* decl.c: Include tree-inline.h.
	(lang_mark_tree): Don't mark inlined_fns.
	* decl2.c (flag_inline_trees): Moved defn to ../tree-inline.c.
	* optimize.c: Include tree-inline.h.
	(optimize_inline_calls): Move declaration to ../tree.h, as
	non-static.
	(remap_decl): Use language-independent constructs and hooks.
	(remap_block, copy_body_r, declare_return_variable): Likewise.
	(inlinable_function_p): Likewise.  Don't test for
	DECL_LANG_SPECIFIC before DECL_INLINED_FNS as inlined_fns is
	no longer language-specific.
	(optimize_inline_calls): Likewise.  Make it non-static.  Moved
	call of dump_function to...
	(optimize_function): Here...
	(clone_body): New function, extracted from...
	(maybe_clone_body): ... here.  Build decl_map locally and pass
	it on to clone_body.
	* semantics.c: Include tree-inline.h.
	* tree.c: Likewise.
	(cp_walk_subtrees): New language-specific hook for tree inlining.
	(cp_cannot_inline_tree_fn, cp_add_pending_fn_decls,
	cp_is_overload_p, cp_auto_var_in_fn_p,
	cp_copy_res_decl_for_inlining): Likewise.
	(walk_tree): Move language-specific constructs into...
	(cp_walk_subtrees): this new function.
	(copy_tree_r): Use language-independent constructs and hooks.
	(init_tree): Initialize tree inlining hooks.
	(remap_save_expr): Adjust prototype so that the declaration
	does not require the definition of splay_tree.

Index: gcc/Makefile.in
===================================================================
RCS file: /cvs/gcc/egcs/gcc/Makefile.in,v
retrieving revision 1.736
diff -u -p -r1.736 Makefile.in
--- gcc/Makefile.in 2001/09/20 15:12:54 1.736
+++ gcc/Makefile.in 2001/09/23 05:45:27
@@ -747,7 +747,7 @@ OBJS =									\
  sdbout.o sibcall.o simplify-rtx.o splay-tree.o ssa.o ssa-ccp.o         \
  ssa-dce.o stmt.o stor-layout.o stringpool.o timevar.o toplev.o tree.o  \
  unroll.o varasm.o varray.o version.o xcoffout.o cfg.o cfganal.o	\
- cfgbuild.o cfgcleanup.o cfgloop.o        \
+ cfgbuild.o cfgcleanup.o cfgloop.o tree-inline.o       \
  $(GGC) $(out_object_file) $(EXTRA_OBJS)
 
 BACKEND = main.o libbackend.a
@@ -1248,7 +1248,7 @@ s-under: $(GCC_PASSES)
 
 c-common.o : c-common.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(OBSTACK_H) \
 	$(C_COMMON_H) flags.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \
-	$(EXPR_H) $(TM_P_H) builtin-types.def $(TARGET_H)
+	$(EXPR_H) $(TM_P_H) builtin-types.def $(TARGET_H) tree-inline.h
 
 c-format.o : c-format.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \
 	$(C_COMMON_H) flags.h toplev.h intl.h diagnostic.h
@@ -1343,6 +1343,8 @@ convert.o: convert.c $(CONFIG_H) $(SYSTE
 
 tree.o : tree.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) flags.h function.h toplev.h \
    $(GGC_H) $(HASHTAB_H) $(TARGET_H) output.h $(TM_P_H)
+tree-inline.o : tree-inline.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \
+   tree-inline.h
 print-tree.o : print-tree.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(GGC_H)
 stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) flags.h \
    function.h $(EXPR_H) $(RTL_H) toplev.h $(GGC_H) $(TM_P_H)
Index: gcc/c-common.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-common.c,v
retrieving revision 1.251
diff -u -p -r1.251 c-common.c
--- gcc/c-common.c 2001/09/15 19:47:38 1.251
+++ gcc/c-common.c 2001/09/23 05:45:28
@@ -22,6 +22,7 @@ Software Foundation, 59 Temple Place - S
 #include "config.h"
 #include "system.h"
 #include "tree.h"
+#include "tree-inline.h"
 #include "flags.h"
 #include "toplev.h"
 #include "output.h"
@@ -3938,7 +3939,6 @@ void
 c_mark_lang_decl (c)
      struct c_lang_decl *c;
 {
-  ggc_mark_tree (c->saved_tree);
 }
 
 /* Mark F for GC.  */
@@ -4406,6 +4406,8 @@ c_common_lang_init ()
   /* If still "unspecified", make it match -fbounded-pointers.  */
   if (flag_bounds_check < 0)
     flag_bounds_check = flag_bounded_pointers;
+
+  lang_anon_aggr_type_p = anon_aggr_type_p;
 
   /* Special format checking options don't work without -Wformat; warn if
      they are used.  */
Index: gcc/c-common.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-common.h,v
retrieving revision 1.83
diff -u -p -r1.83 c-common.h
--- gcc/c-common.h 2001/09/04 12:12:50 1.83
+++ gcc/c-common.h 2001/09/23 05:45:28
@@ -316,12 +316,6 @@ extern void (*lang_expand_function_end) 
 extern int (*lang_missing_noreturn_ok_p)	PARAMS ((tree));
 
 
-/* The type of a function that walks over tree structure.  */
-
-typedef tree (*walk_tree_fn)                    PARAMS ((tree *,
-							 int *,
-							 void *));
-
 extern stmt_tree current_stmt_tree              PARAMS ((void));
 extern tree *current_scope_stmt_stack           PARAMS ((void));
 extern void begin_stmt_tree                     PARAMS ((tree *));
@@ -344,16 +338,8 @@ extern void mark_stmt_tree              
    DECL_LANG_SPECIFIC field.  */
 
 struct c_lang_decl {
-  /* In a FUNCTION_DECL, this is DECL_SAVED_TREE.  */
-  tree saved_tree;
+  char dummy;
 };
-
-/* In a FUNCTION_DECL, the saved representation of the body of the
-   entire function.  Usually a COMPOUND_STMT, but in C++ this may also
-   be a RETURN_INIT, CTOR_INITIALIZER, or TRY_BLOCK.  */
-#define DECL_SAVED_TREE(NODE)						    \
-  (((struct c_lang_decl *) DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (NODE))) \
-   ->saved_tree)
 
 /* In a FUNCTION_DECL for which DECL_BUILT_IN does not hold, this is
      the approximate number of statements in this function.  There is
Index: gcc/ggc-common.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/ggc-common.c,v
retrieving revision 1.42
diff -u -p -r1.42 ggc-common.c
--- gcc/ggc-common.c 2001/09/20 15:12:53 1.42
+++ gcc/ggc-common.c 2001/09/23 05:45:28
@@ -460,8 +460,13 @@ ggc_mark_trees ()
 	  ggc_mark_tree (DECL_VINDEX (t));
 	  if (DECL_ASSEMBLER_NAME_SET_P (t))
 	    ggc_mark_tree (DECL_ASSEMBLER_NAME (t));
-	  if (TREE_CODE (t) == FUNCTION_DECL && DECL_SAVED_INSNS (t))
-	    ggc_mark_struct_function (DECL_SAVED_INSNS (t));
+	  if (TREE_CODE (t) == FUNCTION_DECL)
+	    {
+	      ggc_mark_tree (DECL_SAVED_TREE (t));
+	      ggc_mark_tree (DECL_INLINED_FNS (t));
+	      if (DECL_SAVED_INSNS (t))
+		ggc_mark_struct_function (DECL_SAVED_INSNS (t));
+	    }
 	  lang_mark_tree (t);
 	  break;
 
Index: gcc/tree-inline.c
===================================================================
RCS file: tree-inline.c
diff -N tree-inline.c
--- /dev/null	Tue May  5 13:32:27 1998
+++ gcc/tree-inline.c Sat Sep 22 22:45:28 2001
@@ -0,0 +1,40 @@
+/* Control and data flow functions for trees.
+   Copyright 2001 Free Software Foundation, Inc.
+   Contributed by Alexandre Oliva <aoliva@redhat.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 "tree-inline.h"
+
+treeopt_walk_tree_type *lang_walk_subtrees;
+treeopt_cannot_inline_tree_fn_type *lang_cannot_inline_tree_fn;
+treeopt_add_pending_fn_decls_type *lang_add_pending_fn_decls;
+treeopt_tree_chain_matters_p_type *lang_tree_chain_matters_p;
+treeopt_lang_auto_var_in_fn_p_type *lang_auto_var_in_fn_p;
+treeopt_lang_copy_res_decl_for_inlining_type *lang_copy_res_decl_for_inlining;
+treeopt_lang_anon_aggr_type_p *lang_anon_aggr_type_p;
+
+/* 0 if we should not perform inlining.
+   1 if we should expand functions calls inline at the tree level.  
+   2 if we should consider *all* functions to be inline 
+   candidates.  */
+
+int flag_inline_trees = 0;
Index: gcc/tree-inline.h
===================================================================
RCS file: tree-inline.h
diff -N tree-inline.h
--- /dev/null	Tue May  5 13:32:27 1998
+++ gcc/tree-inline.h Sat Sep 22 22:45:28 2001
@@ -0,0 +1,128 @@
+/* Tree inlining hooks and declarations.
+   Copyright 2001 Free Software Foundation, Inc.
+   Contributed by Alexandre Oliva  <aoliva@redhat.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.  */
+
+#ifndef GCC_TREE_INLINE_H
+#define GCC_TREE_INLINE_H
+
+/* Function prototypes.  */
+
+void optimize_inline_calls PARAMS ((tree));
+tree walk_tree PARAMS ((tree*, walk_tree_fn, void*, void*));
+tree walk_tree_without_duplicates PARAMS ((tree*, walk_tree_fn, void*));
+tree copy_tree_r PARAMS ((tree*, int*, void*));
+void clone_body PARAMS ((tree, tree, void*));
+void remap_save_expr PARAMS ((tree *, void *, tree, int *));
+int varargs_function_p PARAMS ((tree));
+
+/* LANG_WALK_SUBTREES is called by walk_tree() after handling common
+   cases, but before walking code-specific sub-trees.  If
+   lang_walk_subtrees is defined for a language, it should handle
+   language-specific tree codes, as well as language-specific
+   information associated to common tree codes.  If a tree node is
+   completely handled within this function, it should set *SUBTREES to
+   0, so that generic handling isn't attempted.  For language-specific
+   tree codes, generic handling would abort(), so make sure it is set
+   properly.  Both SUBTREES and *SUBTREES is guaranteed to be non-zero
+   when the function is called.  */
+
+#define LANG_WALK_SUBTREES(TP,SUBTREES,FUNC,DATA,HTAB) \
+  (lang_walk_subtrees \
+   ? (*lang_walk_subtrees)((TP),(SUBTREES),(FUNC),(DATA),(HTAB)) \
+   : 0)
+typedef tree treeopt_walk_tree_type PARAMS ((tree*, int*, walk_tree_fn,
+					     void*, void*));
+extern treeopt_walk_tree_type *lang_walk_subtrees;
+
+/* LANG_CANNOT_INLINE_TREE_FN is called to determine whether there are
+   language-specific reasons for not inlining a given function.  */
+
+#define LANG_CANNOT_INLINE_TREE_FN(FNP) \
+  (lang_cannot_inline_tree_fn ? (*lang_cannot_inline_tree_fn)(FNP) : 0)
+typedef int treeopt_cannot_inline_tree_fn_type PARAMS ((tree*));
+extern treeopt_cannot_inline_tree_fn_type *lang_cannot_inline_tree_fn;
+
+/* LANG_ADD_PENDING_FN_DECLS is called before starting to inline a
+   function, to push any language-specific functions that should not
+   be inlined into the current function, into VAFNP.  PFN is the top
+   of varray, and should be returned if no functions are pushed into
+   VAFNP.  The top of the varray should be returned.  */
+
+#define LANG_ADD_PENDING_FN_DECLS(VAFNP,PFN) \
+  (lang_add_pending_fn_decls \
+   ? (*lang_add_pending_fn_decls)((VAFNP),(PFN)) \
+   : (PFN))
+typedef tree treeopt_add_pending_fn_decls_type PARAMS ((void*,tree));
+extern treeopt_add_pending_fn_decls_type *lang_add_pending_fn_decls;
+
+/* LANG_TREE_CHAIN_MATTERS_P indicates whether the TREE_CHAIN of a
+   language-specific tree node is relevant, i.e., whether it should be
+   walked, copied and preserved across copies.  */
+
+#define LANG_TREE_CHAIN_MATTERS_P(T) \
+  (lang_tree_chain_matters_p ? (*lang_tree_chain_matters_p)(T) : 0)
+typedef int treeopt_tree_chain_matters_p_type PARAMS ((tree));
+extern treeopt_tree_chain_matters_p_type *lang_tree_chain_matters_p;
+
+/* LANG_AUTO_VAR_IN_FN_P is called to determine whether VT is an
+   automatic variable defined in function FT.  */
+
+#define LANG_AUTO_VAR_IN_FN_P(VT,FT) \
+  (lang_auto_var_in_fn_p ? (*lang_auto_var_in_fn_p)((VT),(FT)) \
+   : (DECL_P (VT) && DECL_CONTEXT (VT) == (FT) \
+      && (((TREE_CODE (VT) == VAR_DECL || TREE_CODE (VT) == PARM_DECL) \
+	   && ! TREE_STATIC (VT)) \
+	  || TREE_CODE (VT) == LABEL_DECL \
+	  || TREE_CODE (VT) == RESULT_DECL)))
+typedef int treeopt_lang_auto_var_in_fn_p_type PARAMS ((tree,tree));
+extern treeopt_lang_auto_var_in_fn_p_type *lang_auto_var_in_fn_p;
+
+/* LANG_COPY_RES_DECL_FOR_INLINING should return a declaration for the
+   result RES of function FN to be inlined into CALLER.  NDP points to
+   an integer that should be set in case a new declaration wasn't
+   created (presumably because RES was of aggregate type, such that a
+   TARGET_EXPR is used for the result).  TEXPS is a pointer to a
+   varray with the stack of TARGET_EXPRs seen while inlining functions
+   into caller; the top of TEXPS is supposed to match RES.  */
+
+#define LANG_COPY_RES_DECL_FOR_INLINING(RES,FN,CALLER,DM,NDP,TEXPS) \
+  (lang_copy_res_decl_for_inlining \
+   ? (*lang_copy_res_decl_for_inlining)((RES),(FN),(CALLER),\
+					(DM),(NDP),(TEXPS)) \
+   : copy_decl_for_inlining ((RES), (FN), (CALLER)))
+typedef tree treeopt_lang_copy_res_decl_for_inlining_type PARAMS ((tree, tree,
+								   tree, void*,
+								   int*,
+								   void*));
+extern treeopt_lang_copy_res_decl_for_inlining_type
+*lang_copy_res_decl_for_inlining;
+
+/* LANG_ANON_AGGR_TYPE_P determines whether T is a type node
+   representing an anonymous aggregate (union, struct, etc), i.e., one
+   whose members are in the same scope as the union itself.  */
+
+#define LANG_ANON_AGGR_TYPE_P(T) \
+  (lang_anon_aggr_type_p ? (*lang_anon_aggr_type_p)(T) : 0)
+typedef int treeopt_lang_anon_aggr_type_p PARAMS ((tree));
+extern treeopt_lang_anon_aggr_type_p *lang_anon_aggr_type_p;
+
+extern int flag_inline_trees;
+
+#endif /* GCC_TREE_INLINE_H */
Index: gcc/tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tree.h,v
retrieving revision 1.264
diff -u -p -r1.264 tree.h
--- gcc/tree.h 2001/09/06 08:59:35 1.264
+++ gcc/tree.h 2001/09/23 05:45:28
@@ -560,6 +560,10 @@ extern void tree_class_check_failed PARA
    when the node is a type).  */
 #define TREE_READONLY(NODE) ((NODE)->common.readonly_flag)
 
+/* Non-zero if NODE is a _DECL with TREE_READONLY set.  */
+#define TREE_READONLY_DECL_P(NODE) \
+  (TREE_READONLY (NODE) && DECL_P (NODE))
+
 /* Value of expression is constant.
    Always appears in all ..._CST nodes.
    May also appear in an arithmetic expression, an ADDR_EXPR or a CONSTRUCTOR
@@ -1499,6 +1503,14 @@ struct tree_type
    is not error_mark_node, then the decl cannot be put in .common.  */
 #define DECL_COMMON(NODE) (DECL_CHECK (NODE)->decl.common_flag)
 
+/* In a FUNCTION_DECL, the saved representation of the body of the
+   entire function.  Usually a COMPOUND_STMT, but in C++ this may also
+   be a RETURN_INIT, CTOR_INITIALIZER, or TRY_BLOCK.  */
+#define DECL_SAVED_TREE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.saved_tree)
+
+/* List of FUNCION_DECLs inlined into this function's body.  */
+#define DECL_INLINED_FNS(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.inlined_fns)
+
 /* Language-specific decl information.  */
 #define DECL_LANG_SPECIFIC(NODE) (DECL_CHECK (NODE)->decl.lang_specific)
 
@@ -1770,6 +1782,13 @@ struct tree_decl
     int i;
   } u2;
 
+  /* In a FUNCTION_DECL, this is DECL_SAVED_TREE.  */
+  tree saved_tree;
+
+  /* In a FUNCTION_DECL, these are function data which is to be kept
+     as long as FUNCTION_DECL is kept.  */
+  tree inlined_fns;
+
   tree vindex;
   HOST_WIDE_INT pointer_alias_set;
   /* Points to a structure whose details depend on the language in use.  */
@@ -2943,6 +2962,10 @@ extern void dwarf2out_return_save	PARAMS
 /* Entry point for saving the return address in a register.  */
 
 extern void dwarf2out_return_reg	PARAMS ((const char *, unsigned));
+
+/* The type of a function that walks over tree structure.  */
+
+typedef tree (*walk_tree_fn)		PARAMS ((tree *, int *, void *));
 
 
 /* Redefine abort to report an internal error w/o coredump, and
Index: gcc/cp/Make-lang.in
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/Make-lang.in,v
retrieving revision 1.90
diff -u -p -r1.90 Make-lang.in
--- gcc/cp/Make-lang.in 2001/09/15 19:47:34 1.90
+++ gcc/cp/Make-lang.in 2001/09/23 05:45:28
@@ -242,7 +242,7 @@ cp/lex.o: cp/lex.c $(CXX_TREE_H) cp/pars
   $(TM_P_H)
 cp/decl.o: cp/decl.c $(CXX_TREE_H) flags.h cp/lex.h cp/decl.h stack.h \
   output.h $(EXPR_H) except.h toplev.h hash.h $(GGC_H) $(RTL_H) \
-  cp/operators.def $(TM_P_H)
+  cp/operators.def $(TM_P_H) tree-inline.h
 cp/decl2.o: cp/decl2.c $(CXX_TREE_H) flags.h cp/lex.h cp/decl.h $(EXPR_H) \
   output.h except.h toplev.h $(GGC_H) $(RTL_H)
 cp/typeck2.o: cp/typeck2.c $(CXX_TREE_H) flags.h toplev.h output.h $(TM_P_H) \
@@ -260,7 +260,7 @@ cp/method.o: cp/method.c $(CXX_TREE_H) t
 cp/cvt.o: cp/cvt.c $(CXX_TREE_H) cp/decl.h flags.h toplev.h convert.h
 cp/search.o: cp/search.c $(CXX_TREE_H) stack.h flags.h toplev.h $(RTL_H)
 cp/tree.o: cp/tree.c $(CXX_TREE_H) flags.h toplev.h $(GGC_H) $(RTL_H) \
-  insn-config.h integrate.h
+  insn-config.h integrate.h tree-inline.h
 cp/ptree.o: cp/ptree.c $(CXX_TREE_H) $(SYSTEM_H)
 cp/rtti.o: cp/rtti.c $(CXX_TREE_H) flags.h toplev.h
 cp/except.o: cp/except.c $(CXX_TREE_H) flags.h $(RTL_H) except.h toplev.h \
@@ -274,10 +274,11 @@ cp/error.o: cp/error.c $(CXX_TREE_H) top
 cp/errfn.o: cp/errfn.c $(CXX_TREE_H) toplev.h
 cp/repo.o: cp/repo.c $(CXX_TREE_H) toplev.h $(GGC_H) diagnostic.h
 cp/semantics.o: cp/semantics.c $(CXX_TREE_H) cp/lex.h except.h toplev.h \
-  flags.h $(GGC_H) debug.h output.h $(RTL_H) $(TIMEVAR_H) $(EXPR_H)
+  flags.h $(GGC_H) debug.h output.h $(RTL_H) $(TIMEVAR_H) $(EXPR_H) \
+  tree-inline.h
 cp/dump.o: cp/dump.c $(CXX_TREE_H) c-dump.h
 cp/optimize.o: cp/optimize.c $(CXX_TREE_H) rtl.h integrate.h insn-config.h \
-  input.h $(PARAMS_H) debug.h
+  input.h $(PARAMS_H) debug.h tree-inline.h
 cp/mangle.o: cp/mangle.c $(CXX_TREE_H) toplev.h
 
 cp/parse.o: cp/parse.c $(CXX_TREE_H) flags.h cp/lex.h except.h output.h \
Index: gcc/cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.640
diff -u -p -r1.640 cp-tree.h
--- gcc/cp/cp-tree.h 2001/09/06 08:59:38 1.640
+++ gcc/cp/cp-tree.h 2001/09/23 05:45:29
@@ -1754,10 +1754,6 @@ struct lang_decl
   /* In a FUNCTION_DECL, this is DECL_CLONED_FUNCTION.  */
   tree cloned_function;
 
-  /* In a FUNCTION_DECL, these are function data which is to be kept
-     as long as FUNCTION_DECL is kept.  */
-  tree inlined_fns;
-
   union
   {
     tree sorted_fields;
@@ -1774,10 +1770,6 @@ struct lang_decl
 
 #define DEFARG_POINTER(NODE) (DEFAULT_ARG_CHECK(NODE)->identifier.id.str)
 
-/* Non-zero if NODE is a _DECL with TREE_READONLY set.  */
-#define TREE_READONLY_DECL_P(NODE) \
-  (TREE_READONLY (NODE) && DECL_P (NODE))
-
 /* DECL_NEEDED_P holds of a declaration when we need to emit its
    definition.  This is true when the back-end tells us that
    the symbol has been referenced in the generated code.  If, however,
@@ -1884,10 +1876,6 @@ struct lang_decl
 #define DECL_CLONED_FUNCTION(NODE) \
   (DECL_LANG_SPECIFIC (NODE)->cloned_function)
 
-/* List of FUNCION_DECLs inlined into this function's body.  */
-#define DECL_INLINED_FNS(NODE) \
-  (DECL_LANG_SPECIFIC (NODE)->inlined_fns)
-
 /* Nonzero if NODE has DECL_DISCRIMINATOR and not DECL_ACCESS.  */
 #define DECL_DISCRIMINATOR_P(NODE)	\
   (TREE_CODE (NODE) == VAR_DECL		\
@@ -3258,13 +3246,6 @@ extern int flag_implicit_templates;
 
 extern int flag_weak;
 
-/* 0 if we should not perform inlining.
-   1 if we should expand functions calls inline at the tree level.  
-   2 if we should consider *all* functions to be inline 
-   candidates.  */
-
-extern int flag_inline_trees;
-
 /* Nonzero if we're done parsing and into end-of-file activities.  */
 
 extern int at_eof;
@@ -4200,18 +4181,9 @@ extern void debug_binfo				PARAMS ((tree
 extern tree build_dummy_object			PARAMS ((tree));
 extern tree maybe_dummy_object			PARAMS ((tree, tree *));
 extern int is_dummy_object			PARAMS ((tree));
-extern tree walk_tree                           PARAMS ((tree *,
-							 walk_tree_fn,
-							 void *,
-							 htab_t));
-extern tree walk_tree_without_duplicates        PARAMS ((tree *,
-							 walk_tree_fn,
-							 void *));
-extern tree copy_tree_r                         PARAMS ((tree *, int *, void *));
 extern int cp_valid_lang_attribute		PARAMS ((tree, tree, tree, tree));
 extern tree make_ptrmem_cst                     PARAMS ((tree, tree));
 extern tree cp_build_qualified_type_real        PARAMS ((tree, int, int));
-extern void remap_save_expr                     PARAMS ((tree *, splay_tree, tree, int *));
 #define cp_build_qualified_type(TYPE, QUALS) \
   cp_build_qualified_type_real ((TYPE), (QUALS), /*complain=*/1)
 extern tree build_shared_int_cst                PARAMS ((int));
Index: gcc/cp/decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.813
diff -u -p -r1.813 decl.c
--- gcc/cp/decl.c 2001/09/13 14:37:14 1.813
+++ gcc/cp/decl.c 2001/09/23 05:45:30
@@ -35,6 +35,7 @@ Boston, MA 02111-1307, USA.  */
 #include "expr.h"
 #include "flags.h"
 #include "cp-tree.h"
+#include "tree-inline.h"
 #include "decl.h"
 #include "lex.h"
 #include "output.h"
@@ -14460,7 +14461,6 @@ lang_mark_tree (t)
 	      ggc_mark_tree (ld->befriending_classes);
 	      ggc_mark_tree (ld->context);
 	      ggc_mark_tree (ld->cloned_function);
-	      ggc_mark_tree (ld->inlined_fns);
 	      if (TREE_CODE (t) == TYPE_DECL)
 		ggc_mark_tree (ld->u.sorted_fields);
 	      else if (TREE_CODE (t) == FUNCTION_DECL
Index: gcc/cp/decl2.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl2.c,v
retrieving revision 1.491
diff -u -p -r1.491 decl2.c
--- gcc/cp/decl2.c 2001/09/12 16:25:07 1.491
+++ gcc/cp/decl2.c 2001/09/23 05:45:30
@@ -378,13 +378,6 @@ int flag_weak = 1;
 
 int flag_use_cxa_atexit;
 
-/* 0 if we should not perform inlining.
-   1 if we should expand functions calls inline at the tree level.  
-   2 if we should consider *all* functions to be inline 
-   candidates.  */
-
-int flag_inline_trees = 0;
-
 /* Maximum template instantiation depth.  This limit is rather
    arbitrary, but it exists to limit the time it takes to notice
    infinite template instantiations.  */
Index: gcc/cp/optimize.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/optimize.c,v
retrieving revision 1.77
diff -u -p -r1.77 optimize.c
--- gcc/cp/optimize.c 2001/08/30 13:55:17 1.77
+++ gcc/cp/optimize.c 2001/09/23 05:45:30
@@ -33,6 +33,7 @@ Software Foundation, 59 Temple Place - S
 #include "params.h"
 #include "hashtab.h"
 #include "debug.h"
+#include "tree-inline.h"
 
 /* To Do:
 
@@ -99,7 +100,6 @@ static int inlinable_function_p PARAMS (
 static tree remap_decl PARAMS ((tree, inline_data *));
 static void remap_block PARAMS ((tree, tree, inline_data *));
 static void copy_scope_stmt PARAMS ((tree *, int *, inline_data *));
-static void optimize_inline_calls PARAMS ((tree));
 static tree calls_setjmp_r PARAMS ((tree *, int *, void *));
 static void update_cloned_parm PARAMS ((tree, tree));
 static void dump_function PARAMS ((enum tree_dump_index, tree));
@@ -121,7 +121,7 @@ remap_decl (decl, id)
 
   /* We only remap local variables in the current function.  */
   fn = VARRAY_TOP_TREE (id->fns);
-  if (!nonstatic_local_decl_p (decl) || DECL_CONTEXT (decl) != fn)
+  if (! LANG_AUTO_VAR_IN_FN_P (decl, fn))
     return NULL_TREE;
 
   /* See if we have remapped this declaration.  */
@@ -151,8 +151,8 @@ remap_decl (decl, id)
 		     copy_body_r, id, NULL);
 	}
 
-      if (!DECL_NAME (t) && TREE_TYPE (t)
-	  && ANON_AGGR_TYPE_P (TREE_TYPE ((t))))
+      if (! DECL_NAME (t) && TREE_TYPE (t)
+	  && LANG_ANON_AGGR_TYPE_P (TREE_TYPE (t)))
 	{
 	  /* For a VAR_DECL of anonymous type, we must also copy the
 	     member VAR_DECLS here and rechain the
@@ -165,7 +165,8 @@ remap_decl (decl, id)
 	    {
 	      tree member = remap_decl (TREE_VALUE (src), id);
 
-	      my_friendly_assert (!TREE_PURPOSE (src), 20010529);
+	      if (TREE_PURPOSE (src))
+		abort ();
 	      members = tree_cons (NULL, member, members);
 	    }
 	  DECL_ANON_UNION_ELEMS (t) = nreverse (members);
@@ -277,7 +278,8 @@ remap_block (scope_stmt, decls, id)
       /* Find this block in the table of remapped things.  */
       n = splay_tree_lookup (id->decl_map,
 			     (splay_tree_key) SCOPE_STMT_BLOCK (scope_stmt));
-      my_friendly_assert (n != NULL, 19991203);
+      if (! n)
+	abort ();
       SCOPE_STMT_BLOCK (scope_stmt) = (tree) n->value;
     }
 }
@@ -322,12 +324,14 @@ copy_body_r (tp, walk_subtrees, data)
   id = (inline_data *) data;
   fn = VARRAY_TOP_TREE (id->fns);
 
+#if 0
   /* 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 (! DECL_EXTERNAL (*tp) && ! TREE_STATIC (*tp))
+      abort ();
+#endif
 
   /* If this is a RETURN_STMT, change it into an EXPR_STMT and a
      GOTO_STMT with the RET_LABEL as its target.  */
@@ -359,26 +363,29 @@ copy_body_r (tp, walk_subtrees, data)
      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)
+  else if (LANG_AUTO_VAR_IN_FN_P (*tp, fn))
     {
       tree new_decl;
 
       /* Remap the declaration.  */
       new_decl = remap_decl (*tp, id);
-      my_friendly_assert (new_decl != NULL_TREE, 19991203);
+      if (! new_decl)
+	abort ();
       /* Replace this variable with the copy.  */
       STRIP_TYPE_NOPS (new_decl);
       *tp = new_decl;
     }
+#if 0
   else if (nonstatic_local_decl_p (*tp)
 	   && DECL_CONTEXT (*tp) != VARRAY_TREE (id->fns, 0))
-    my_friendly_abort (0);
+    abort ();
+#endif
   else if (TREE_CODE (*tp) == SAVE_EXPR)
     remap_save_expr (tp, id->decl_map, VARRAY_TREE (id->fns, 0),
 		     walk_subtrees);
   else if (TREE_CODE (*tp) == UNSAVE_EXPR)
     /* UNSAVE_EXPRs should not be generated until expansion time.  */
-    my_friendly_abort (19991113);
+    abort ();
   /* For a SCOPE_STMT, we must copy the associated block so that we
      can write out debugging information for the inlined variables.  */
   else if (TREE_CODE (*tp) == SCOPE_STMT && !id->in_target_cleanup_p)
@@ -398,8 +405,7 @@ copy_body_r (tp, walk_subtrees, data)
 	}
       else if (TREE_CODE (*tp) == MODIFY_EXPR
 	       && TREE_OPERAND (*tp, 0) == TREE_OPERAND (*tp, 1)
-	       && nonstatic_local_decl_p (TREE_OPERAND (*tp, 0))
-	       && DECL_CONTEXT (TREE_OPERAND (*tp, 0)) == fn)
+	       && LANG_AUTO_VAR_IN_FN_P (TREE_OPERAND (*tp, 0), fn))
 	{
 	  /* Some assignments VAR = VAR; don't generate any rtl code
 	     and thus don't count as variable modification.  Avoid
@@ -561,7 +567,7 @@ declare_return_variable (id, use_stmt)
   tree fn = VARRAY_TOP_TREE (id->fns);
   tree result = DECL_RESULT (fn);
   tree var;
-  int aggregate_return_p;
+  int need_return_decl = 1;
 
   /* We don't need to do anything for functions that don't return
      anything.  */
@@ -571,30 +577,10 @@ declare_return_variable (id, use_stmt)
       return NULL_TREE;
     }
 
-  /* Figure out whether or not FN returns an aggregate.  */
-  aggregate_return_p = IS_AGGR_TYPE (TREE_TYPE (result));
+  var = LANG_COPY_RES_DECL_FOR_INLINING (result, fn, VARRAY_TREE (id->fns, 0),
+					 id->decl_map, &need_return_decl,
+					 &id->target_exprs);
 
-  /* If FN returns an aggregate then the caller will always create the
-     temporary (using a TARGET_EXPR) and the call will be the
-     initializing expression for the TARGET_EXPR.  If we were just to
-     create a new VAR_DECL here, then the result of this function
-     would be copied (bitwise) into the variable initialized by the
-     TARGET_EXPR.  That's incorrect, so we must transform any
-     references to the RESULT into references to the target.  */
-  if (aggregate_return_p)
-    {
-      my_friendly_assert (VARRAY_ACTIVE_SIZE (id->target_exprs) != 0,
-			  20000430);
-      var = TREE_OPERAND (VARRAY_TOP_TREE (id->target_exprs), 0);
-      my_friendly_assert
-	(same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (var),
-						    TREE_TYPE (result)),
-	 20000430);
-    }
-  /* Otherwise, make an appropriate copy.  */
-  else
-    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.  */
@@ -602,29 +588,12 @@ declare_return_variable (id, use_stmt)
 		     (splay_tree_key) result,
 		     (splay_tree_value) var);
 
-  if (DECL_SAVED_FUNCTION_DATA (fn))
-    {
-      tree nrv = DECL_SAVED_FUNCTION_DATA (fn)->x_return_value;
-      if (nrv)
-	{
-	  /* We have a named return value; copy the name and source
-	     position so we can get reasonable debugging information, and
-	     register the return variable as its equivalent.  */
-	  DECL_NAME (var) = DECL_NAME (nrv);
-	  DECL_SOURCE_FILE (var) = DECL_SOURCE_FILE (nrv);
-	  DECL_SOURCE_LINE (var) = DECL_SOURCE_LINE (nrv);
-	  splay_tree_insert (id->decl_map,
-			     (splay_tree_key) nrv,
-			     (splay_tree_value) var);
-	}
-    }
-
   /* Build the USE_STMT.  */
   *use_stmt = build_stmt (EXPR_STMT, var);
 
   /* Build the declaration statement if FN does not return an
      aggregate.  */
-  if (!aggregate_return_p)
+  if (need_return_decl)
     return build_stmt (DECL_STMT, var);
   /* If FN does return an aggregate, there's no need to declare the
      return variable; we're using a variable in our caller's frame.  */
@@ -681,16 +650,9 @@ inlinable_function_p (fn, id)
       && DECL_NUM_STMTS (fn) * INSNS_PER_STMT > MAX_INLINE_INSNS / 4)
     inlinable = 0;
 
-  /* We can inline a template instantiation only if it's fully
-     instantiated.  */
-  if (inlinable
-      && DECL_TEMPLATE_INFO (fn)
-      && TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn)))
-    {
-      fn = instantiate_decl (fn, /*defer_ok=*/0);
-      inlinable = !TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn));
-    }
-
+  if (inlinable && LANG_CANNOT_INLINE_TREE_FN (&fn))
+    inlinable = 0;
+  
   /* If we don't have the function body available, we can't inline
      it.  */
   if (!DECL_SAVED_TREE (fn))
@@ -706,7 +668,7 @@ inlinable_function_p (fn, id)
 	if (VARRAY_TREE (id->fns, i) == fn)
 	  return 0;
 
-      if (inlinable && DECL_LANG_SPECIFIC (fn) && DECL_INLINED_FNS (fn))
+      if (inlinable && DECL_INLINED_FNS (fn))
 	{
 	  int j;
 	  tree inlined_fns = DECL_INLINED_FNS (fn);
@@ -808,7 +770,7 @@ expand_call_inline (tp, walk_subtrees, d
      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);
+  expr = build1 (STMT_EXPR, TREE_TYPE (TREE_TYPE (fn)), NULL_TREE);
 
   /* Local declarations will be replaced by their equivalents in this
      map.  */
@@ -832,7 +794,7 @@ expand_call_inline (tp, walk_subtrees, d
 
   /* Record the function we are about to inline if optimize_function
      has not been called on it yet and we don't have it in the list.  */
-  if (DECL_LANG_SPECIFIC (fn) && !DECL_INLINED_FNS (fn))
+  if (! DECL_INLINED_FNS (fn))
     {
       int i;
 
@@ -878,9 +840,9 @@ expand_call_inline (tp, walk_subtrees, d
   /* Close the block for the parameters.  */
   scope_stmt = build_stmt (SCOPE_STMT, DECL_INITIAL (fn));
   SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;
-  my_friendly_assert (DECL_INITIAL (fn)
-		      && TREE_CODE (DECL_INITIAL (fn)) == BLOCK,
-		      19991203);
+  if (! DECL_INITIAL (fn)
+      || TREE_CODE (DECL_INITIAL (fn)) != BLOCK)
+    abort ();
   remap_block (scope_stmt, NULL_TREE, id);
   STMT_EXPR_STMT (expr)
     = chainon (STMT_EXPR_STMT (expr), scope_stmt);
@@ -957,13 +919,12 @@ expand_calls_inline (tp, id)
 
 /* Expand calls to inline functions in the body of FN.  */
 
-static void
+void
 optimize_inline_calls (fn)
      tree fn;
 {
   inline_data id;
   tree prev_fn;
-  struct saved_scope *s;
   
   /* Clear out ID.  */
   memset (&id, 0, sizeof (id));
@@ -978,12 +939,8 @@ optimize_inline_calls (fn)
       VARRAY_PUSH_TREE (id.fns, current_function_decl);
       prev_fn = current_function_decl;
     }
-  for (s = scope_chain; s; s = s->prev)
-    if (s->function_decl && s->function_decl != prev_fn)
-      {
-	VARRAY_PUSH_TREE (id.fns, s->function_decl);
-	prev_fn = s->function_decl;
-      }
+
+  prev_fn = LANG_ADD_PENDING_FN_DECLS (&id.fns, prev_fn);
   
   /* Create the stack of TARGET_EXPRs.  */
   VARRAY_TREE_INIT (id.target_exprs, 32, "target_exprs");
@@ -1014,8 +971,6 @@ optimize_inline_calls (fn)
       DECL_INLINED_FNS (fn) = ifn;
     }
   VARRAY_FREE (id.inlined_fns);
-  
-  dump_function (TDI_inlined, fn);
 }
 
 /* Optimize the body of FN. */
@@ -1043,8 +998,12 @@ optimize_function (fn)
          optimization, (c) virtual functions are rarely inlineable,
          and (d) ASM_OUTPUT_MI_THUNK is there to DTRT anyway.  */
       && !DECL_THUNK_P (fn))
-    optimize_inline_calls (fn);
+    {
+      optimize_inline_calls (fn);
   
+      dump_function (TDI_inlined, fn);
+    }
+
   /* Undo the call to ggc_push_context above.  */
   --function_depth;
   
@@ -1106,6 +1065,38 @@ update_cloned_parm (parm, cloned_parm)
   DECL_SOURCE_LINE (cloned_parm) = DECL_SOURCE_LINE (parm);
 }
 
+/* FN is a function that has a complete body, and CLONE is a function
+   whose body is to be set to a copy of FN, mapping argument
+   declarations according to the ARG_MAP splay_tree.  */
+
+void
+clone_body (clone, fn, arg_map)
+     tree clone, fn;
+     void *arg_map;
+{
+  inline_data id;
+
+  /* Clone the body, as if we were making an inline call.  But, remap
+     the parameters in the callee to the parameters of caller.  If
+     there's an in-charge parameter, map it to an appropriate
+     constant.  */
+  memset (&id, 0, sizeof (id));
+  VARRAY_TREE_INIT (id.fns, 2, "fns");
+  VARRAY_PUSH_TREE (id.fns, clone);
+  VARRAY_PUSH_TREE (id.fns, fn);
+  id.decl_map = (splay_tree)arg_map;
+
+  /* Cloning is treated slightly differently from inlining.  Set
+     CLONING_P so that it's clear which operation we're performing.  */
+  id.cloning_p = true;
+
+  /* Actually copy the body.  */
+  TREE_CHAIN (DECL_SAVED_TREE (clone)) = copy_body (&id);
+
+  /* Clean up.  */
+  VARRAY_FREE (id.fns);
+}
+
 /* FN is a function that has a complete body.  Clone the body as
    necessary.  Returns non-zero if there's no longer any need to
    process the main body.  */
@@ -1114,7 +1105,6 @@ int
 maybe_clone_body (fn)
      tree fn;
 {
-  inline_data id;
   tree clone;
   int first = 1;
 
@@ -1135,6 +1125,7 @@ maybe_clone_body (fn)
       tree parm;
       tree clone_parm;
       int parmno;
+      splay_tree decl_map;
 
       /* Update CLONE's source position information to match FN's.  */
       DECL_SOURCE_FILE (clone) = DECL_SOURCE_FILE (fn);
@@ -1178,22 +1169,8 @@ maybe_clone_body (fn)
       push_to_top_level ();
       start_function (NULL_TREE, clone, NULL_TREE, SF_PRE_PARSED);
 
-      /* Just clone the body, as if we were making an inline call.
-	 But, remap the parameters in the callee to the parameters of
-	 caller.  If there's an in-charge parameter, map it to an
-	 appropriate constant.  */
-      memset (&id, 0, sizeof (id));
-      VARRAY_TREE_INIT (id.fns, 2, "fns");
-      VARRAY_PUSH_TREE (id.fns, clone);
-      VARRAY_PUSH_TREE (id.fns, fn);
-
-      /* Cloning is treated slightly differently from inlining.  Set
-	 CLONING_P so that its clear which operation we're performing.  */
-      id.cloning_p = true;
-
       /* Remap the parameters.  */
-      id.decl_map = splay_tree_new (splay_tree_compare_pointers,
-				    NULL, NULL);
+      decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
       for (parmno = 0,
 	     parm = DECL_ARGUMENTS (fn),
 	     clone_parm = DECL_ARGUMENTS (clone);
@@ -1206,7 +1183,7 @@ maybe_clone_body (fn)
 	    {
 	      tree in_charge;
 	      in_charge = in_charge_arg_for_name (DECL_NAME (clone));
-	      splay_tree_insert (id.decl_map,
+	      splay_tree_insert (decl_map,
 				 (splay_tree_key) parm,
 				 (splay_tree_value) in_charge);
 	    }
@@ -1219,7 +1196,7 @@ maybe_clone_body (fn)
 	      if (DECL_HAS_VTT_PARM_P (clone))
 		{
 		  DECL_ABSTRACT_ORIGIN (clone_parm) = parm;
-		  splay_tree_insert (id.decl_map,
+		  splay_tree_insert (decl_map,
 				     (splay_tree_key) parm,
 				     (splay_tree_value) clone_parm);
 		  clone_parm = TREE_CHAIN (clone_parm);
@@ -1227,7 +1204,7 @@ maybe_clone_body (fn)
 	      /* Otherwise, map the VTT parameter to `NULL'.  */
 	      else
 		{
-		  splay_tree_insert (id.decl_map,
+		  splay_tree_insert (decl_map,
 				     (splay_tree_key) parm,
 				     (splay_tree_value) null_pointer_node);
 		}
@@ -1236,23 +1213,22 @@ maybe_clone_body (fn)
 	     function.  */
 	  else
 	    {
-	      splay_tree_insert (id.decl_map,
+	      splay_tree_insert (decl_map,
 				 (splay_tree_key) parm,
 				 (splay_tree_value) clone_parm);
 	      clone_parm = TREE_CHAIN (clone_parm);
 	    }
 	}
 
-      /* Actually copy the body.  */
-      TREE_CHAIN (DECL_SAVED_TREE (clone)) = copy_body (&id);
+      /* Clone the body.  */
+      clone_body (clone, fn, decl_map);
 
       /* There are as many statements in the clone as in the
 	 original.  */
       DECL_NUM_STMTS (clone) = DECL_NUM_STMTS (fn);
 
       /* Clean up.  */
-      splay_tree_delete (id.decl_map);
-      VARRAY_FREE (id.fns);
+      splay_tree_delete (decl_map);
 
       /* Now, expand this function into RTL, if appropriate.  */
       finish_function (0);
Index: gcc/cp/semantics.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/semantics.c,v
retrieving revision 1.224
diff -u -p -r1.224 semantics.c
--- gcc/cp/semantics.c 2001/09/04 21:04:59 1.224
+++ gcc/cp/semantics.c 2001/09/23 05:45:30
@@ -28,6 +28,7 @@
 #include "system.h"
 #include "tree.h"
 #include "cp-tree.h"
+#include "tree-inline.h"
 #include "except.h"
 #include "lex.h"
 #include "toplev.h"
Index: gcc/cp/tree.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/tree.c,v
retrieving revision 1.252
diff -u -p -r1.252 tree.c
--- gcc/cp/tree.c 2001/08/27 06:48:42 1.252
+++ gcc/cp/tree.c 2001/09/23 05:45:30
@@ -31,6 +31,7 @@ Boston, MA 02111-1307, USA.  */
 #include "ggc.h"
 #include "insn-config.h"
 #include "integrate.h"
+#include "tree-inline.h"
 
 static tree bot_manip PARAMS ((tree *, int *, void *));
 static tree bot_replace PARAMS ((tree *, int *, void *));
@@ -49,7 +50,17 @@ static tree count_trees_r PARAMS ((tree 
 static tree verify_stmt_tree_r PARAMS ((tree *, int *, void *));
 static tree find_tree_r PARAMS ((tree *, int *, void *));
 extern int cp_statement_code_p PARAMS ((enum tree_code));
+static tree cp_walk_subtrees PARAMS ((tree *, int *, walk_tree_fn,
+				      void *, void *));
+static int cp_cannot_inline_tree_fn PARAMS ((tree *));
+static tree cp_add_pending_fn_decls PARAMS ((void *, tree));
+static int cp_is_overload_p PARAMS ((tree));
+static int cp_auto_var_in_fn_p PARAMS ((tree, tree));
+static tree cp_copy_res_decl_for_inlining PARAMS ((tree, tree, tree,
+						   void *, int *, void *));
 
+extern int cp_statement_code_p PARAMS ((enum tree_code));
+
 /* If REF is an lvalue, returns the kind of lvalue that REF is.
    Otherwise, returns clk_none.  If TREAT_CLASS_RVALUES_AS_LVALUES is
    non-zero, rvalues of class type are considered lvalues.  */
@@ -1150,12 +1161,13 @@ bind_template_template_parm (t, newargs)
    once.  */
 
 tree 
-walk_tree (tp, func, data, htab)
+walk_tree (tp, func, data, htab_)
      tree *tp;
      walk_tree_fn func;
      void *data;
-     htab_t htab;
+     void *htab_;
 {
+  htab_t htab = (htab_t)htab_;
   enum tree_code code;
   int walk_subtrees;
   tree result;
@@ -1200,7 +1212,8 @@ walk_tree (tp, func, data, htab)
      interesting below this point in the tree.  */
   if (!walk_subtrees)
     {
-      if (statement_code_p (code) || code == TREE_LIST || code == OVERLOAD)
+      if (statement_code_p (code) || code == TREE_LIST
+	  || LANG_TREE_CHAIN_MATTERS_P (*tp))
 	/* But we still need to check our siblings.  */
 	return walk_tree (&TREE_CHAIN (*tp), func, data, htab);
       else
@@ -1264,6 +1277,10 @@ walk_tree (tp, func, data, htab)
       return NULL_TREE;
     }
 
+  result = LANG_WALK_SUBTREES (tp, &walk_subtrees, func, data, htab);
+  if (result || ! walk_subtrees)
+    return result;
+
   /* Not one of the easy cases.  We must explicitly go through the
      children.  */
   switch (code)
@@ -1273,47 +1290,29 @@ walk_tree (tp, func, data, htab)
     case INTEGER_CST:
     case REAL_CST:
     case STRING_CST:
-    case DEFAULT_ARG:
-    case TEMPLATE_TEMPLATE_PARM:
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
-    case TEMPLATE_PARM_INDEX:
-    case TEMPLATE_TYPE_PARM:
     case REAL_TYPE:
     case COMPLEX_TYPE:
     case VECTOR_TYPE:
     case VOID_TYPE:
     case BOOLEAN_TYPE:
-    case TYPENAME_TYPE:
     case UNION_TYPE:
     case ENUMERAL_TYPE:
-    case TYPEOF_TYPE:
     case BLOCK:
+    case RECORD_TYPE:
       /* None of thse have subtrees other than those already walked
          above.  */
       break;
 
-    case PTRMEM_CST:
-      WALK_SUBTREE (TREE_TYPE (*tp));
-      break;
-
     case POINTER_TYPE:
     case REFERENCE_TYPE:
       WALK_SUBTREE (TREE_TYPE (*tp));
       break;
 
     case TREE_LIST:
-      /* A BASELINK_P's TREE_PURPOSE is a BINFO, and hence circular.  */
-      if (!BASELINK_P (*tp))
-        WALK_SUBTREE (TREE_PURPOSE (*tp));
       WALK_SUBTREE (TREE_VALUE (*tp));
       WALK_SUBTREE (TREE_CHAIN (*tp));
       break;
 
-    case OVERLOAD:
-      WALK_SUBTREE (OVL_FUNCTION (*tp));
-      WALK_SUBTREE (OVL_CHAIN (*tp));
-      break;
-
     case TREE_VEC:
       {
 	int len = TREE_VEC_LENGTH (*tp);
@@ -1361,13 +1360,8 @@ walk_tree (tp, func, data, htab)
       WALK_SUBTREE (TYPE_OFFSET_BASETYPE (*tp));
       break;
 
-    case RECORD_TYPE:
-      if (TYPE_PTRMEMFUNC_P (*tp))
-	WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
-      break;
-
     default:
-      my_friendly_abort (19990803);
+      abort ();
     }
 
   /* We didn't find what we were looking for.  */
@@ -1535,7 +1529,7 @@ copy_tree_r (tp, walk_subtrees, data)
       || TREE_CODE_CLASS (code) == 's'
       || code == TREE_LIST
       || code == TREE_VEC
-      || code == OVERLOAD)
+      || LANG_TREE_CHAIN_MATTERS_P (*tp))
     {
       /* Because the chain gets clobbered when we make a copy, we save it
 	 here.  */
@@ -1546,7 +1540,8 @@ 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
+	  || LANG_TREE_CHAIN_MATTERS_P (*tp)
 	  || statement_code_p (code))
 	TREE_CHAIN (*tp) = chain;
 
@@ -2303,12 +2298,214 @@ make_ptrmem_cst (type, member)
   return ptrmem_cst;
 }
 
+
+/* Apply FUNC to all language-specific sub-trees of TP in a pre-order
+   traversal.  Called from walk_tree().  */
+
+static tree 
+cp_walk_subtrees (tp, walk_subtrees_p, func, data, htab)
+     tree *tp;
+     int *walk_subtrees_p;
+     walk_tree_fn func;
+     void *data;
+     void *htab;
+{
+  enum tree_code code = TREE_CODE (*tp);
+  tree result;
+  
+#define WALK_SUBTREE(NODE)				\
+  do							\
+    {							\
+      result = walk_tree (&(NODE), func, data, htab);	\
+      if (result)					\
+	return result;					\
+    }							\
+  while (0)
+
+  /* Not one of the easy cases.  We must explicitly go through the
+     children.  */
+  switch (code)
+    {
+    case DEFAULT_ARG:
+    case TEMPLATE_TEMPLATE_PARM:
+    case BOUND_TEMPLATE_TEMPLATE_PARM:
+    case TEMPLATE_PARM_INDEX:
+    case TEMPLATE_TYPE_PARM:
+    case TYPENAME_TYPE:
+    case TYPEOF_TYPE:
+      /* None of thse have subtrees other than those already walked
+         above.  */
+      *walk_subtrees_p = 0;
+      break;
+
+    case PTRMEM_CST:
+      WALK_SUBTREE (TREE_TYPE (*tp));
+      *walk_subtrees_p = 0;
+      break;
+
+    case TREE_LIST:
+      /* A BASELINK_P's TREE_PURPOSE is a BINFO, and hence circular.  */
+      if (!BASELINK_P (*tp))
+        WALK_SUBTREE (TREE_PURPOSE (*tp));
+      break;
+
+    case OVERLOAD:
+      WALK_SUBTREE (OVL_FUNCTION (*tp));
+      WALK_SUBTREE (OVL_CHAIN (*tp));
+      *walk_subtrees_p = 0;
+      break;
+
+    case RECORD_TYPE:
+      if (TYPE_PTRMEMFUNC_P (*tp))
+	WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
+      break;
+
+    default:
+      break;
+    }
+
+  /* We didn't find what we were looking for.  */
+  return NULL_TREE;
+
+#undef WALK_SUBTREE
+}
+
+/* Decide whether there are language-specific reasons to not inline a
+   function as a tree.  */
+
+static int
+cp_cannot_inline_tree_fn (fnp)
+     tree *fnp;
+{
+  /* We can inline a template instantiation only if it's fully
+     instantiated.  */
+  if (DECL_TEMPLATE_INFO (*fnp)
+      && TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (*fnp)))
+    {
+      *fnp = instantiate_decl (*fnp, /*defer_ok=*/0);
+      return TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (*fnp));
+    }
+
+  return 0;
+}
+
+/* Add any pending functions other than the current function (already
+   handled by the caller), that thus cannot be inlined, to FNS_P, then
+   return the latest function added to the array, PREV_FN.  */
+
+static tree
+cp_add_pending_fn_decls (fns_p, prev_fn)
+     void *fns_p;
+     tree prev_fn;
+{
+  varray_type *fnsp = (varray_type *)fns_p;
+  struct saved_scope *s;
+
+  for (s = scope_chain; s; s = s->prev)
+    if (s->function_decl && s->function_decl != prev_fn)
+      {
+	VARRAY_PUSH_TREE (*fnsp, s->function_decl);
+	prev_fn = s->function_decl;
+      }
+
+  return prev_fn;
+}
+
+/* Determine whether a tree node is an OVERLOAD node.  Used to decide
+   whether to copy a node or to preserve its chain when inlining a
+   function.  */
+
+static int
+cp_is_overload_p (t)
+     tree t;
+{
+  return TREE_CODE (t) == OVERLOAD;
+}
+
+/* Determine whether VAR is a declaration of an automatic variable in
+   function FN.  */
+
+static int
+cp_auto_var_in_fn_p (var, fn)
+     tree var, fn;
+{
+  return (DECL_P (var) && DECL_CONTEXT (var) == fn
+	  && nonstatic_local_decl_p (var));
+}
+
+/* Tell whether a declaration is needed for the RESULT of a function
+   FN being inlined into CALLER or if the top node of target_exprs is
+   to be used.  */
+
+static tree
+cp_copy_res_decl_for_inlining (result, fn, caller, decl_map_,
+			       need_decl, target_exprs)
+     tree result, fn, caller;
+     void *decl_map_;
+     int *need_decl;
+     void *target_exprs;
+{
+  splay_tree decl_map = (splay_tree)decl_map_;
+  varray_type *texps = (varray_type *)target_exprs;
+  tree var;
+  int aggregate_return_p;
+
+  /* Figure out whether or not FN returns an aggregate.  */
+  aggregate_return_p = IS_AGGR_TYPE (TREE_TYPE (result));
+  *need_decl = ! aggregate_return_p;
+
+  /* If FN returns an aggregate then the caller will always create the
+     temporary (using a TARGET_EXPR) and the call will be the
+     initializing expression for the TARGET_EXPR.  If we were just to
+     create a new VAR_DECL here, then the result of this function
+     would be copied (bitwise) into the variable initialized by the
+     TARGET_EXPR.  That's incorrect, so we must transform any
+     references to the RESULT into references to the target.  */
+  if (aggregate_return_p)
+    {
+      if (VARRAY_ACTIVE_SIZE (*texps) == 0)
+	abort ();
+      var = TREE_OPERAND (VARRAY_TOP_TREE (*texps), 0);
+      if (! same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (var),
+						       TREE_TYPE (result)))
+	abort ();
+    }
+  /* Otherwise, make an appropriate copy.  */
+  else
+    var = copy_decl_for_inlining (result, fn, caller);
+
+  if (DECL_SAVED_FUNCTION_DATA (fn))
+    {
+      tree nrv = DECL_SAVED_FUNCTION_DATA (fn)->x_return_value;
+      if (nrv)
+	{
+	  /* We have a named return value; copy the name and source
+	     position so we can get reasonable debugging information, and
+	     register the return variable as its equivalent.  */
+	  DECL_NAME (var) = DECL_NAME (nrv);
+	  DECL_SOURCE_FILE (var) = DECL_SOURCE_FILE (nrv);
+	  DECL_SOURCE_LINE (var) = DECL_SOURCE_LINE (nrv);
+	  splay_tree_insert (decl_map,
+			     (splay_tree_key) nrv,
+			     (splay_tree_value) var);
+	}
+    }
+
+  return var;
+}
+
 /* Initialize tree.c.  */
 
 void
 init_tree ()
 {
   make_lang_type_fn = cp_make_lang_type;
+  lang_walk_subtrees = cp_walk_subtrees;
+  lang_cannot_inline_tree_fn = cp_cannot_inline_tree_fn;
+  lang_add_pending_fn_decls = cp_add_pending_fn_decls;
+  lang_tree_chain_matters_p = cp_is_overload_p;
+  lang_auto_var_in_fn_p = cp_auto_var_in_fn_p;
+  lang_copy_res_decl_for_inlining = cp_copy_res_decl_for_inlining;
   lang_unsave = cp_unsave;
   lang_statement_code_p = cp_statement_code_p;
   lang_set_decl_assembler_name = mangle_decl;
@@ -2324,12 +2521,13 @@ init_tree ()
    ST.  FN is the function into which the copy will be placed.  */
 
 void
-remap_save_expr (tp, st, fn, walk_subtrees)
+remap_save_expr (tp, st_, fn, walk_subtrees)
      tree *tp;
-     splay_tree st;
+     void *st_;
      tree fn;
      int *walk_subtrees;
 {
+  splay_tree st = (splay_tree) st_;
   splay_tree_node n;
 
   /* See if we already encountered this SAVE_EXPR.  */


(*) except for the fact that function-as-trees is only defined in
c-common, so they would only be available to C-like front-ends until
someone takes over the task of moving language-independent, which I'm
passing on for now.

-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                  aoliva@{cygnus.com, redhat.com}
CS PhD student at IC-Unicamp        oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist    *Please* write to mailing lists, not to me

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]