This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Update pass manager to handle generate_summary/transform functions
- From: "H.J. Lu" <hjl dot tools at gmail dot com>
- To: "Jan Hubicka" <jh at suse dot cz>
- Cc: gcc-patches at gcc dot gnu dot org, dnovillo at google dot com, zadeck at naturalbridge dot com
- Date: Thu, 1 May 2008 09:41:28 -0700
- Subject: Re: Update pass manager to handle generate_summary/transform functions
- References: <20080405065456.GI30149@kam.mff.cuni.cz> <6dc9ffc80805010934n16aeed3ci83b77b72c0a572b6@mail.gmail.com>
I opened a bug report
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36100
H.J.
On Thu, May 1, 2008 at 9:34 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> Hi Jan,
>
> I think this patch breaks always_inline attribute at -O0:
>
> [hjl@gnu-6 gcc]$ cat /tmp/y.c
> #include <emmintrin.h>
>
> int
> main ()
> {
> __m128i x, y;
> x = _mm_xor_si128 (x, y);
> return 0;
> }
> [hjl@gnu-6 gcc]$ ./xgcc -B./ -m32 /tmp/y.c -msse2
> /tmp/ccQGxyxs.o: In function `main':
> y.c:(.text+0x24): undefined reference to `_mm_xor_si128'
> collect2: ld returned 1 exit status
> [hjl@gnu-6 gcc]$
>
> H.J.
> ---
>
>
>
> On Fri, Apr 4, 2008 at 11:54 PM, Jan Hubicka <jh@suse.cz> wrote:
> > Hi,
> > this patch updates PM to handle IPA_PASS with separate
> > generate_summary/transform hooks and update inliner to use new infrastructure.
> >
> > Pass manager now execute generate_summary of all IPA_PASS passes in queue in
> > sequence on each function/variable before executing them and it adds their
> > transform functions into lists housed in cfun. Those lists are executed before
> > next local pass is done.
> >
> > I use private lists for each function since IPA passes might introduce new functions
> > during execution we don't want to run earlier transforms on.
> >
> > This is meant to be initial implementation, I didn't add support for variables
> > yet and also PM should be smarter and couple summary generation with previous
> > local pass if available. This is however enough so we can turn existing passes
> > to the scheme and I have followup for this ready.
> >
> > Bootstrapped/regtested i686-linux, OK?
> >
> > * tree-pass.h (opt_pass): Add IPA_PASS.
> > (varpool_node, cgraph_node): Forward declare.
> > (ipa_opt_pass): Define.
> > (pass_ipa_inline): Turn into ipa_opt_pass.
> > (pass_apply_inline): Remove.
> > * ipa-inline.c (pass_ipa_inline): Turn into ipa_opt_pass.
> > (apply_inline): Turn into ....
> > (inline_transform): ... this one.
> > (inline_generate_summary): New function.
> > (pass_apply_inline): Remove.
> > * function.h (ipa_opt_pass): Forward declare structure; typedef;
> > vector.
> > (struct function): Add ipa_transforms_to_apply.
> > * passes.c (register_one_dump_file): Work on IPA_PASS.
> > (init_optimization_passes): Remove pass_inline_parameters and
> > pass_apply_inline.
> > (pass_init_dump_file, pass_fini_dump_file): Break out from ....
> > (execute_one_pass) ... here; apply transforms when possible.
> > (add_ipa_transform_pass, execute_ipa_summary_asses,
> > execute_one_ipa_transform_pass): New.
> > (execute_ipa_pass_list): Update for IPA_PASS type.
> >
> > Index: tree-pass.h
> > ===================================================================
> > *** tree-pass.h (revision 133930)
> > --- tree-pass.h (working copy)
> > *************** struct opt_pass
> > *** 96,102 ****
> > enum opt_pass_type {
> > GIMPLE_PASS,
> > RTL_PASS,
> > ! SIMPLE_IPA_PASS
> > } type;
> > /* Terse name of the pass used as a fragment of the dump file name. */
> > const char *name;
> > --- 96,103 ----
> > enum opt_pass_type {
> > GIMPLE_PASS,
> > RTL_PASS,
> > ! SIMPLE_IPA_PASS,
> > ! IPA_PASS
> > } type;
> > /* Terse name of the pass used as a fragment of the dump file name. */
> > const char *name;
> > *************** struct opt_pass
> > *** 133,139 ****
> > unsigned int todo_flags_finish;
> > };
> >
> > ! /* Description or GIMPLE pass. */
> > struct gimple_opt_pass
> > {
> > struct opt_pass pass;
> > --- 134,140 ----
> > unsigned int todo_flags_finish;
> > };
> >
> > ! /* Description of GIMPLE pass. */
> > struct gimple_opt_pass
> > {
> > struct opt_pass pass;
> > *************** struct rtl_opt_pass
> > *** 145,151 ****
> > struct opt_pass pass;
> > };
> >
> > ! /* Description if simple IPA pass. Simple IPA passes have just one execute
> > hook. */
> > struct simple_ipa_opt_pass
> > {
> > --- 146,181 ----
> > struct opt_pass pass;
> > };
> >
> > ! struct varpool_node;
> > ! struct cgraph_node;
> > !
> > ! /* Description of IPA pass with generate summary, write, execute, read and
> > ! transform stages. */
> > ! struct ipa_opt_pass
> > ! {
> > ! struct opt_pass pass;
> > !
> > ! /* IPA passes can analyze function body and variable initializers using this
> > ! hook and produce summary. */
> > ! void (*function_generate_summary) (struct cgraph_node *);
> > ! void (*variable_generate_summary) (struct varpool_node *);
> > !
> > ! /* These hooks will be used to serialize IPA summaries on disk. For a moment
> > ! they are just placeholders. */
> > ! void (*function_write_summary) (struct cgraph_node *);
> > ! void (*variable_write_summary) (struct varpool_node *);
> > ! void (*function_read_summary) (struct cgraph_node *);
> > ! void (*variable_read_summary) (struct varpool_node *);
> > !
> > ! /* Results of interprocedural propagation of an IPA pass is applied to
> > ! function body via this hook. */
> > ! unsigned int function_transform_todo_flags_start;
> > ! unsigned int (*function_transform) (struct cgraph_node *);
> > ! void (*variable_transform) (struct varpool_node *);
> > !
> > ! };
> > !
> > ! /* Description of simple IPA pass. Simple IPA passes have just one execute
> > hook. */
> > struct simple_ipa_opt_pass
> > {
> > *************** extern struct gimple_opt_pass pass_build
> > *** 353,361 ****
> > extern struct gimple_opt_pass pass_reset_cc_flags;
> >
> > /* IPA Passes */
> > extern struct simple_ipa_opt_pass pass_ipa_matrix_reorg;
> > extern struct simple_ipa_opt_pass pass_ipa_cp;
> > - extern struct simple_ipa_opt_pass pass_ipa_inline;
> > extern struct simple_ipa_opt_pass pass_ipa_early_inline;
> > extern struct simple_ipa_opt_pass pass_ipa_reference;
> > extern struct simple_ipa_opt_pass pass_ipa_pure_const;
> > --- 383,392 ----
> > extern struct gimple_opt_pass pass_reset_cc_flags;
> >
> > /* IPA Passes */
> > + extern struct ipa_opt_pass pass_ipa_inline;
> > +
> > extern struct simple_ipa_opt_pass pass_ipa_matrix_reorg;
> > extern struct simple_ipa_opt_pass pass_ipa_cp;
> > extern struct simple_ipa_opt_pass pass_ipa_early_inline;
> > extern struct simple_ipa_opt_pass pass_ipa_reference;
> > extern struct simple_ipa_opt_pass pass_ipa_pure_const;
> > *************** extern struct rtl_opt_pass pass_rtl_seqa
> > *** 469,475 ****
> > extern struct gimple_opt_pass pass_release_ssa_names;
> > extern struct gimple_opt_pass pass_early_inline;
> > extern struct gimple_opt_pass pass_inline_parameters;
> > - extern struct gimple_opt_pass pass_apply_inline;
> > extern struct gimple_opt_pass pass_all_early_optimizations;
> > extern struct gimple_opt_pass pass_update_address_taken;
> >
> > --- 500,505 ----
> > Index: ipa-inline.c
> > ===================================================================
> > *** ipa-inline.c (revision 133930)
> > --- ipa-inline.c (working copy)
> > *************** cgraph_gate_inlining (void)
> > *** 1426,1451 ****
> > return flag_inline_trees;
> > }
> >
> > - struct simple_ipa_opt_pass pass_ipa_inline =
> > - {
> > - {
> > - SIMPLE_IPA_PASS,
> > - "inline", /* name */
> > - cgraph_gate_inlining, /* gate */
> > - cgraph_decide_inlining, /* execute */
> > - NULL, /* sub */
> > - NULL, /* next */
> > - 0, /* static_pass_number */
> > - TV_INLINE_HEURISTICS, /* tv_id */
> > - 0, /* properties_required */
> > - PROP_cfg, /* properties_provided */
> > - 0, /* properties_destroyed */
> > - TODO_remove_functions, /* todo_flags_finish */
> > - TODO_dump_cgraph | TODO_dump_func
> > - | TODO_remove_functions /* todo_flags_finish */
> > - }
> > - };
> > -
> > /* Because inlining might remove no-longer reachable nodes, we need to
> > keep the array visible to garbage collector to avoid reading collected
> > out nodes. */
> > --- 1426,1431 ----
> > *************** struct gimple_opt_pass pass_inline_param
> > *** 1579,1591 ****
> > }
> > };
> >
> > ! /* Apply inline plan to the function. */
> > ! static unsigned int
> > ! apply_inline (void)
> > {
> > unsigned int todo = 0;
> > struct cgraph_edge *e;
> > - struct cgraph_node *node = cgraph_node (current_function_decl);
> >
> > /* Even when not optimizing, ensure that always_inline functions get inlined.
> > */
> > --- 1559,1578 ----
> > }
> > };
> >
> > ! /* Note function body size. */
> > ! void
> > ! inline_generate_summary (struct cgraph_node *node ATTRIBUTE_UNUSED)
> > ! {
> > ! compute_inline_parameters ();
> > ! return;
> > ! }
> > !
> > ! /* Apply inline plan to function. */
> > ! int
> > ! inline_transform (struct cgraph_node *node)
> > {
> > unsigned int todo = 0;
> > struct cgraph_edge *e;
> >
> > /* Even when not optimizing, ensure that always_inline functions get inlined.
> > */
> > *************** apply_inline (void)
> > *** 1617,1629 ****
> > return todo | execute_fixup_cfg ();
> > }
> >
> > ! struct gimple_opt_pass pass_apply_inline =
> > {
> > {
> > ! GIMPLE_PASS,
> > ! "apply_inline", /* name */
> > ! NULL, /* gate */
> > ! apply_inline, /* execute */
> > NULL, /* sub */
> > NULL, /* next */
> > 0, /* static_pass_number */
> > --- 1604,1616 ----
> > return todo | execute_fixup_cfg ();
> > }
> >
> > ! struct ipa_opt_pass pass_ipa_inline =
> > {
> > {
> > ! IPA_PASS,
> > ! "inline", /* name */
> > ! cgraph_gate_inlining, /* gate */
> > ! cgraph_decide_inlining, /* execute */
> > NULL, /* sub */
> > NULL, /* next */
> > 0, /* static_pass_number */
> > *************** struct gimple_opt_pass pass_apply_inline
> > *** 1631,1640 ****
> > 0, /* properties_required */
> > PROP_cfg, /* properties_provided */
> > 0, /* properties_destroyed */
> > ! 0, /* todo_flags_start */
> > ! TODO_dump_func | TODO_verify_flow
> > ! | TODO_verify_stmts /* todo_flags_finish */
> > ! }
> > };
> >
> > #include "gt-ipa-inline.h"
> > --- 1618,1636 ----
> > 0, /* properties_required */
> > PROP_cfg, /* properties_provided */
> > 0, /* properties_destroyed */
> > ! TODO_remove_functions, /* todo_flags_finish */
> > ! TODO_dump_cgraph | TODO_dump_func
> > ! | TODO_remove_functions /* todo_flags_finish */
> > ! },
> > ! inline_generate_summary, /* function_generate_summary */
> > ! NULL, /* variable_generate_summary */
> > ! NULL, /* function_write_summary */
> > ! NULL, /* variable_write_summary */
> > ! NULL, /* function_read_summary */
> > ! NULL, /* variable_read_summary */
> > ! 0, /* TODOs */
> > ! inline_transform, /* function_transform */
> > ! NULL, /* variable_transform */
> > };
> >
> > #include "gt-ipa-inline.h"
> > Index: function.h
> > ===================================================================
> > *** function.h (revision 133930)
> > --- function.h (working copy)
> > *************** typedef struct temp_slot *temp_slot_p;
> > *** 149,154 ****
> > --- 149,159 ----
> >
> > DEF_VEC_P(temp_slot_p);
> > DEF_VEC_ALLOC_P(temp_slot_p,gc);
> > + struct ipa_opt_pass;
> > + typedef struct ipa_opt_pass *ipa_opt_pass;
> > +
> > + DEF_VEC_P(ipa_opt_pass);
> > + DEF_VEC_ALLOC_P(ipa_opt_pass,heap);
> >
> > enum function_frequency {
> > /* This function most likely won't be executed at all.
> > *************** struct function GTY(())
> > *** 375,380 ****
> > --- 380,389 ----
> > /* Properties used by the pass manager. */
> > unsigned int curr_properties;
> > unsigned int last_verified;
> > + /* Interprocedural passes scheduled to have their transform functions
> > + applied next time we execute local pass on them. We maintain it
> > + per-function in order to allow IPA passes to introduce new functions. */
> > + VEC(ipa_opt_pass,heap) * GTY((skip)) ipa_transforms_to_apply;
> >
> > /* Collected bit flags. */
> >
> > Index: passes.c
> > ===================================================================
> > *** passes.c (revision 133930)
> > --- passes.c (working copy)
> > *************** register_one_dump_file (struct opt_pass
> > *** 352,358 ****
> > ? 1 : pass->static_pass_number));
> >
> > dot_name = concat (".", pass->name, num, NULL);
> > ! if (pass->type == SIMPLE_IPA_PASS)
> > prefix = "ipa-", flags = TDF_IPA;
> > else if (pass->type == GIMPLE_PASS)
> > prefix = "tree-", flags = TDF_TREE;
> > --- 352,358 ----
> > ? 1 : pass->static_pass_number));
> >
> > dot_name = concat (".", pass->name, num, NULL);
> > ! if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS)
> > prefix = "ipa-", flags = TDF_IPA;
> > else if (pass->type == GIMPLE_PASS)
> > prefix = "tree-", flags = TDF_TREE;
> > *************** init_optimization_passes (void)
> > *** 538,544 ****
> > NEXT_PASS (pass_release_ssa_names);
> > }
> > NEXT_PASS (pass_rebuild_cgraph_edges);
> > - NEXT_PASS (pass_inline_parameters);
> > }
> > NEXT_PASS (pass_ipa_increase_alignment);
> > NEXT_PASS (pass_ipa_matrix_reorg);
> > --- 538,543 ----
> > *************** init_optimization_passes (void)
> > *** 554,560 ****
> > /* These passes are run after IPA passes on every function that is being
> > output to the assembler file. */
> > p = &all_passes;
> > - NEXT_PASS (pass_apply_inline);
> > NEXT_PASS (pass_all_optimizations);
> > {
> > struct opt_pass **p = &pass_all_optimizations.pass.sub;
> > --- 553,558 ----
> > *************** verify_curr_properties (void *data)
> > *** 1053,1058 ****
> > --- 1051,1103 ----
> > }
> > #endif
> >
> > + /* Initialize pass dump file. */
> > + static bool
> > + pass_init_dump_file (struct opt_pass *pass)
> > + {
> > + /* If a dump file name is present, open it if enabled. */
> > + if (pass->static_pass_number != -1)
> > + {
> > + bool initializing_dump = !dump_initialized_p (pass->static_pass_number);
> > + dump_file_name = get_dump_file_name (pass->static_pass_number);
> > + dump_file = dump_begin (pass->static_pass_number, &dump_flags);
> > + if (dump_file && current_function_decl)
> > + {
> > + const char *dname, *aname;
> > + dname = lang_hooks.decl_printable_name (current_function_decl, 2);
> > + aname = (IDENTIFIER_POINTER
> > + (DECL_ASSEMBLER_NAME (current_function_decl)));
> > + fprintf (dump_file, "\n;; Appli transform to function %s (%s)%s\n\n", dname, aname,
> > + cfun->function_frequency == FUNCTION_FREQUENCY_HOT
> > + ? " (hot)"
> > + : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED
> > + ? " (unlikely executed)"
> > + : "");
> > + }
> > + return initializing_dump;
> > + }
> > + else
> > + return false;
> > + }
> > +
> > + /* Flush pass dump file. */
> > + static void
> > + pass_fini_dump_file (struct opt_pass *pass)
> > + {
> > + /* Flush and close dump file. */
> > + if (dump_file_name)
> > + {
> > + free (CONST_CAST (char *, dump_file_name));
> > + dump_file_name = NULL;
> > + }
> > +
> > + if (dump_file)
> > + {
> > + dump_end (pass->static_pass_number, dump_file);
> > + dump_file = NULL;
> > + }
> > + }
> > +
> > /* After executing the pass, apply expected changes to the function
> > properties. */
> > static void
> > *************** update_properties_after_pass (void *data
> > *** 1063,1068 ****
> > --- 1108,1183 ----
> > & ~pass->properties_destroyed;
> > }
> >
> > + /* Schedule IPA transform pass DATA for CFUN. */
> > + static void
> > + add_ipa_transform_pass (void *data)
> > + {
> > + struct ipa_opt_pass *ipa_pass = (struct ipa_opt_pass *) data;
> > + VEC_safe_push (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply, ipa_pass);
> > + }
> > +
> > + /* Execute IPA pass function summary generation. */
> > + static void
> > + execute_ipa_summary_passes (void *data)
> > + {
> > + struct ipa_opt_pass *ipa_pass = (struct ipa_opt_pass *)data;
> > + struct cgraph_node *node = cgraph_node (cfun->decl);
> > + while (ipa_pass && ipa_pass->pass.type == IPA_PASS)
> > + {
> > + struct opt_pass *pass = &ipa_pass->pass;
> > + if (!pass->gate || pass->gate ())
> > + {
> > + pass_init_dump_file (pass);
> > + ipa_pass->function_generate_summary (node);
> > + pass_fini_dump_file (pass);
> > + }
> > + ipa_pass = (struct ipa_opt_pass *)ipa_pass->pass.next;
> > + }
> > + }
> > +
> > + /* Execute IPA pass function transform. */
> > + static void
> > + execute_one_ipa_transform_pass (struct cgraph_node *node,
> > + struct ipa_opt_pass *ipa_pass)
> > + {
> > + struct opt_pass *pass = &ipa_pass->pass;
> > + unsigned int todo_after = 0;
> > +
> > + current_pass = pass;
> > + if (!ipa_pass->function_transform)
> > + return;
> > +
> > + /* Note that the folders should only create gimple expressions.
> > + This is a hack until the new folder is ready. */
> > + in_gimple_form = (cfun && (cfun->curr_properties & PROP_trees)) != 0;
> > +
> > + pass_init_dump_file (pass);
> > +
> > + /* Run pre-pass verification. */
> > + execute_todo (pass->todo_flags_start);
> > +
> > + /* If a timevar is present, start it. */
> > + if (pass->tv_id)
> > + timevar_push (pass->tv_id);
> > +
> > + /* Do it! */
> > + todo_after = ipa_pass->function_transform (node);
> > +
> > + /* Stop timevar. */
> > + if (pass->tv_id)
> > + timevar_pop (pass->tv_id);
> > +
> > + /* Run post-pass cleanup and verification. */
> > + execute_todo (todo_after);
> > + verify_interpass_invariants ();
> > +
> > + pass_fini_dump_file (pass);
> > +
> > + current_pass = NULL;
> > + /* Reset in_gimple_form to not break non-unit-at-a-time mode. */
> > + in_gimple_form = false;
> > + }
> > +
> > static bool
> > execute_one_pass (struct opt_pass *pass)
> > {
> > *************** execute_one_pass (struct opt_pass *pass)
> > *** 1071,1077 ****
> >
> > /* IPA passes are executed on whole program, so cfun should be NULL.
> > Ohter passes needs function context set. */
> > ! if (pass->type == SIMPLE_IPA_PASS)
> > gcc_assert (!cfun && !current_function_decl);
> > else
> > {
> > --- 1186,1192 ----
> >
> > /* IPA passes are executed on whole program, so cfun should be NULL.
> > Ohter passes needs function context set. */
> > ! if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS)
> > gcc_assert (!cfun && !current_function_decl);
> > else
> > {
> > *************** execute_one_pass (struct opt_pass *pass)
> > *** 1080,1085 ****
> > --- 1195,1215 ----
> > || pass->type != RTL_PASS);
> > }
> >
> > + if (cfun && cfun->ipa_transforms_to_apply)
> > + {
> > + unsigned int i;
> > + struct cgraph_node *node = cgraph_node (current_function_decl);
> > +
> > + for (i = 0; i < VEC_length (ipa_opt_pass, cfun->ipa_transforms_to_apply);
> > + i++)
> > + execute_one_ipa_transform_pass (node,
> > + VEC_index (ipa_opt_pass,
> > + cfun->ipa_transforms_to_apply,
> > + i));
> > + VEC_free (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply);
> > + cfun->ipa_transforms_to_apply = NULL;
> > + }
> > +
> > current_pass = pass;
> > /* See if we're supposed to run this pass. */
> > if (pass->gate && !pass->gate ())
> > *************** execute_one_pass (struct opt_pass *pass)
> > *** 1103,1130 ****
> > (void *)(size_t)pass->properties_required);
> > #endif
> >
> > ! /* If a dump file name is present, open it if enabled. */
> > ! if (pass->static_pass_number != -1)
> > ! {
> > ! initializing_dump = !dump_initialized_p (pass->static_pass_number);
> > ! dump_file_name = get_dump_file_name (pass->static_pass_number);
> > ! dump_file = dump_begin (pass->static_pass_number, &dump_flags);
> > ! if (dump_file && current_function_decl)
> > ! {
> > ! const char *dname, *aname;
> > ! dname = lang_hooks.decl_printable_name (current_function_decl, 2);
> > ! aname = (IDENTIFIER_POINTER
> > ! (DECL_ASSEMBLER_NAME (current_function_decl)));
> > ! fprintf (dump_file, "\n;; Function %s (%s)%s\n\n", dname, aname,
> > ! cfun->function_frequency == FUNCTION_FREQUENCY_HOT
> > ! ? " (hot)"
> > ! : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED
> > ! ? " (unlikely executed)"
> > ! : "");
> > ! }
> > ! }
> > ! else
> > ! initializing_dump = false;
> >
> > /* If a timevar is present, start it. */
> > if (pass->tv_id)
> > --- 1233,1239 ----
> > (void *)(size_t)pass->properties_required);
> > #endif
> >
> > ! initializing_dump = pass_init_dump_file (pass);
> >
> > /* If a timevar is present, start it. */
> > if (pass->tv_id)
> > *************** execute_one_pass (struct opt_pass *pass)
> > *** 1157,1178 ****
> > /* Run post-pass cleanup and verification. */
> > execute_todo (todo_after | pass->todo_flags_finish);
> > verify_interpass_invariants ();
> >
> > if (!current_function_decl)
> > cgraph_process_new_functions ();
> >
> > ! /* Flush and close dump file. */
> > ! if (dump_file_name)
> > ! {
> > ! free (CONST_CAST (char *, dump_file_name));
> > ! dump_file_name = NULL;
> > ! }
> > !
> > ! if (dump_file)
> > ! {
> > ! dump_end (pass->static_pass_number, dump_file);
> > ! dump_file = NULL;
> > ! }
> >
> > current_pass = NULL;
> > /* Reset in_gimple_form to not break non-unit-at-a-time mode. */
> > --- 1266,1278 ----
> > /* Run post-pass cleanup and verification. */
> > execute_todo (todo_after | pass->todo_flags_finish);
> > verify_interpass_invariants ();
> > + if (pass->type == IPA_PASS)
> > + do_per_function (add_ipa_transform_pass, pass);
> >
> > if (!current_function_decl)
> > cgraph_process_new_functions ();
> >
> > ! pass_fini_dump_file (pass);
> >
> > current_pass = NULL;
> > /* Reset in_gimple_form to not break non-unit-at-a-time mode. */
> > *************** execute_pass_list (struct opt_pass *pass
> > *** 1200,1216 ****
> > void
> > execute_ipa_pass_list (struct opt_pass *pass)
> > {
> > do
> > {
> > gcc_assert (!current_function_decl);
> > gcc_assert (!cfun);
> > ! gcc_assert (pass->type == SIMPLE_IPA_PASS);
> > if (execute_one_pass (pass) && pass->sub)
> > {
> > if (pass->sub->type == GIMPLE_PASS)
> > do_per_function_toporder ((void (*)(void *))execute_pass_list,
> > pass->sub);
> > ! else if (pass->sub->type == SIMPLE_IPA_PASS)
> > execute_ipa_pass_list (pass->sub);
> > else
> > gcc_unreachable ();
> > --- 1300,1330 ----
> > void
> > execute_ipa_pass_list (struct opt_pass *pass)
> > {
> > + bool summaries_generated = false;
> > do
> > {
> > gcc_assert (!current_function_decl);
> > gcc_assert (!cfun);
> > ! gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
> > ! if (pass->type == IPA_PASS && (!pass->gate || pass->gate ()))
> > ! {
> > ! if (!summaries_generated)
> > ! {
> > ! if (!quiet_flag && !cfun)
> > ! fprintf (stderr, " <summary generate>");
> > ! do_per_function_toporder (execute_ipa_summary_passes, pass);
> > ! }
> > ! summaries_generated = true;
> > ! }
> > ! else
> > ! summaries_generated = false;
> > if (execute_one_pass (pass) && pass->sub)
> > {
> > if (pass->sub->type == GIMPLE_PASS)
> > do_per_function_toporder ((void (*)(void *))execute_pass_list,
> > pass->sub);
> > ! else if (pass->sub->type == SIMPLE_IPA_PASS
> > ! || pass->sub->type == IPA_PASS)
> > execute_ipa_pass_list (pass->sub);
> > else
> > gcc_unreachable ();
> >
>