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]

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


On Sep 23, 2001, Alexandre Oliva <aoliva@redhat.com> wrote:

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

The plan remains, with patches 2 and 3 to follow this one in a matter
of seconds, but I decided to put in a bit of addition stuff into patch
#1 (LANG_DISREGARD_INLINE_LIMITS) and name the hooks and hook types
more uniformly.

Tested on athlon-pc-linux-gnu, by itself and along with patches 2 and
3.  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.c: 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/pt.o, 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.
	* pt.c, 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.738
diff -u -p -r1.738 Makefile.in
--- gcc/Makefile.in 2001/09/22 13:59:01 1.738
+++ gcc/Makefile.in 2001/09/24 19:49:39
@@ -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
 
 # A file used by all variants of C and some other languages.
 
@@ -1349,6 +1349,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.255
diff -u -p -r1.255 c-common.c
--- gcc/c-common.c 2001/09/22 15:13:42 1.255
+++ gcc/c-common.c 2001/09/24 19:49:41
@@ -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"
@@ -3312,7 +3313,6 @@ void
 c_mark_lang_decl (c)
      struct c_lang_decl *c;
 {
-  ggc_mark_tree (c->saved_tree);
 }
 
 /* Mark F for GC.  */
@@ -3793,6 +3793,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.85
diff -u -p -r1.85 c-common.h
--- gcc/c-common.h 2001/09/22 13:14:34 1.85
+++ gcc/c-common.h 2001/09/24 19:49:42
@@ -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.43
diff -u -p -r1.43 ggc-common.c
--- gcc/ggc-common.c 2001/09/21 01:26:52 1.43
+++ gcc/ggc-common.c 2001/09/24 19:49:47
@@ -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 Mon Sep 24 12:49:47 2001
@@ -0,0 +1,43 @@
+/* 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"
+
+/* Definitions of language hooks.  */
+
+treeopt_walk_subtrees_type *lang_walk_subtrees;
+treeopt_cannot_inline_tree_fn_type *lang_cannot_inline_tree_fn;
+treeopt_disregard_inline_limits_type *lang_disregard_inline_limits;
+treeopt_add_pending_fn_decls_type *lang_add_pending_fn_decls;
+treeopt_tree_chain_matters_p_type *lang_tree_chain_matters_p;
+treeopt_auto_var_in_fn_p_type *lang_auto_var_in_fn_p;
+treeopt_copy_res_decl_for_inlining_type *lang_copy_res_decl_for_inlining;
+treeopt_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 Mon Sep 24 12:49:48 2001
@@ -0,0 +1,140 @@
+/* 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_subtrees_type PARAMS ((tree*, int*, walk_tree_fn,
+						 void*, void*));
+extern treeopt_walk_subtrees_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_DISREGARD_INLINE_LIMITS is called to determine whether a
+   function should be inlined even if it would exceed inlining limits.  */
+
+#define LANG_DISREGARD_INLINE_LIMITS(FN) \
+  (lang_disregard_inline_limits ? (*lang_disregard_inline_limits)(FN) : 0)
+typedef int treeopt_disregard_inline_limits_type PARAMS ((tree));
+extern treeopt_disregard_inline_limits_type *lang_disregard_inline_limits;
+
+/* 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_auto_var_in_fn_p_type PARAMS ((tree,tree));
+extern treeopt_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_copy_res_decl_for_inlining_type PARAMS ((tree, tree,
+							      tree, void*,
+							      int*, void*));
+extern treeopt_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_anon_aggr_type_p PARAMS ((tree));
+extern treeopt_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.  */
+
+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.268
diff -u -p -r1.268 tree.h
--- gcc/tree.h 2001/09/22 15:13:42 1.268
+++ gcc/tree.h 2001/09/24 19:49:49
@@ -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
@@ -1547,6 +1551,14 @@ struct tree_type
 /* In a FUNCTION_DECL, nonzero if the function cannot be inlined.  */
 #define DECL_UNINLINABLE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.uninlinable)
 
+/* 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)
+
 /* Nonzero in a FUNCTION_DECL means this is a built-in function
    that is not specified by ansi C and that users are supposed to be allowed
    to redefine for any purpose whatever.  */
