summaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>2001-03-27 02:17:48 +0000
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>2001-03-27 02:17:48 +0000
commit1f1fa73c1ad0871e076e13f914a555fb91d09f19 (patch)
tree948316451d83b15b776dfaed5ddc3be0ef0528cf /gcc/cp
parent95ed21b8d3c6ada80e21893c08f8713621c589c3 (diff)
downloadgcc-1f1fa73c1ad0871e076e13f914a555fb91d09f19.tar.gz
* c-common.h (DECL_NUM_STMTS): New macro.
* c-decl.c (duplicate_decls): Copy DECL_NUM_STMTS, not DECL_FRAME_SIZE. (pushdecl): Likewise. * c-semantics.c (add_stmt): Update DECL_NUM_STMTS. * integrate.c (expand_inline_function): Don't check DECL_FRAME_SIZE. * print-tree.c (print_node): Don't print it. * toplev.c (rest_of_compilation): Don't try to inline when flag_no_inline is on. * tree.h (DECL_FRAME_SIZE): Remove. (tree_decl): Adjust accordingly. * Makefile.in (optimize.o): Depend on params.h. (duplicate_decls): Copy DECL_NUM_STMTS, not DECL_FRAME_SIZE. (init_decl_processing): Set flag_no_inline when doing inlining-on-trees. * optimize.c: Include params.h. (struct inline_data): Improve documentation of FNS. Add FIRST_INLINED_FN, INLINED_STMTS, and CLONING_P. (INSNS_PER_STMT): New macro. (remap_block): Use CLONING_P. (inlinable_function_p): Don't inline big functions. (expand_call_inline): Keep track of how much inlining we've done. (optimize_function): Set FIRST_INLINED_FN. (maybe_clone_body): Set CLONING_P. * semantics.c (simplify_aggr_init_exprs_r): Fix typing problems in tree nodes. (genrtl_finish_function): Clear DECL_DEFER_OUTPUT before calling rest_of_compilation. Clear DECL_RTL for local variables afterwards. (clear_decl_rtl): New function. * com.c (duplicate_decls): Don't copy DECL_FRAME_SIZE. * parse.h (DECL_END_SOURCE_LINE): Don't rely on DECL_FRAME_SIZE. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@40859 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog22
-rw-r--r--gcc/cp/Make-lang.in2
-rw-r--r--gcc/cp/decl.c7
-rw-r--r--gcc/cp/optimize.c55
-rw-r--r--gcc/cp/semantics.c57
5 files changed, 124 insertions, 19 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 3b89a973e06..cdf1637c61d 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,25 @@
+2001-03-26 Mark Mitchell <mark@codesourcery.com>
+
+ * Makefile.in (optimize.o): Depend on params.h.
+ (duplicate_decls): Copy DECL_NUM_STMTS, not DECL_FRAME_SIZE.
+ (init_decl_processing): Set flag_no_inline when doing
+ inlining-on-trees.
+ * optimize.c: Include params.h.
+ (struct inline_data): Improve documentation of FNS. Add
+ FIRST_INLINED_FN, INLINED_STMTS, and CLONING_P.
+ (INSNS_PER_STMT): New macro.
+ (remap_block): Use CLONING_P.
+ (inlinable_function_p): Don't inline big functions.
+ (expand_call_inline): Keep track of how much inlining we've done.
+ (optimize_function): Set FIRST_INLINED_FN.
+ (maybe_clone_body): Set CLONING_P.
+ * semantics.c (simplify_aggr_init_exprs_r): Fix typing problems in
+ tree nodes.
+ (genrtl_finish_function): Clear DECL_DEFER_OUTPUT before calling
+ rest_of_compilation. Clear DECL_RTL for local variables
+ afterwards.
+ (clear_decl_rtl): New function.
+
2001-03-26 Nathan Sidwell <nathan@codesourcery.com>
Implement DR 209
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 67789446278..d9685335688 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -297,7 +297,7 @@ cp/semantics.o: cp/semantics.c $(CXX_TREE_H) cp/lex.h except.h toplev.h \
flags.h $(GGC_H) output.h $(RTL_H) $(TIMEVAR_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
+ input.h params.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 \
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 03f94a35fa1..92ee8edb7ac 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -3692,7 +3692,7 @@ duplicate_decls (newdecl, olddecl)
SET_DECL_RTL (newdecl, DECL_RTL (olddecl));
}
else
- DECL_FRAME_SIZE (newdecl) = DECL_FRAME_SIZE (olddecl);
+ DECL_NUM_STMTS (newdecl) = DECL_NUM_STMTS (olddecl);
DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
if ((DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl)))
@@ -6346,7 +6346,10 @@ init_decl_processing ()
if (! flag_permissive && ! pedantic)
flag_pedantic_errors = 1;
if (!flag_no_inline)
- flag_inline_trees = 1;
+ {
+ flag_inline_trees = 1;
+ flag_no_inline = 1;
+ }
/* Initially, C. */
current_lang_name = lang_name_c;
diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c
index d350fdaaeed..f7f957509c2 100644
--- a/gcc/cp/optimize.c
+++ b/gcc/cp/optimize.c
@@ -30,6 +30,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "toplev.h"
#include "varray.h"
#include "ggc.h"
+#include "params.h"
/* To Do:
@@ -50,8 +51,13 @@ typedef struct inline_data
/* A stack of the functions we are inlining. For example, if we are
compiling `f', which calls `g', which calls `h', and we are
inlining the body of `h', the stack will contain, `h', followed
- by `g', followed by `f'. */
+ by `g', followed by `f'. The first few elements of the stack may
+ contain other functions that we know we should not recurse into,
+ even though they are not directly being inlined. */
varray_type fns;
+ /* The index of the first element of FNS that really represents an
+ inlined function. */
+ unsigned first_inlined_fn;
/* The label to jump to when a return statement is encountered. If
this value is NULL, then return statements will simply be
remapped as return statements, rather than as jumps. */
@@ -66,6 +72,14 @@ typedef struct inline_data
varray_type target_exprs;
/* A list of the functions current function has inlined. */
varray_type inlined_fns;
+ /* The approximate number of statements we have inlined in the
+ current call stack. */
+ int inlined_stmts;
+ /* We use the same mechanism to build clones that we do to perform
+ inlining. However, there are a few places where we need to
+ distinguish between those two situations. This flag is true nif
+ we are cloning, rather than inlining. */
+ bool cloning_p;
} inline_data;
/* Prototypes. */
@@ -82,6 +96,11 @@ static void remap_block PARAMS ((tree, tree, inline_data *));
static void copy_scope_stmt PARAMS ((tree *, int *, inline_data *));
static tree calls_setjmp_r PARAMS ((tree *, int *, void *));
+/* The approximate number of instructions per statement. This number
+ need not be particularly accurate; it is used only to make
+ decisions about when a function is too big to inline. */
+#define INSNS_PER_STMT (10)
+
/* Remap DECL during the copying of the BLOCK tree for the function.
DATA is really an `inline_data *'. */
@@ -199,9 +218,10 @@ remap_block (scope_stmt, decls, id)
/* We put the BLOCK_VARS in reverse order; fix that now. */
BLOCK_VARS (new_block) = nreverse (BLOCK_VARS (new_block));
fn = VARRAY_TREE (id->fns, 0);
- if (fn == current_function_decl)
- /* We're building a clone; DECL_INITIAL is still error_mark_node, and
- current_binding_level is the parm binding level. */
+ if (id->cloning_p)
+ /* We're building a clone; DECL_INITIAL is still
+ error_mark_node, and current_binding_level is the parm
+ binding level. */
insert_block (new_block);
else
{
@@ -583,6 +603,9 @@ 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. */
+ else if (DECL_NUM_STMTS (fn) * INSNS_PER_STMT > MAX_INLINE_INSNS)
+ ;
/* All is well. We can inline this function. Traditionally, GCC
has refused to inline functions using alloca, or functions whose
values are returned in a PARALLEL, and a few other such obscure
@@ -593,6 +616,13 @@ inlinable_function_p (fn, id)
/* Squirrel away the result so that we don't have to check again. */
DECL_UNINLINABLE (fn) = !inlinable;
+ /* 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 inlining any more. */
+ if ((DECL_NUM_STMTS (fn) + id->inlined_stmts) * INSNS_PER_STMT
+ > MAX_INLINE_INSNS)
+ inlinable = 0;
+
/* We can inline a template instantiation only if it's fully
instantiated. */
if (inlinable
@@ -830,10 +860,19 @@ expand_call_inline (tp, walk_subtrees, data)
the equivalent inlined version either. */
TREE_USED (*tp) = 1;
+ /* Our function now has more statements than it did before. */
+ DECL_NUM_STMTS (VARRAY_TREE (id->fns, 0)) += DECL_NUM_STMTS (fn);
+ id->inlined_stmts += DECL_NUM_STMTS (VARRAY_TREE (id->fns, 0));
+
/* Recurse into the body of the just inlined function. */
expand_calls_inline (inlined_body, id);
VARRAY_POP (id->fns);
+ /* If we've returned to the top level, clear out the record of how
+ much inlining has been done. */
+ if (VARRAY_ACTIVE_SIZE (id->fns) == id->first_inlined_fn)
+ id->inlined_stmts = 0;
+
/* Don't walk into subtrees. We've already handled them above. */
*walk_subtrees = 0;
@@ -904,6 +943,10 @@ optimize_function (fn)
/* Create the list of functions this call will inline. */
VARRAY_TREE_INIT (id.inlined_fns, 32, "inlined_fns");
+ /* Keep track of the low-water mark, i.e., the point where
+ the first real inlining is represented in ID.FNS. */
+ id.first_inlined_fn = VARRAY_ACTIVE_SIZE (id.fns);
+
/* Replace all calls to inline functions with the bodies of those
functions. */
expand_calls_inline (&DECL_SAVED_TREE (fn), &id);
@@ -1011,6 +1054,10 @@ maybe_clone_body (fn)
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);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index c99a0db4e70..5406b3e3bd0 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -59,6 +59,7 @@ static void genrtl_named_return_value PARAMS ((void));
static void cp_expand_stmt PARAMS ((tree));
static void genrtl_start_function PARAMS ((tree));
static void genrtl_finish_function PARAMS ((tree));
+static tree clear_decl_rtl PARAMS ((tree *, int *, void *));
/* Finish processing the COND, the SUBSTMT condition for STMT. */
@@ -2241,7 +2242,6 @@ simplify_aggr_init_exprs_r (tp, walk_subtrees, data)
tree args;
tree slot;
tree type;
- tree call_type;
int copy_from_buffer_p;
aggr_init_expr = *tp;
@@ -2264,17 +2264,20 @@ simplify_aggr_init_exprs_r (tp, walk_subtrees, data)
args = TREE_OPERAND (aggr_init_expr, 1);
slot = TREE_OPERAND (aggr_init_expr, 2);
type = TREE_TYPE (aggr_init_expr);
- call_type = type;
if (AGGR_INIT_VIA_CTOR_P (aggr_init_expr))
{
/* Replace the first argument with the address of the third
argument to the AGGR_INIT_EXPR. */
- call_type = build_pointer_type (type);
mark_addressable (slot);
- args = tree_cons (NULL_TREE, build1 (ADDR_EXPR, call_type, slot),
+ args = tree_cons (NULL_TREE,
+ build1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (slot)),
+ slot),
TREE_CHAIN (args));
}
- call_expr = build (CALL_EXPR, call_type, fn, args, NULL_TREE);
+ call_expr = build (CALL_EXPR,
+ TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
+ fn, args, NULL_TREE);
TREE_SIDE_EFFECTS (call_expr) = 1;
/* If we're using the non-reentrant PCC calling convention, then we
@@ -2681,6 +2684,10 @@ genrtl_finish_function (fn)
if (function_depth > 1)
ggc_push_context ();
+ /* There's no need to defer outputting this function any more; we
+ know we want to output it. */
+ DECL_DEFER_OUTPUT (fn) = 0;
+
/* Run the optimizers and output the assembler code for this
function. */
rest_of_compilation (fn);
@@ -2721,28 +2728,54 @@ genrtl_finish_function (fn)
--function_depth;
- if (!DECL_SAVED_INSNS (fn)
- && !(flag_inline_trees && DECL_INLINE (fn)))
+ /* If we don't need the RTL for this function anymore, stop pointing
+ to it. That's especially important for LABEL_DECLs, since you
+ can reach all the instructions in the function from the
+ CODE_LABEL stored in the DECL_RTL for the LABEL_DECL. */
+ if (!DECL_SAVED_INSNS (fn))
{
tree t;
- /* Stop pointing to the local nodes about to be freed. */
- /* But DECL_INITIAL must remain nonzero so we know this
- was an actual function definition. */
- DECL_INITIAL (fn) = error_mark_node;
+ /* Walk the BLOCK-tree, clearing DECL_RTL for LABEL_DECLs and
+ non-static local variables. */
+ walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
+ clear_decl_rtl,
+ NULL);
+
+ /* Clear out the RTL for the arguments. */
for (t = DECL_ARGUMENTS (fn); t; t = TREE_CHAIN (t))
{
SET_DECL_RTL (t, NULL_RTX);
DECL_INCOMING_RTL (t) = NULL_RTX;
}
- }
+ if (!(flag_inline_trees && DECL_INLINE (fn)))
+ /* DECL_INITIAL must remain nonzero so we know this was an
+ actual function definition. */
+ DECL_INITIAL (fn) = error_mark_node;
+ }
+
/* Let the error reporting routines know that we're outside a
function. For a nested function, this value is used in
pop_cp_function_context and then reset via pop_function_context. */
current_function_decl = NULL_TREE;
}
+/* Clear out the DECL_RTL for the non-static variables in BLOCK and
+ its sub-blocks. */
+
+static tree
+clear_decl_rtl (tp, walk_subtrees, data)
+ tree *tp;
+ int *walk_subtrees ATTRIBUTE_UNUSED;
+ void *data ATTRIBUTE_UNUSED;
+{
+ if (nonstatic_local_decl_p (*tp))
+ SET_DECL_RTL (*tp, NULL_RTX);
+
+ return NULL_TREE;
+}
+
/* Perform initialization related to this module. */
void