[C++ patch]: reorganize tree inlining
Nathan Sidwell
nathan@codesourcery.com
Sun Jul 1 13:02:00 GMT 2001
Hi,
this patch reorganizes the tree based inlining by breaking out the
inliner into a separate function (inline_into_function), and leaving
optimize_function to call the different tree optimizer functions
(of which there is only one at the moment).
It also adds a new ast dump, just after inlining.
This is in preparation to attacking the inliner heuristics.
booted & tested on i686-pc-linux-gnu, ok?
nathan
--
Dr Nathan Sidwell :: http://www.codesourcery.com :: CodeSourcery LLC
'But that's a lie.' - 'Yes it is. What's your point?'
nathan@codesourcery.com : http://www.cs.bris.ac.uk/~nathan/ : nathan@acm.org
optimize1.patch
-------------- next part --------------
2001-07-01 Nathan Sidwell <nathan@codesourcery.com>
* optimize.c (inline_into_function): New function, broken out
of ...
(optimize_function): ... here. Call it. Don't inline if it is
a thunk.
(dump_function): Print name of dump flag causing this dump.
* semantics.c (expand_body): Move thunk inline check to
optimize_function.
2001-07-01 Nathan Sidwell <nathan@codesourcery.com>
* c-common.h (TDI_inlined): New ast dump phase.
(dump_flag_name): New function.
* c-dump.c (dump_files): Add inlined phase.
(dump_flag_name): Define.
* doc/invoke.texi (-fdump-ast-inlined): Document.
Index: cp/optimize.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/optimize.c,v
retrieving revision 1.73
diff -c -3 -p -r1.73 optimize.c
*** optimize.c 2001/06/05 08:03:45 1.73
--- optimize.c 2001/06/29 14:58:17
*************** typedef struct inline_data
*** 78,84 ****
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;
/* Hash table used to prevent walk_tree from visiting the same node
--- 78,84 ----
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 if
we are cloning, rather than inlining. */
bool cloning_p;
/* Hash table used to prevent walk_tree from visiting the same node
*************** static int inlinable_function_p PARAMS (
*** 98,103 ****
--- 98,104 ----
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 inline_into_function 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));
*************** expand_calls_inline (tp, id)
*** 934,939 ****
--- 935,1003 ----
walk_tree (tp, expand_call_inline, id, id->tree_pruner);
}
+ /* Expand calls to inline functions. */
+
+ static void
+ inline_into_function (fn)
+ tree fn;
+ {
+ inline_data id;
+ tree prev_fn;
+ struct saved_scope *s;
+
+ /* Clear out ID. */
+ memset (&id, 0, sizeof (id));
+
+ /* Don't allow recursion into FN. */
+ VARRAY_TREE_INIT (id.fns, 32, "fns");
+ VARRAY_PUSH_TREE (id.fns, fn);
+ /* Or any functions that aren't finished yet. */
+ prev_fn = NULL_TREE;
+ if (current_function_decl)
+ {
+ 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;
+ }
+
+ /* Create the stack of TARGET_EXPRs. */
+ VARRAY_TREE_INIT (id.target_exprs, 32, "target_exprs");
+
+ /* 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. */
+ id.tree_pruner = htab_create (37, htab_hash_pointer,
+ htab_eq_pointer, NULL);
+ expand_calls_inline (&DECL_SAVED_TREE (fn), &id);
+
+ /* Clean up. */
+ htab_delete (id.tree_pruner);
+ VARRAY_FREE (id.fns);
+ VARRAY_FREE (id.target_exprs);
+ if (DECL_LANG_SPECIFIC (fn))
+ {
+ tree ifn = make_tree_vec (VARRAY_ACTIVE_SIZE (id.inlined_fns));
+
+ memcpy (&TREE_VEC_ELT (ifn, 0), &VARRAY_TREE (id.inlined_fns, 0),
+ VARRAY_ACTIVE_SIZE (id.inlined_fns) * sizeof (tree));
+ DECL_INLINED_FNS (fn) = ifn;
+ }
+ VARRAY_FREE (id.inlined_fns);
+
+ dump_function (TDI_inlined, fn);
+ }
+
/* Optimize the body of FN. */
void
*************** optimize_function (fn)
*** 952,1016 ****
must protect ourselves, just as we do while building up the body
of the function. */
++function_depth;
-
- /* Expand calls to inline functions. */
- if (flag_inline_trees)
- {
- inline_data id;
- tree prev_fn;
- struct saved_scope *s;
-
- /* Clear out ID. */
- memset (&id, 0, sizeof (id));
-
- /* Don't allow recursion into FN. */
- VARRAY_TREE_INIT (id.fns, 32, "fns");
- VARRAY_PUSH_TREE (id.fns, fn);
- /* Or any functions that aren't finished yet. */
- prev_fn = NULL_TREE;
- if (current_function_decl)
- {
- 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;
- }
-
- /* Create the stack of TARGET_EXPRs. */
- VARRAY_TREE_INIT (id.target_exprs, 32, "target_exprs");
-
- /* 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. */
- id.tree_pruner = htab_create (37, htab_hash_pointer,
- htab_eq_pointer, NULL);
- expand_calls_inline (&DECL_SAVED_TREE (fn), &id);
-
- /* Clean up. */
- htab_delete (id.tree_pruner);
- VARRAY_FREE (id.fns);
- VARRAY_FREE (id.target_exprs);
- if (DECL_LANG_SPECIFIC (fn))
- {
- tree ifn = make_tree_vec (VARRAY_ACTIVE_SIZE (id.inlined_fns));
! memcpy (&TREE_VEC_ELT (ifn, 0), &VARRAY_TREE (id.inlined_fns, 0),
! VARRAY_ACTIVE_SIZE (id.inlined_fns) * sizeof (tree));
! DECL_INLINED_FNS (fn) = ifn;
! }
! VARRAY_FREE (id.inlined_fns);
! }
!
/* Undo the call to ggc_push_context above. */
--function_depth;
--- 1016,1030 ----
must protect ourselves, just as we do while building up the body
of the function. */
++function_depth;
! if (flag_inline_trees
! /* We do not inline thunks, as (a) the backend tries to optimize
! the call to the thunkee, (b) tree based inlining breaks that
! optimization, (c) virtual functions are rarely inlineable,
! and (d) ASM_OUTPUT_MI_THUNK is there to DTRT anyway. */
! && !DECL_THUNK_P (fn))
! inline_into_function (fn);
!
/* Undo the call to ggc_push_context above. */
--function_depth;
*************** dump_function (phase, fn)
*** 1246,1252 ****
{
fprintf (stream, "\n;; Function %s",
decl_as_string (fn, TFF_DECL_SPECIFIERS));
! fprintf (stream, " (%s)", decl_as_string (DECL_ASSEMBLER_NAME (fn), 0));
fprintf (stream, "\n\n");
dump_node (fn, TDF_SLIM | flags, stream);
--- 1260,1268 ----
{
fprintf (stream, "\n;; Function %s",
decl_as_string (fn, TFF_DECL_SPECIFIERS));
! fprintf (stream, " (%s)\n",
! decl_as_string (DECL_ASSEMBLER_NAME (fn), 0));
! fprintf (stream, ";; enabled by -%s", dump_flag_name (phase));
fprintf (stream, "\n\n");
dump_node (fn, TDF_SLIM | flags, stream);
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/semantics.c,v
retrieving revision 1.214
diff -c -3 -p -r1.214 semantics.c
*** semantics.c 2001/06/18 16:15:12 1.214
--- semantics.c 2001/06/29 14:58:18
*************** expand_body (fn)
*** 2408,2420 ****
timevar_push (TV_INTEGRATION);
! /* Optimize the body of the function before expanding it. We do not
! optimize thunks, as (1) the backend tries to optimize the call to
! the thunkee, (b) the tree based inliner breaks that optimization,
! (c) virtual functions are rarely inlineable, and (d)
! ASM_OUTPUT_MI_THUNK is there to DTRT anyway. */
! if (!DECL_THUNK_P (fn))
! optimize_function (fn);
timevar_pop (TV_INTEGRATION);
timevar_push (TV_EXPAND);
--- 2408,2415 ----
timevar_push (TV_INTEGRATION);
! /* Optimize the body of the function before expanding it. */
! optimize_function (fn);
timevar_pop (TV_INTEGRATION);
timevar_push (TV_EXPAND);
Index: c-common.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-common.h,v
retrieving revision 1.75
diff -c -3 -p -r1.75 c-common.h
*** c-common.h 2001/06/18 16:15:01 1.75
--- c-common.h 2001/06/29 14:58:19
*************** enum tree_dump_index
*** 814,821 ****
{
TDI_all, /* dump the whole translation unit */
TDI_original, /* dump each function before optimizing it */
! TDI_optimized, /* dump each function after optimizing it */
TDI_class, /* dump class heirarchy */
TDI_end
};
--- 814,823 ----
{
TDI_all, /* dump the whole translation unit */
TDI_original, /* dump each function before optimizing it */
! TDI_optimized, /* dump each function after optimizing it */
TDI_class, /* dump class heirarchy */
+ TDI_inlined, /* dump each function after inlining
+ within it. */
TDI_end
};
*************** extern FILE *dump_begin PARAMS ((enum
*** 839,844 ****
--- 841,847 ----
extern void dump_end PARAMS ((enum tree_dump_index, FILE *));
extern void dump_node PARAMS ((tree, int, FILE *));
extern int dump_switch_p PARAMS ((const char *));
+ extern const char *dump_flag_name PARAMS ((enum tree_dump_index));
/* Information recorded about each file examined during compilation. */
Index: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/doc/invoke.texi,v
retrieving revision 1.24
diff -c -3 -p -r1.24 invoke.texi
*** invoke.texi 2001/06/27 15:04:15 1.24
--- invoke.texi 2001/06/29 14:58:24
*************** in the following sections.
*** 239,244 ****
--- 239,245 ----
-a -ax -d@var{letters} -dumpspecs -dumpmachine -dumpversion @gol
-fdump-unnumbered -fdump-translation-unit@r{[}-@var{n}@r{]} -fdump-class-hierarchy@r{[}-@var{n}@r{]} @gol
-fdump-ast-original@r{[}-@var{n}@r{]} -fdump-ast-optimized@r{[}-@var{n}@r{]} @gol
+ -fdump-ast-inlined@r{[}-@var{n}@r{]} @gol
-fmem-report -fpretend-float @gol
-fprofile-arcs -ftest-coverage -ftime-report @gol
-g -g@var{level} -gcoff -gdwarf -gdwarf-1 -gdwarf-1+ -gdwarf-2 @gol
*************** The following tree dumps are possible:
*** 3029,3034 ****
--- 3030,3038 ----
Dump before any tree based optimization, to @file{@var{file}.original}.
@item optimized
Dump after all tree based optimization, to @file{@var{file}.optimized}.
+ @item inlined
+ Dump after inlining within the body of the function, to
+ @file{@var{file}.inlined}.
@end table
@item -fpretend-float
Index: c-dump.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-dump.c,v
retrieving revision 1.4
diff -c -3 -p -r1.4 c-dump.c
*** c-dump.c 2001/06/05 08:03:44 1.4
--- c-dump.c 2001/07/01 19:44:57
*************** static struct dump_file_info dump_files[
*** 802,807 ****
--- 802,808 ----
{".original", "dump-ast-original", 0, 0},
{".optimized", "dump-ast-optimized", 0, 0},
{".class", "dump-class-hierarchy", 0, 0},
+ {".inlined", "dump-ast-inlined", 0, 0},
};
/* Begin a tree dump for PHASE. Stores any user supplied flag in
*************** dump_begin (phase, flag_ptr)
*** 835,850 ****
/* Returns non-zero if tree dump PHASE is enabled. */
! int dump_enabled_p (phase)
enum tree_dump_index phase;
{
return dump_files[phase].state;
}
/* Finish a tree dump for PHASE. STREAM is the stream created by
dump_begin. */
! void dump_end (phase, stream)
enum tree_dump_index phase ATTRIBUTE_UNUSED;
FILE *stream;
{
--- 836,862 ----
/* Returns non-zero if tree dump PHASE is enabled. */
! int
! dump_enabled_p (phase)
enum tree_dump_index phase;
{
return dump_files[phase].state;
}
+ /* Returns the switch name of PHASE. */
+
+ const char *
+ dump_flag_name (phase)
+ enum tree_dump_index phase;
+ {
+ return dump_files[phase].swtch;
+ }
+
/* Finish a tree dump for PHASE. STREAM is the stream created by
dump_begin. */
! void
! dump_end (phase, stream)
enum tree_dump_index phase ATTRIBUTE_UNUSED;
FILE *stream;
{
*************** void dump_end (phase, stream)
*** 854,860 ****
/* Parse ARG as a dump switch. Return non-zero if it is, and store the
relevant details in the dump_files array. */
! int dump_switch_p (arg)
const char *arg;
{
unsigned ix;
--- 866,873 ----
/* Parse ARG as a dump switch. Return non-zero if it is, and store the
relevant details in the dump_files array. */
! int
! dump_switch_p (arg)
const char *arg;
{
unsigned ix;
More information about the Gcc-patches
mailing list