This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Tree inlining for the C front end (part 1 of 3)
- To: gcc-patches at gcc dot gnu dot org
- Subject: Re: Tree inlining for the C front end (part 1 of 3)
- From: Alexandre Oliva <aoliva at redhat dot com>
- Date: 24 Sep 2001 17:33:52 -0300
- Organization: GCC Team, Red Hat
- References: <oriteacut1.fsf@localhost.localdomain>
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