@@ -1769,6 +1781,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.  */
@@ -3036,6 +3055,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.92
diff -u -p -r1.92 Make-lang.in
--- gcc/cp/Make-lang.in 2001/09/24 00:27:33 1.92
+++ gcc/cp/Make-lang.in 2001/09/24 19:50:00
@@ -243,7 +243,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) \
@@ -261,7 +261,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 \
@@ -270,14 +270,15 @@ cp/expr.o: cp/expr.c $(CXX_TREE_H) $(RTL
   except.h $(TM_P_H)
 cp/xref.o: cp/xref.c $(CXX_TREE_H) input.h toplev.h
 cp/pt.o: cp/pt.c $(CXX_TREE_H) cp/decl.h cp/parse.h cp/lex.h toplev.h \
-  $(GGC_H) $(RTL_H) except.h
+  $(GGC_H) $(RTL_H) except.h tree-inline.h
 cp/error.o: cp/error.c $(CXX_TREE_H) toplev.h diagnostic.h flags.h real.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.643
diff -u -p -r1.643 cp-tree.h
--- gcc/cp/cp-tree.h 2001/09/24 00:27:33 1.643
+++ gcc/cp/cp-tree.h 2001/09/24 19:50:05
@@ -1758,10 +1758,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;
@@ -1778,10 +1774,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,
@@ -1888,10 +1880,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		\
@@ -3262,13 +3250,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;
@@ -4196,18 +4177,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 const struct attribute_spec cp_attribute_table[];
 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.815
diff -u -p -r1.815 decl.c
--- gcc/cp/decl.c 2001/09/21 07:17:49 1.815
+++ gcc/cp/decl.c 2001/09/24 19:50:24
@@ -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"
@@ -14452,7 +14453,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.493
diff -u -p -r1.493 decl2.c
--- gcc/cp/decl2.c 2001/09/21 16:58:20 1.493
+++ gcc/cp/decl2.c 2001/09/24 19:50:29
@@ -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/24 19:50: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.  */
@@ -659,8 +628,8 @@ inlinable_function_p (fn, id)
   /* We can't inline varargs functions.  */
   else if (varargs_function_p (fn))
     ;
-  /* We can't inline functions that are too big.
-   * Only allow a single function to eat up half of our budget. */
+  /* We can't inline functions that are too big.  Only allow a single
+     function to eat up half of our budget.  */
   else if (DECL_NUM_STMTS (fn) * INSNS_PER_STMT > MAX_INLINE_INSNS / 2)
     ;
   /* All is well.  We can inline this function.  Traditionally, GCC
@@ -675,22 +644,16 @@ inlinable_function_p (fn, id)
 
   /* Even if this function is not itself too big to inline, it might
      be that we've done so much inlining already that we don't want to
-     risk too much inlining any more and thus halve the acceptable size. */
+     risk too much inlining any more and thus halve the acceptable
+     size.  */
   if ((DECL_NUM_STMTS (fn) + id->inlined_stmts) * INSNS_PER_STMT
       > MAX_INLINE_INSNS
       && 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 +669,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 +771,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 +795,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 +841,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 +920,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 +940,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 +972,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,7 +999,11 @@ 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 +1066,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 +1106,6 @@ int
 maybe_clone_body (fn)
      tree fn;
 {
-  inline_data id;
   tree clone;
   int first = 1;
 
@@ -1135,6 +1126,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 +1170,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 +1184,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 +1197,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 +1205,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 +1214,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/pt.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/pt.c,v
retrieving revision 1.549
diff -u -p -r1.549 pt.c
--- gcc/cp/pt.c 2001/09/21 01:26:55 1.549
+++ gcc/cp/pt.c 2001/09/24 19:50:36
@@ -29,10 +29,10 @@ Boston, MA 02111-1307, USA.  */
 #include "config.h"
 #include "system.h"
 #include "obstack.h"
-
 #include "tree.h"
 #include "flags.h"
 #include "cp-tree.h"
+#include "tree-inline.h"
 #include "decl.h"
 #include "parse.h"
 #include "lex.h"
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/24 19:50:37
@@ -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.253
diff -u -p -r1.253 tree.c
--- gcc/cp/tree.c 2001/09/21 01:27:00 1.253
+++ gcc/cp/tree.c 2001/09/24 19:50:39
@@ -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,6 +50,12 @@ 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 treeopt_walk_subtrees_type cp_walk_subtrees;
+static treeopt_cannot_inline_tree_fn_type cp_cannot_inline_tree_fn;
+static treeopt_add_pending_fn_decls_type cp_add_pending_fn_decls;
+static treeopt_tree_chain_matters_p_type cp_is_overload_p;
+static treeopt_auto_var_in_fn_p_type cp_auto_var_in_fn_p;
+static treeopt_copy_res_decl_for_inlining_type cp_copy_res_decl_for_inlining;
 
 static tree handle_java_interface_attribute PARAMS ((tree *, tree, tree, int, bool *));
 static tree handle_com_interface_attribute PARAMS ((tree *, tree, tree, int, bool *));
@@ -1154,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;
@@ -1204,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
@@ -1268,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)
@@ -1277,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);
@@ -1365,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.  */
@@ -1539,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.  */
@@ -1550,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;
 
@@ -2344,12 +2335,213 @@ 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;
@@ -2365,12 +2557,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.  */

-- 
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]