static struct dump_file_info dump_files[TDI_end] =
{
{".tu", "dump-translation-unit", 0, 0},
+ {".class", "dump-class-hierarchy", 0, 0},
{".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
/* Returns non-zero if tree dump PHASE is enabled. */
-int dump_enabled_p (phase)
+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)
+void
+dump_end (phase, stream)
enum tree_dump_index phase ATTRIBUTE_UNUSED;
FILE *stream;
{
/* 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)
+int
+dump_switch_p (arg)
const char *arg;
{
unsigned ix;
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
+ 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 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));
walk_tree (tp, expand_call_inline, id, id->tree_pruner);
}
+/* Expand calls to inline functions in the body of FN. */
+
+static 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));
+
+ /* 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
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);
- }
-
+ 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))
+ optimize_inline_calls (fn);
+
/* Undo the call to ggc_push_context above. */
--function_depth;
{
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");
+ fprintf (stream, " (%s)\n",
+ decl_as_string (DECL_ASSEMBLER_NAME (fn), 0));
+ fprintf (stream, ";; enabled by -%s\n", dump_flag_name (phase));
+ fprintf (stream, "\n");
dump_node (fn, TDF_SLIM | flags, stream);
dump_end (phase, stream);
-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
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
current directory, if appropriate) are searched. @xref{Directory
Options}, for information on @option{-I}.
-By using both @option{-nostdinc} and @option{-I-}, you can limit the include-file
-search path to only those directories you specify explicitly.
+By using both @option{-nostdinc} and @option{-I-}, you can limit the
+include-file search path to only those directories you specify explicitly.
@item -remap
@opindex remap
one @option{-I} option, the directories are scanned in left-to-right
order; the standard system directories come after.
+GCC will detect and warn you, if a directory is specified with both the
+@option{-I} and also is a system search directory (either by default, or
+with @option{-isystem}).
+
@item -I-
@opindex I-
Any directories you specify with @option{-I} options before the @option{-I-}