diff mbox

New options to disable/enable any pass for any functions (issue4550056)

Message ID 20110518183708.D5E5A207D9@syzygy.mtv.corp.google.com
State New
Headers show

Commit Message

Xinliang David Li May 18, 2011, 6:37 p.m. UTC
In gcc, not all passes have user level control to turn it on/off, and
there is no way to flip on/off the pass for a subset of functions. I
implemented a generic option handling scheme in gcc to allow
disabling/enabling any gcc pass for any specified function(s).  The
new options will be very useful for things like performance
experiments and bug triaging (gcc has dbgcnt mechanism, but not all
passes have the counter).

The option syntax is very similar to -fdump- options. The following
are some examples:

-fdisable-tree-ccp1    <--- disable ccp1 for all functions
-fenable-tree-cunroll=1   <--- enable complete unroll for the function
                           whose cgraphnode uid is 1
-fdisable-rtl-gcse2=1:100,300,400:1000   <-- disable gcse2 for
                                           functions at the following
                                            ranges [1,1], [300,400], and [400,1000]
-fdisable-tree-einline --> disable early inlining for all callers
-fdisable-ipa-inline --> disable ipa inlininig

In the gcc dumps, the uid numbers are displayed in the function header.

The options are intended to be used internally by gcc developers.

Ok for trunk ? (There is a little LIPO specific change that can be removed).

David

2011-05-18  David Li  <davidxl@google.com>

	* final.c (rest_of_clean_state): Call function header dumper.
	* opts-global.c (handle_common_deferred_options): Handle new options.
	* tree-cfg.c (gimple_dump_cfg): Call function header dumper.
	* passes.c (register_one_dump_file): Call register_pass_name.
	(pass_init_dump_file): Call function header dumper.
	(execute_one_pass): Check explicit enable/disable flag.
	(passr_hash): New function.
	(passr_eq): 
	(register_pass_name):
	(get_pass_by_name):
	(pass_hash):
	(pass_eq):
	(enable_disable_pass):
	(is_pass_explicitly_enabled_or_disabled):
	(is_pass_explicitly_enabled):
	(is_pass_explicitly_disabled):



--
This patch is available for review at http://codereview.appspot.com/4550056

Comments

Joseph Myers May 18, 2011, 7:30 p.m. UTC | #1
On Wed, 18 May 2011, David Li wrote:

> +      error ("Unrecognized option %s", is_enable ? "-fenable" : "-fdisable");

> +      error ("Unknown pass %s specified in %s",
> +	     phase_name,
> +	     is_enable ? "-fenable" : "-fdisable");

Follow GNU Coding Standards for diagnostics (start with lowercase letter).

> +      inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
> +              is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);

Use separate calls to inform for the enable and disable cases, so that 
full sentences can be extracted for translation.

> +	      error ("Invalid range %s in option %s",
> +		     one_range,
> +		     is_enable ? "-fenable" : "-fdisable");

GNU Coding Standards.

> +		  error ("Invalid range %s in option %s",

Likewise.

> +          inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
> +                  is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);

Again needs GCS and i18n fixes.
Xinliang David Li May 18, 2011, 7:42 p.m. UTC | #2
Thanks for the comment. Will fix those.

David

On Wed, May 18, 2011 at 12:30 PM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> On Wed, 18 May 2011, David Li wrote:
>
>> +      error ("Unrecognized option %s", is_enable ? "-fenable" : "-fdisable");
>
>> +      error ("Unknown pass %s specified in %s",
>> +          phase_name,
>> +          is_enable ? "-fenable" : "-fdisable");
>
> Follow GNU Coding Standards for diagnostics (start with lowercase letter).
>
>> +      inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
>> +              is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);
>
> Use separate calls to inform for the enable and disable cases, so that
> full sentences can be extracted for translation.
>
>> +           error ("Invalid range %s in option %s",
>> +                  one_range,
>> +                  is_enable ? "-fenable" : "-fdisable");
>
> GNU Coding Standards.
>
>> +               error ("Invalid range %s in option %s",
>
> Likewise.
>
>> +          inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
>> +                  is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);
>
> Again needs GCS and i18n fixes.
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>
Richard Biener May 18, 2011, 8:26 p.m. UTC | #3
On Wed, May 18, 2011 at 8:37 PM, David Li <davidxl@google.com> wrote:
>
> In gcc, not all passes have user level control to turn it on/off, and
> there is no way to flip on/off the pass for a subset of functions. I
> implemented a generic option handling scheme in gcc to allow
> disabling/enabling any gcc pass for any specified function(s).  The
> new options will be very useful for things like performance
> experiments and bug triaging (gcc has dbgcnt mechanism, but not all
> passes have the counter).
>
> The option syntax is very similar to -fdump- options. The following
> are some examples:
>
> -fdisable-tree-ccp1    <--- disable ccp1 for all functions
> -fenable-tree-cunroll=1   <--- enable complete unroll for the function
>                           whose cgraphnode uid is 1
> -fdisable-rtl-gcse2=1:100,300,400:1000   <-- disable gcse2 for
>                                           functions at the following
>                                            ranges [1,1], [300,400], and [400,1000]
> -fdisable-tree-einline --> disable early inlining for all callers
> -fdisable-ipa-inline --> disable ipa inlininig
>
> In the gcc dumps, the uid numbers are displayed in the function header.
>
> The options are intended to be used internally by gcc developers.
>
> Ok for trunk ? (There is a little LIPO specific change that can be removed).
>
> David
>
> 2011-05-18  David Li  <davidxl@google.com>
>
>        * final.c (rest_of_clean_state): Call function header dumper.
>        * opts-global.c (handle_common_deferred_options): Handle new options.
>        * tree-cfg.c (gimple_dump_cfg): Call function header dumper.
>        * passes.c (register_one_dump_file): Call register_pass_name.
>        (pass_init_dump_file): Call function header dumper.
>        (execute_one_pass): Check explicit enable/disable flag.
>        (passr_hash): New function.
>        (passr_eq):
>        (register_pass_name):
>        (get_pass_by_name):
>        (pass_hash):
>        (pass_eq):
>        (enable_disable_pass):
>        (is_pass_explicitly_enabled_or_disabled):
>        (is_pass_explicitly_enabled):
>        (is_pass_explicitly_disabled):

Bogus changelog entry.

New options need documenting in doc/invoke.texi.

Richard.

>
> Index: tree-pass.h
> ===================================================================
> --- tree-pass.h (revision 173635)
> +++ tree-pass.h (working copy)
> @@ -644,4 +644,12 @@ extern bool first_pass_instance;
>  /* Declare for plugins.  */
>  extern void do_per_function_toporder (void (*) (void *), void *);
>
> +extern void enable_disable_pass (const char *, bool);
> +extern bool is_pass_explicitly_disabled (struct opt_pass *, tree);
> +extern bool is_pass_explicitly_enabled (struct opt_pass *, tree);
> +extern void register_pass_name (struct opt_pass *, const char *);
> +extern struct opt_pass *get_pass_by_name (const char *);
> +struct function;
> +extern void pass_dump_function_header (FILE *, tree, struct function *);
> +
>  #endif /* GCC_TREE_PASS_H */
> Index: final.c
> ===================================================================
> --- final.c     (revision 173635)
> +++ final.c     (working copy)
> @@ -4456,19 +4456,7 @@ rest_of_clean_state (void)
>        }
>       else
>        {
> -         const char *aname;
> -         struct cgraph_node *node = cgraph_node (current_function_decl);
> -
> -         aname = (IDENTIFIER_POINTER
> -                  (DECL_ASSEMBLER_NAME (current_function_decl)));
> -         fprintf (final_output, "\n;; Function (%s) %s\n\n", aname,
> -            node->frequency == NODE_FREQUENCY_HOT
> -            ? " (hot)"
> -            : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
> -            ? " (unlikely executed)"
> -            : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
> -            ? " (executed once)"
> -            : "");
> +         pass_dump_function_header (final_output, current_function_decl, cfun);
>
>          flag_dump_noaddr = flag_dump_unnumbered = 1;
>          if (flag_compare_debug_opt || flag_compare_debug)
> Index: common.opt
> ===================================================================
> --- common.opt  (revision 173635)
> +++ common.opt  (working copy)
> @@ -1018,6 +1018,14 @@ fdiagnostics-show-option
>  Common Var(flag_diagnostics_show_option) Init(1)
>  Amend appropriate diagnostic messages with the command line option that controls them
>
> +fdisable-
> +Common Joined RejectNegative Var(common_deferred_options) Defer
> +-fdisable-[tree|rtl|ipa]-<pass>=range1+range2 disables an optimization pass
> +
> +fenable-
> +Common Joined RejectNegative Var(common_deferred_options) Defer
> +-fenable-[tree|rtl|ipa]-<pass>=range1+range2 enables an optimization pass
> +
>  fdump-
>  Common Joined RejectNegative Var(common_deferred_options) Defer
>  -fdump-<type>  Dump various compiler internals to a file
> Index: opts-global.c
> ===================================================================
> --- opts-global.c       (revision 173635)
> +++ opts-global.c       (working copy)
> @@ -411,6 +411,12 @@ handle_common_deferred_options (void)
>            error ("unrecognized command line option %<-fdump-%s%>", opt->arg);
>          break;
>
> +       case OPT_fenable_:
> +       case OPT_fdisable_:
> +         enable_disable_pass (opt->arg, (opt->opt_index == OPT_fenable_?
> +                              true : false));
> +          break;
> +
>        case OPT_ffixed_:
>          /* Deferred.  */
>          fix_register (opt->arg, 1, 1);
> Index: tree-cfg.c
> ===================================================================
> --- tree-cfg.c  (revision 173636)
> +++ tree-cfg.c  (working copy)
> @@ -2090,11 +2090,7 @@ gimple_dump_cfg (FILE *file, int flags)
>  {
>   if (flags & TDF_DETAILS)
>     {
> -      const char *funcname
> -       = lang_hooks.decl_printable_name (current_function_decl, 2);
> -
> -      fputc ('\n', file);
> -      fprintf (file, ";; Function %s\n\n", funcname);
> +      pass_dump_function_header (file, current_function_decl, cfun);
>       fprintf (file, ";; \n%d basic blocks, %d edges, last basic block %d.\n\n",
>               n_basic_blocks, n_edges, last_basic_block);
>
> Index: passes.c
> ===================================================================
> --- passes.c    (revision 173635)
> +++ passes.c    (working copy)
> @@ -382,7 +382,7 @@ void
>  register_one_dump_file (struct opt_pass *pass)
>  {
>   char *dot_name, *flag_name, *glob_name;
> -  const char *name, *prefix;
> +  const char *name, *full_name, *prefix;
>   char num[10];
>   int flags, id;
>
> @@ -411,6 +411,8 @@ register_one_dump_file (struct opt_pass
>   glob_name = concat (prefix, name, NULL);
>   id = dump_register (dot_name, flag_name, glob_name, flags);
>   set_pass_for_id (id, pass);
> +  full_name = concat (prefix, pass->name, num, NULL);
> +  register_pass_name (pass, full_name);
>  }
>
>  /* Recursive worker function for register_dump_files.  */
> @@ -454,6 +456,298 @@ register_dump_files (struct opt_pass *pa
>   register_dump_files_1 (pass, properties);
>  }
>
> +struct pass_registry
> +{
> +  const char* unique_name;
> +  struct opt_pass *pass;
> +};
> +
> +/* Pass registry hash function.  */
> +
> +static hashval_t
> +passr_hash (const void *p)
> +{
> +  const struct pass_registry *const s = (const struct pass_registry *const) p;
> +  return htab_hash_string (s->unique_name);
> +}
> +
> +/* Hash equal function  */
> +
> +static int
> +passr_eq (const void *p1, const void *p2)
> +{
> +  const struct pass_registry *const s1 = (const struct pass_registry *const) p1;
> +  const struct pass_registry *const s2 = (const struct pass_registry *const) p2;
> +
> +  return !strcmp (s1->unique_name, s2->unique_name);
> +}
> +
> +static htab_t pass_name_tab = NULL;
> +
> +/* Register PASS with NAME.  */
> +
> +void
> +register_pass_name (struct opt_pass *pass, const char *name)
> +{
> +  struct pass_registry **slot;
> +  struct pass_registry pr;
> +
> +  if (!pass_name_tab)
> +    pass_name_tab = htab_create (10, passr_hash, passr_eq, NULL);
> +
> +  pr.unique_name = name;
> +  slot = (struct pass_registry **) htab_find_slot (pass_name_tab, &pr, INSERT);
> +  if (!*slot)
> +    {
> +      struct pass_registry *new_pr;
> +
> +      new_pr = XCNEW (struct pass_registry);
> +      new_pr->unique_name = xstrdup (name);
> +      new_pr->pass = pass;
> +      *slot = new_pr;
> +    }
> +  else
> +    gcc_assert ((*slot)->pass == pass);
> +}
> +
> +/* Returns the pass with NAME.  */
> +
> +struct opt_pass *
> +get_pass_by_name (const char *name)
> +{
> +  struct pass_registry **slot, pr;
> +
> +  gcc_assert (pass_name_tab);
> +  pr.unique_name = name;
> +  slot = (struct pass_registry **) htab_find_slot (pass_name_tab, &pr, NO_INSERT);
> +
> +  if (!slot || !*slot)
> +    return NULL;
> +
> +  return (*slot)->pass;
> +}
> +
> +
> +/* Range [start, last].  */
> +
> +struct uid_range
> +{
> +  struct opt_pass *pass;
> +  unsigned int start;
> +  unsigned int last;
> +  struct uid_range *next;
> +};
> +
> +/* Hash function for pass structure.  */
> +
> +static hashval_t
> +pass_hash (const void *s)
> +{
> +  const struct uid_range *const p = (const struct uid_range *const) s;
> +  return p->pass->static_pass_number;
> +}
> +
> +/* Pass equal function  */
> +
> +static int
> +pass_eq (const void *s1, const void *s2)
> +{
> +  const struct uid_range *const p1 = (const struct uid_range *const) s1;
> +  const struct uid_range *const p2 = (const struct uid_range *const) s2;
> +  return p1->pass->static_pass_number == p2->pass->static_pass_number;
> +}
> +
> +htab_t enabled_pass_uid_range_tab = NULL;
> +htab_t disabled_pass_uid_range_tab = NULL;
> +
> +/* Parse option string for -fdisable- and -fenabler-
> +   The syntax of the options:
> +
> +   -fenable-<pass_name>
> +   -fdisable-<pass_name>
> +
> +   -fenable-<pass_name>=s1:e1,s2:e2,...
> +   -fdisable-<pass_name>=s1:e1,s2:e2,...
> +*/
> +
> +void
> +enable_disable_pass (const char *arg, bool is_enable)
> +{
> +  struct opt_pass *pass;
> +  htab_t the_tab;
> +  char *range_str, *phase_name;
> +  char *argstr = xstrdup (arg);
> +
> +  range_str = strchr (argstr,'=');
> +  if (range_str)
> +    {
> +      *range_str = '\0';
> +      range_str++;
> +    }
> +
> +  phase_name = argstr;
> +  if (!*phase_name)
> +    {
> +      error ("Unrecognized option %s", is_enable ? "-fenable" : "-fdisable");
> +      free (argstr);
> +      return;
> +    }
> +  pass = get_pass_by_name (phase_name);
> +  if (!pass)
> +    {
> +      error ("Unknown pass %s specified in %s",
> +            phase_name,
> +            is_enable ? "-fenable" : "-fdisable");
> +      free (argstr);
> +      return;
> +    }
> +  if (is_enable)
> +    {
> +      if (!enabled_pass_uid_range_tab)
> +       enabled_pass_uid_range_tab = htab_create (10, pass_hash, pass_eq, NULL);
> +      the_tab = enabled_pass_uid_range_tab;
> +    }
> +  else
> +    {
> +      if (!disabled_pass_uid_range_tab)
> +       disabled_pass_uid_range_tab = htab_create (10, pass_hash, pass_eq, NULL);
> +      the_tab = disabled_pass_uid_range_tab;
> +    }
> +
> +  if (!range_str)
> +    {
> +      struct uid_range **slot;
> +      struct uid_range *new_range = XCNEW (struct uid_range);
> +
> +      new_range->pass = pass;
> +      new_range->start = 0;
> +      new_range->last = (unsigned)-1;
> +
> +      slot = (struct uid_range **) htab_find_slot (the_tab, new_range, INSERT);
> +      new_range->next = *slot;
> +      *slot = new_range;
> +      inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
> +              is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);
> +    }
> +  else
> +    {
> +      char *next_range = NULL;
> +      char *one_range = range_str;
> +      char *end_val = NULL;
> +
> +      do
> +       {
> +         struct uid_range **slot;
> +         struct uid_range *new_range;
> +         char *invalid = NULL;
> +         long start;
> +
> +         next_range = strchr (one_range, ',');
> +         if (next_range)
> +           {
> +             *next_range = '\0';
> +             next_range++;
> +           }
> +
> +         end_val = strchr (one_range, ':');
> +         if (end_val)
> +           {
> +             *end_val = '\0';
> +             end_val++;
> +           }
> +         start = strtol (one_range, &invalid, 10);
> +         if (*invalid || start < 0)
> +           {
> +             error ("Invalid range %s in option %s",
> +                    one_range,
> +                    is_enable ? "-fenable" : "-fdisable");
> +             free (argstr);
> +             return;
> +           }
> +         if (!end_val)
> +           {
> +             new_range = XCNEW (struct uid_range);
> +              new_range->pass = pass;
> +             new_range->start = (unsigned) start;
> +             new_range->last = (unsigned) start;
> +           }
> +         else
> +           {
> +             long last = strtol (end_val, &invalid, 10);
> +             if (*invalid || last < start)
> +               {
> +                 error ("Invalid range %s in option %s",
> +                        end_val,
> +                        is_enable ? "-fenable" : "-fdisable");
> +                 free (argstr);
> +                 return;
> +               }
> +             new_range = XCNEW (struct uid_range);
> +              new_range->pass = pass;
> +             new_range->start = (unsigned) start;
> +             new_range->last = (unsigned) last;
> +           }
> +         slot = (struct uid_range **) htab_find_slot (the_tab, new_range, INSERT);
> +         new_range->next = *slot;
> +         *slot = new_range;
> +          inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
> +                  is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);
> +
> +         one_range = next_range;
> +       } while (next_range);
> +    }
> +
> +  free (argstr);
> +}
> +
> +/* Returns true if PASS is explicitly enabled/disabled for FUNC.  */
> +
> +static bool
> +is_pass_explicitly_enabled_or_disabled (struct opt_pass *pass,
> +                                       tree func, htab_t tab)
> +{
> +  struct uid_range **slot, *range, key;
> +  int cgraph_uid;
> +
> +  if (!tab)
> +    return false;
> +
> +  key.pass = pass;
> +  slot = (struct uid_range **) htab_find_slot (tab, &key, NO_INSERT);
> +  if (!slot || !*slot)
> +    return false;
> +
> +  cgraph_uid = func ? cgraph_node (func)->uid : 0;
> +
> +  range = *slot;
> +  while (range)
> +    {
> +      if ((unsigned) cgraph_uid >= range->start
> +         && (unsigned) cgraph_uid <= range->last)
> +       return true;
> +      range = range->next;
> +    }
> +
> +  return false;
> +}
> +
> +/* Returns true if PASS is explicitly enabled for FUNC.  */
> +
> +bool
> +is_pass_explicitly_enabled (struct opt_pass *pass, tree func)
> +{
> +  return is_pass_explicitly_enabled_or_disabled (pass, func, enabled_pass_uid_range_tab);
> +}
> +
> +/* Returns true if PASS is explicitly disabled for FUNC.  */
> +
> +bool
> +is_pass_explicitly_disabled (struct opt_pass *pass, tree func)
> +{
> +  return is_pass_explicitly_enabled_or_disabled (pass, func, disabled_pass_uid_range_tab);
> +}
> +
> +
>  /* Look at the static_pass_number and duplicate the pass
>    if it is already added to a list. */
>
> @@ -1349,6 +1643,29 @@ verify_curr_properties (void *data)
>  }
>  #endif
>
> +void
> +pass_dump_function_header (FILE *dump_file, tree fdecl, struct function *fun)
> +{
> +  const char *dname, *aname;
> +  struct cgraph_node *node = cgraph_node (fdecl);
> +  dname = lang_hooks.decl_printable_name (fdecl, 2);
> +  aname = (IDENTIFIER_POINTER
> +          (DECL_ASSEMBLER_NAME (fdecl)));
> +  if (L_IPO_COMP_MODE)
> +    fprintf (dump_file, "\n;; Function %s (%s)[%d:%d][uid=%d]", dname, aname,
> +            FUNC_DECL_MODULE_ID (fun), FUNC_DECL_FUNC_ID (fun), node->uid);
> +  else
> +    fprintf (dump_file, "\n;; Function %s (%s)[uid=%d]", dname, aname, node->uid);
> +  fprintf (dump_file, "%s\n\n",
> +           node->frequency == NODE_FREQUENCY_HOT
> +           ? " (hot)"
> +           : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
> +           ? " (unlikely executed)"
> +           : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
> +           ? " (executed once)"
> +           : "");
> +}
> +
>  /* Initialize pass dump file.  */
>  /* This is non-static so that the plugins can use it.  */
>
> @@ -1362,26 +1679,7 @@ pass_init_dump_file (struct opt_pass *pa
>       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;
> -         struct cgraph_node *node = cgraph_node (current_function_decl);
> -         dname = lang_hooks.decl_printable_name (current_function_decl, 2);
> -         aname = (IDENTIFIER_POINTER
> -                  (DECL_ASSEMBLER_NAME (current_function_decl)));
> -         if (L_IPO_COMP_MODE)
> -           fprintf (dump_file, "\n;; Function %s (%s)[%d:%d]", dname, aname,
> -                    FUNC_DECL_MODULE_ID (cfun), FUNC_DECL_FUNC_ID (cfun));
> -         else
> -           fprintf (dump_file, "\n;; Function %s (%s)", dname, aname);
> -         fprintf (dump_file, "%s\n\n",
> -            node->frequency == NODE_FREQUENCY_HOT
> -            ? " (hot)"
> -            : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
> -            ? " (unlikely executed)"
> -            : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
> -            ? " (executed once)"
> -            : "");
> -       }
> +        pass_dump_function_header (dump_file, current_function_decl, cfun);
>       return initializing_dump;
>     }
>   else
> @@ -1525,6 +1823,8 @@ execute_one_pass (struct opt_pass *pass)
>  {
>   bool initializing_dump;
>   unsigned int todo_after = 0;
> +  bool explicitly_enabled = false;
> +  bool explicitly_disabled = false;
>
>   bool gate_status;
>
> @@ -1535,11 +1835,15 @@ execute_one_pass (struct opt_pass *pass)
>   else
>     gcc_assert (cfun && current_function_decl);
>
> +  explicitly_enabled = is_pass_explicitly_enabled (pass, current_function_decl);
> +  explicitly_disabled = is_pass_explicitly_disabled (pass, current_function_decl);
> +
>   current_pass = pass;
>
>   /* Check whether gate check should be avoided.
>      User controls the value of the gate through the parameter "gate_status". */
>   gate_status = (pass->gate == NULL) ? true : pass->gate();
> +  gate_status = !explicitly_disabled && (gate_status || explicitly_enabled);
>
>   /* Override gate with plugin.  */
>   invoke_plugin_callbacks (PLUGIN_OVERRIDE_GATE, &gate_status);
>
> --
> This patch is available for review at http://codereview.appspot.com/4550056
>
Xinliang David Li May 18, 2011, 8:34 p.m. UTC | #4
Will fix the Changelog, and add documentation.

Thanks,

David



On Wed, May 18, 2011 at 1:26 PM, Richard Guenther
<richard.guenther@gmail.com> wrote:
> On Wed, May 18, 2011 at 8:37 PM, David Li <davidxl@google.com> wrote:
>>
>> In gcc, not all passes have user level control to turn it on/off, and
>> there is no way to flip on/off the pass for a subset of functions. I
>> implemented a generic option handling scheme in gcc to allow
>> disabling/enabling any gcc pass for any specified function(s).  The
>> new options will be very useful for things like performance
>> experiments and bug triaging (gcc has dbgcnt mechanism, but not all
>> passes have the counter).
>>
>> The option syntax is very similar to -fdump- options. The following
>> are some examples:
>>
>> -fdisable-tree-ccp1    <--- disable ccp1 for all functions
>> -fenable-tree-cunroll=1   <--- enable complete unroll for the function
>>                           whose cgraphnode uid is 1
>> -fdisable-rtl-gcse2=1:100,300,400:1000   <-- disable gcse2 for
>>                                           functions at the following
>>                                            ranges [1,1], [300,400], and [400,1000]
>> -fdisable-tree-einline --> disable early inlining for all callers
>> -fdisable-ipa-inline --> disable ipa inlininig
>>
>> In the gcc dumps, the uid numbers are displayed in the function header.
>>
>> The options are intended to be used internally by gcc developers.
>>
>> Ok for trunk ? (There is a little LIPO specific change that can be removed).
>>
>> David
>>
>> 2011-05-18  David Li  <davidxl@google.com>
>>
>>        * final.c (rest_of_clean_state): Call function header dumper.
>>        * opts-global.c (handle_common_deferred_options): Handle new options.
>>        * tree-cfg.c (gimple_dump_cfg): Call function header dumper.
>>        * passes.c (register_one_dump_file): Call register_pass_name.
>>        (pass_init_dump_file): Call function header dumper.
>>        (execute_one_pass): Check explicit enable/disable flag.
>>        (passr_hash): New function.
>>        (passr_eq):
>>        (register_pass_name):
>>        (get_pass_by_name):
>>        (pass_hash):
>>        (pass_eq):
>>        (enable_disable_pass):
>>        (is_pass_explicitly_enabled_or_disabled):
>>        (is_pass_explicitly_enabled):
>>        (is_pass_explicitly_disabled):
>
> Bogus changelog entry.
>
> New options need documenting in doc/invoke.texi.
>
> Richard.
>
>>
>> Index: tree-pass.h
>> ===================================================================
>> --- tree-pass.h (revision 173635)
>> +++ tree-pass.h (working copy)
>> @@ -644,4 +644,12 @@ extern bool first_pass_instance;
>>  /* Declare for plugins.  */
>>  extern void do_per_function_toporder (void (*) (void *), void *);
>>
>> +extern void enable_disable_pass (const char *, bool);
>> +extern bool is_pass_explicitly_disabled (struct opt_pass *, tree);
>> +extern bool is_pass_explicitly_enabled (struct opt_pass *, tree);
>> +extern void register_pass_name (struct opt_pass *, const char *);
>> +extern struct opt_pass *get_pass_by_name (const char *);
>> +struct function;
>> +extern void pass_dump_function_header (FILE *, tree, struct function *);
>> +
>>  #endif /* GCC_TREE_PASS_H */
>> Index: final.c
>> ===================================================================
>> --- final.c     (revision 173635)
>> +++ final.c     (working copy)
>> @@ -4456,19 +4456,7 @@ rest_of_clean_state (void)
>>        }
>>       else
>>        {
>> -         const char *aname;
>> -         struct cgraph_node *node = cgraph_node (current_function_decl);
>> -
>> -         aname = (IDENTIFIER_POINTER
>> -                  (DECL_ASSEMBLER_NAME (current_function_decl)));
>> -         fprintf (final_output, "\n;; Function (%s) %s\n\n", aname,
>> -            node->frequency == NODE_FREQUENCY_HOT
>> -            ? " (hot)"
>> -            : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
>> -            ? " (unlikely executed)"
>> -            : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
>> -            ? " (executed once)"
>> -            : "");
>> +         pass_dump_function_header (final_output, current_function_decl, cfun);
>>
>>          flag_dump_noaddr = flag_dump_unnumbered = 1;
>>          if (flag_compare_debug_opt || flag_compare_debug)
>> Index: common.opt
>> ===================================================================
>> --- common.opt  (revision 173635)
>> +++ common.opt  (working copy)
>> @@ -1018,6 +1018,14 @@ fdiagnostics-show-option
>>  Common Var(flag_diagnostics_show_option) Init(1)
>>  Amend appropriate diagnostic messages with the command line option that controls them
>>
>> +fdisable-
>> +Common Joined RejectNegative Var(common_deferred_options) Defer
>> +-fdisable-[tree|rtl|ipa]-<pass>=range1+range2 disables an optimization pass
>> +
>> +fenable-
>> +Common Joined RejectNegative Var(common_deferred_options) Defer
>> +-fenable-[tree|rtl|ipa]-<pass>=range1+range2 enables an optimization pass
>> +
>>  fdump-
>>  Common Joined RejectNegative Var(common_deferred_options) Defer
>>  -fdump-<type>  Dump various compiler internals to a file
>> Index: opts-global.c
>> ===================================================================
>> --- opts-global.c       (revision 173635)
>> +++ opts-global.c       (working copy)
>> @@ -411,6 +411,12 @@ handle_common_deferred_options (void)
>>            error ("unrecognized command line option %<-fdump-%s%>", opt->arg);
>>          break;
>>
>> +       case OPT_fenable_:
>> +       case OPT_fdisable_:
>> +         enable_disable_pass (opt->arg, (opt->opt_index == OPT_fenable_?
>> +                              true : false));
>> +          break;
>> +
>>        case OPT_ffixed_:
>>          /* Deferred.  */
>>          fix_register (opt->arg, 1, 1);
>> Index: tree-cfg.c
>> ===================================================================
>> --- tree-cfg.c  (revision 173636)
>> +++ tree-cfg.c  (working copy)
>> @@ -2090,11 +2090,7 @@ gimple_dump_cfg (FILE *file, int flags)
>>  {
>>   if (flags & TDF_DETAILS)
>>     {
>> -      const char *funcname
>> -       = lang_hooks.decl_printable_name (current_function_decl, 2);
>> -
>> -      fputc ('\n', file);
>> -      fprintf (file, ";; Function %s\n\n", funcname);
>> +      pass_dump_function_header (file, current_function_decl, cfun);
>>       fprintf (file, ";; \n%d basic blocks, %d edges, last basic block %d.\n\n",
>>               n_basic_blocks, n_edges, last_basic_block);
>>
>> Index: passes.c
>> ===================================================================
>> --- passes.c    (revision 173635)
>> +++ passes.c    (working copy)
>> @@ -382,7 +382,7 @@ void
>>  register_one_dump_file (struct opt_pass *pass)
>>  {
>>   char *dot_name, *flag_name, *glob_name;
>> -  const char *name, *prefix;
>> +  const char *name, *full_name, *prefix;
>>   char num[10];
>>   int flags, id;
>>
>> @@ -411,6 +411,8 @@ register_one_dump_file (struct opt_pass
>>   glob_name = concat (prefix, name, NULL);
>>   id = dump_register (dot_name, flag_name, glob_name, flags);
>>   set_pass_for_id (id, pass);
>> +  full_name = concat (prefix, pass->name, num, NULL);
>> +  register_pass_name (pass, full_name);
>>  }
>>
>>  /* Recursive worker function for register_dump_files.  */
>> @@ -454,6 +456,298 @@ register_dump_files (struct opt_pass *pa
>>   register_dump_files_1 (pass, properties);
>>  }
>>
>> +struct pass_registry
>> +{
>> +  const char* unique_name;
>> +  struct opt_pass *pass;
>> +};
>> +
>> +/* Pass registry hash function.  */
>> +
>> +static hashval_t
>> +passr_hash (const void *p)
>> +{
>> +  const struct pass_registry *const s = (const struct pass_registry *const) p;
>> +  return htab_hash_string (s->unique_name);
>> +}
>> +
>> +/* Hash equal function  */
>> +
>> +static int
>> +passr_eq (const void *p1, const void *p2)
>> +{
>> +  const struct pass_registry *const s1 = (const struct pass_registry *const) p1;
>> +  const struct pass_registry *const s2 = (const struct pass_registry *const) p2;
>> +
>> +  return !strcmp (s1->unique_name, s2->unique_name);
>> +}
>> +
>> +static htab_t pass_name_tab = NULL;
>> +
>> +/* Register PASS with NAME.  */
>> +
>> +void
>> +register_pass_name (struct opt_pass *pass, const char *name)
>> +{
>> +  struct pass_registry **slot;
>> +  struct pass_registry pr;
>> +
>> +  if (!pass_name_tab)
>> +    pass_name_tab = htab_create (10, passr_hash, passr_eq, NULL);
>> +
>> +  pr.unique_name = name;
>> +  slot = (struct pass_registry **) htab_find_slot (pass_name_tab, &pr, INSERT);
>> +  if (!*slot)
>> +    {
>> +      struct pass_registry *new_pr;
>> +
>> +      new_pr = XCNEW (struct pass_registry);
>> +      new_pr->unique_name = xstrdup (name);
>> +      new_pr->pass = pass;
>> +      *slot = new_pr;
>> +    }
>> +  else
>> +    gcc_assert ((*slot)->pass == pass);
>> +}
>> +
>> +/* Returns the pass with NAME.  */
>> +
>> +struct opt_pass *
>> +get_pass_by_name (const char *name)
>> +{
>> +  struct pass_registry **slot, pr;
>> +
>> +  gcc_assert (pass_name_tab);
>> +  pr.unique_name = name;
>> +  slot = (struct pass_registry **) htab_find_slot (pass_name_tab, &pr, NO_INSERT);
>> +
>> +  if (!slot || !*slot)
>> +    return NULL;
>> +
>> +  return (*slot)->pass;
>> +}
>> +
>> +
>> +/* Range [start, last].  */
>> +
>> +struct uid_range
>> +{
>> +  struct opt_pass *pass;
>> +  unsigned int start;
>> +  unsigned int last;
>> +  struct uid_range *next;
>> +};
>> +
>> +/* Hash function for pass structure.  */
>> +
>> +static hashval_t
>> +pass_hash (const void *s)
>> +{
>> +  const struct uid_range *const p = (const struct uid_range *const) s;
>> +  return p->pass->static_pass_number;
>> +}
>> +
>> +/* Pass equal function  */
>> +
>> +static int
>> +pass_eq (const void *s1, const void *s2)
>> +{
>> +  const struct uid_range *const p1 = (const struct uid_range *const) s1;
>> +  const struct uid_range *const p2 = (const struct uid_range *const) s2;
>> +  return p1->pass->static_pass_number == p2->pass->static_pass_number;
>> +}
>> +
>> +htab_t enabled_pass_uid_range_tab = NULL;
>> +htab_t disabled_pass_uid_range_tab = NULL;
>> +
>> +/* Parse option string for -fdisable- and -fenabler-
>> +   The syntax of the options:
>> +
>> +   -fenable-<pass_name>
>> +   -fdisable-<pass_name>
>> +
>> +   -fenable-<pass_name>=s1:e1,s2:e2,...
>> +   -fdisable-<pass_name>=s1:e1,s2:e2,...
>> +*/
>> +
>> +void
>> +enable_disable_pass (const char *arg, bool is_enable)
>> +{
>> +  struct opt_pass *pass;
>> +  htab_t the_tab;
>> +  char *range_str, *phase_name;
>> +  char *argstr = xstrdup (arg);
>> +
>> +  range_str = strchr (argstr,'=');
>> +  if (range_str)
>> +    {
>> +      *range_str = '\0';
>> +      range_str++;
>> +    }
>> +
>> +  phase_name = argstr;
>> +  if (!*phase_name)
>> +    {
>> +      error ("Unrecognized option %s", is_enable ? "-fenable" : "-fdisable");
>> +      free (argstr);
>> +      return;
>> +    }
>> +  pass = get_pass_by_name (phase_name);
>> +  if (!pass)
>> +    {
>> +      error ("Unknown pass %s specified in %s",
>> +            phase_name,
>> +            is_enable ? "-fenable" : "-fdisable");
>> +      free (argstr);
>> +      return;
>> +    }
>> +  if (is_enable)
>> +    {
>> +      if (!enabled_pass_uid_range_tab)
>> +       enabled_pass_uid_range_tab = htab_create (10, pass_hash, pass_eq, NULL);
>> +      the_tab = enabled_pass_uid_range_tab;
>> +    }
>> +  else
>> +    {
>> +      if (!disabled_pass_uid_range_tab)
>> +       disabled_pass_uid_range_tab = htab_create (10, pass_hash, pass_eq, NULL);
>> +      the_tab = disabled_pass_uid_range_tab;
>> +    }
>> +
>> +  if (!range_str)
>> +    {
>> +      struct uid_range **slot;
>> +      struct uid_range *new_range = XCNEW (struct uid_range);
>> +
>> +      new_range->pass = pass;
>> +      new_range->start = 0;
>> +      new_range->last = (unsigned)-1;
>> +
>> +      slot = (struct uid_range **) htab_find_slot (the_tab, new_range, INSERT);
>> +      new_range->next = *slot;
>> +      *slot = new_range;
>> +      inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
>> +              is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);
>> +    }
>> +  else
>> +    {
>> +      char *next_range = NULL;
>> +      char *one_range = range_str;
>> +      char *end_val = NULL;
>> +
>> +      do
>> +       {
>> +         struct uid_range **slot;
>> +         struct uid_range *new_range;
>> +         char *invalid = NULL;
>> +         long start;
>> +
>> +         next_range = strchr (one_range, ',');
>> +         if (next_range)
>> +           {
>> +             *next_range = '\0';
>> +             next_range++;
>> +           }
>> +
>> +         end_val = strchr (one_range, ':');
>> +         if (end_val)
>> +           {
>> +             *end_val = '\0';
>> +             end_val++;
>> +           }
>> +         start = strtol (one_range, &invalid, 10);
>> +         if (*invalid || start < 0)
>> +           {
>> +             error ("Invalid range %s in option %s",
>> +                    one_range,
>> +                    is_enable ? "-fenable" : "-fdisable");
>> +             free (argstr);
>> +             return;
>> +           }
>> +         if (!end_val)
>> +           {
>> +             new_range = XCNEW (struct uid_range);
>> +              new_range->pass = pass;
>> +             new_range->start = (unsigned) start;
>> +             new_range->last = (unsigned) start;
>> +           }
>> +         else
>> +           {
>> +             long last = strtol (end_val, &invalid, 10);
>> +             if (*invalid || last < start)
>> +               {
>> +                 error ("Invalid range %s in option %s",
>> +                        end_val,
>> +                        is_enable ? "-fenable" : "-fdisable");
>> +                 free (argstr);
>> +                 return;
>> +               }
>> +             new_range = XCNEW (struct uid_range);
>> +              new_range->pass = pass;
>> +             new_range->start = (unsigned) start;
>> +             new_range->last = (unsigned) last;
>> +           }
>> +         slot = (struct uid_range **) htab_find_slot (the_tab, new_range, INSERT);
>> +         new_range->next = *slot;
>> +         *slot = new_range;
>> +          inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
>> +                  is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);
>> +
>> +         one_range = next_range;
>> +       } while (next_range);
>> +    }
>> +
>> +  free (argstr);
>> +}
>> +
>> +/* Returns true if PASS is explicitly enabled/disabled for FUNC.  */
>> +
>> +static bool
>> +is_pass_explicitly_enabled_or_disabled (struct opt_pass *pass,
>> +                                       tree func, htab_t tab)
>> +{
>> +  struct uid_range **slot, *range, key;
>> +  int cgraph_uid;
>> +
>> +  if (!tab)
>> +    return false;
>> +
>> +  key.pass = pass;
>> +  slot = (struct uid_range **) htab_find_slot (tab, &key, NO_INSERT);
>> +  if (!slot || !*slot)
>> +    return false;
>> +
>> +  cgraph_uid = func ? cgraph_node (func)->uid : 0;
>> +
>> +  range = *slot;
>> +  while (range)
>> +    {
>> +      if ((unsigned) cgraph_uid >= range->start
>> +         && (unsigned) cgraph_uid <= range->last)
>> +       return true;
>> +      range = range->next;
>> +    }
>> +
>> +  return false;
>> +}
>> +
>> +/* Returns true if PASS is explicitly enabled for FUNC.  */
>> +
>> +bool
>> +is_pass_explicitly_enabled (struct opt_pass *pass, tree func)
>> +{
>> +  return is_pass_explicitly_enabled_or_disabled (pass, func, enabled_pass_uid_range_tab);
>> +}
>> +
>> +/* Returns true if PASS is explicitly disabled for FUNC.  */
>> +
>> +bool
>> +is_pass_explicitly_disabled (struct opt_pass *pass, tree func)
>> +{
>> +  return is_pass_explicitly_enabled_or_disabled (pass, func, disabled_pass_uid_range_tab);
>> +}
>> +
>> +
>>  /* Look at the static_pass_number and duplicate the pass
>>    if it is already added to a list. */
>>
>> @@ -1349,6 +1643,29 @@ verify_curr_properties (void *data)
>>  }
>>  #endif
>>
>> +void
>> +pass_dump_function_header (FILE *dump_file, tree fdecl, struct function *fun)
>> +{
>> +  const char *dname, *aname;
>> +  struct cgraph_node *node = cgraph_node (fdecl);
>> +  dname = lang_hooks.decl_printable_name (fdecl, 2);
>> +  aname = (IDENTIFIER_POINTER
>> +          (DECL_ASSEMBLER_NAME (fdecl)));
>> +  if (L_IPO_COMP_MODE)
>> +    fprintf (dump_file, "\n;; Function %s (%s)[%d:%d][uid=%d]", dname, aname,
>> +            FUNC_DECL_MODULE_ID (fun), FUNC_DECL_FUNC_ID (fun), node->uid);
>> +  else
>> +    fprintf (dump_file, "\n;; Function %s (%s)[uid=%d]", dname, aname, node->uid);
>> +  fprintf (dump_file, "%s\n\n",
>> +           node->frequency == NODE_FREQUENCY_HOT
>> +           ? " (hot)"
>> +           : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
>> +           ? " (unlikely executed)"
>> +           : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
>> +           ? " (executed once)"
>> +           : "");
>> +}
>> +
>>  /* Initialize pass dump file.  */
>>  /* This is non-static so that the plugins can use it.  */
>>
>> @@ -1362,26 +1679,7 @@ pass_init_dump_file (struct opt_pass *pa
>>       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;
>> -         struct cgraph_node *node = cgraph_node (current_function_decl);
>> -         dname = lang_hooks.decl_printable_name (current_function_decl, 2);
>> -         aname = (IDENTIFIER_POINTER
>> -                  (DECL_ASSEMBLER_NAME (current_function_decl)));
>> -         if (L_IPO_COMP_MODE)
>> -           fprintf (dump_file, "\n;; Function %s (%s)[%d:%d]", dname, aname,
>> -                    FUNC_DECL_MODULE_ID (cfun), FUNC_DECL_FUNC_ID (cfun));
>> -         else
>> -           fprintf (dump_file, "\n;; Function %s (%s)", dname, aname);
>> -         fprintf (dump_file, "%s\n\n",
>> -            node->frequency == NODE_FREQUENCY_HOT
>> -            ? " (hot)"
>> -            : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
>> -            ? " (unlikely executed)"
>> -            : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
>> -            ? " (executed once)"
>> -            : "");
>> -       }
>> +        pass_dump_function_header (dump_file, current_function_decl, cfun);
>>       return initializing_dump;
>>     }
>>   else
>> @@ -1525,6 +1823,8 @@ execute_one_pass (struct opt_pass *pass)
>>  {
>>   bool initializing_dump;
>>   unsigned int todo_after = 0;
>> +  bool explicitly_enabled = false;
>> +  bool explicitly_disabled = false;
>>
>>   bool gate_status;
>>
>> @@ -1535,11 +1835,15 @@ execute_one_pass (struct opt_pass *pass)
>>   else
>>     gcc_assert (cfun && current_function_decl);
>>
>> +  explicitly_enabled = is_pass_explicitly_enabled (pass, current_function_decl);
>> +  explicitly_disabled = is_pass_explicitly_disabled (pass, current_function_decl);
>> +
>>   current_pass = pass;
>>
>>   /* Check whether gate check should be avoided.
>>      User controls the value of the gate through the parameter "gate_status". */
>>   gate_status = (pass->gate == NULL) ? true : pass->gate();
>> +  gate_status = !explicitly_disabled && (gate_status || explicitly_enabled);
>>
>>   /* Override gate with plugin.  */
>>   invoke_plugin_callbacks (PLUGIN_OVERRIDE_GATE, &gate_status);
>>
>> --
>> This patch is available for review at http://codereview.appspot.com/4550056
>>
>
Xinliang David Li May 18, 2011, 10:38 p.m. UTC | #5
The attached is the revised patch. Bootstrap and regression tested in
trunk on x86-64/linux.

Ok for checkin?

Thanks,

David

On Wed, May 18, 2011 at 1:34 PM, Xinliang David Li <davidxl@google.com> wrote:
> Will fix the Changelog, and add documentation.
>
> Thanks,
>
> David
>
>
>
> On Wed, May 18, 2011 at 1:26 PM, Richard Guenther
> <richard.guenther@gmail.com> wrote:
>> On Wed, May 18, 2011 at 8:37 PM, David Li <davidxl@google.com> wrote:
>>>
>>> In gcc, not all passes have user level control to turn it on/off, and
>>> there is no way to flip on/off the pass for a subset of functions. I
>>> implemented a generic option handling scheme in gcc to allow
>>> disabling/enabling any gcc pass for any specified function(s).  The
>>> new options will be very useful for things like performance
>>> experiments and bug triaging (gcc has dbgcnt mechanism, but not all
>>> passes have the counter).
>>>
>>> The option syntax is very similar to -fdump- options. The following
>>> are some examples:
>>>
>>> -fdisable-tree-ccp1    <--- disable ccp1 for all functions
>>> -fenable-tree-cunroll=1   <--- enable complete unroll for the function
>>>                           whose cgraphnode uid is 1
>>> -fdisable-rtl-gcse2=1:100,300,400:1000   <-- disable gcse2 for
>>>                                           functions at the following
>>>                                            ranges [1,1], [300,400], and [400,1000]
>>> -fdisable-tree-einline --> disable early inlining for all callers
>>> -fdisable-ipa-inline --> disable ipa inlininig
>>>
>>> In the gcc dumps, the uid numbers are displayed in the function header.
>>>
>>> The options are intended to be used internally by gcc developers.
>>>
>>> Ok for trunk ? (There is a little LIPO specific change that can be removed).
>>>
>>> David
>>>
>>> 2011-05-18  David Li  <davidxl@google.com>
>>>
>>>        * final.c (rest_of_clean_state): Call function header dumper.
>>>        * opts-global.c (handle_common_deferred_options): Handle new options.
>>>        * tree-cfg.c (gimple_dump_cfg): Call function header dumper.
>>>        * passes.c (register_one_dump_file): Call register_pass_name.
>>>        (pass_init_dump_file): Call function header dumper.
>>>        (execute_one_pass): Check explicit enable/disable flag.
>>>        (passr_hash): New function.
>>>        (passr_eq):
>>>        (register_pass_name):
>>>        (get_pass_by_name):
>>>        (pass_hash):
>>>        (pass_eq):
>>>        (enable_disable_pass):
>>>        (is_pass_explicitly_enabled_or_disabled):
>>>        (is_pass_explicitly_enabled):
>>>        (is_pass_explicitly_disabled):
>>
>> Bogus changelog entry.
>>
>> New options need documenting in doc/invoke.texi.
>>
>> Richard.
>>
>>>
>>> Index: tree-pass.h
>>> ===================================================================
>>> --- tree-pass.h (revision 173635)
>>> +++ tree-pass.h (working copy)
>>> @@ -644,4 +644,12 @@ extern bool first_pass_instance;
>>>  /* Declare for plugins.  */
>>>  extern void do_per_function_toporder (void (*) (void *), void *);
>>>
>>> +extern void enable_disable_pass (const char *, bool);
>>> +extern bool is_pass_explicitly_disabled (struct opt_pass *, tree);
>>> +extern bool is_pass_explicitly_enabled (struct opt_pass *, tree);
>>> +extern void register_pass_name (struct opt_pass *, const char *);
>>> +extern struct opt_pass *get_pass_by_name (const char *);
>>> +struct function;
>>> +extern void pass_dump_function_header (FILE *, tree, struct function *);
>>> +
>>>  #endif /* GCC_TREE_PASS_H */
>>> Index: final.c
>>> ===================================================================
>>> --- final.c     (revision 173635)
>>> +++ final.c     (working copy)
>>> @@ -4456,19 +4456,7 @@ rest_of_clean_state (void)
>>>        }
>>>       else
>>>        {
>>> -         const char *aname;
>>> -         struct cgraph_node *node = cgraph_node (current_function_decl);
>>> -
>>> -         aname = (IDENTIFIER_POINTER
>>> -                  (DECL_ASSEMBLER_NAME (current_function_decl)));
>>> -         fprintf (final_output, "\n;; Function (%s) %s\n\n", aname,
>>> -            node->frequency == NODE_FREQUENCY_HOT
>>> -            ? " (hot)"
>>> -            : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
>>> -            ? " (unlikely executed)"
>>> -            : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
>>> -            ? " (executed once)"
>>> -            : "");
>>> +         pass_dump_function_header (final_output, current_function_decl, cfun);
>>>
>>>          flag_dump_noaddr = flag_dump_unnumbered = 1;
>>>          if (flag_compare_debug_opt || flag_compare_debug)
>>> Index: common.opt
>>> ===================================================================
>>> --- common.opt  (revision 173635)
>>> +++ common.opt  (working copy)
>>> @@ -1018,6 +1018,14 @@ fdiagnostics-show-option
>>>  Common Var(flag_diagnostics_show_option) Init(1)
>>>  Amend appropriate diagnostic messages with the command line option that controls them
>>>
>>> +fdisable-
>>> +Common Joined RejectNegative Var(common_deferred_options) Defer
>>> +-fdisable-[tree|rtl|ipa]-<pass>=range1+range2 disables an optimization pass
>>> +
>>> +fenable-
>>> +Common Joined RejectNegative Var(common_deferred_options) Defer
>>> +-fenable-[tree|rtl|ipa]-<pass>=range1+range2 enables an optimization pass
>>> +
>>>  fdump-
>>>  Common Joined RejectNegative Var(common_deferred_options) Defer
>>>  -fdump-<type>  Dump various compiler internals to a file
>>> Index: opts-global.c
>>> ===================================================================
>>> --- opts-global.c       (revision 173635)
>>> +++ opts-global.c       (working copy)
>>> @@ -411,6 +411,12 @@ handle_common_deferred_options (void)
>>>            error ("unrecognized command line option %<-fdump-%s%>", opt->arg);
>>>          break;
>>>
>>> +       case OPT_fenable_:
>>> +       case OPT_fdisable_:
>>> +         enable_disable_pass (opt->arg, (opt->opt_index == OPT_fenable_?
>>> +                              true : false));
>>> +          break;
>>> +
>>>        case OPT_ffixed_:
>>>          /* Deferred.  */
>>>          fix_register (opt->arg, 1, 1);
>>> Index: tree-cfg.c
>>> ===================================================================
>>> --- tree-cfg.c  (revision 173636)
>>> +++ tree-cfg.c  (working copy)
>>> @@ -2090,11 +2090,7 @@ gimple_dump_cfg (FILE *file, int flags)
>>>  {
>>>   if (flags & TDF_DETAILS)
>>>     {
>>> -      const char *funcname
>>> -       = lang_hooks.decl_printable_name (current_function_decl, 2);
>>> -
>>> -      fputc ('\n', file);
>>> -      fprintf (file, ";; Function %s\n\n", funcname);
>>> +      pass_dump_function_header (file, current_function_decl, cfun);
>>>       fprintf (file, ";; \n%d basic blocks, %d edges, last basic block %d.\n\n",
>>>               n_basic_blocks, n_edges, last_basic_block);
>>>
>>> Index: passes.c
>>> ===================================================================
>>> --- passes.c    (revision 173635)
>>> +++ passes.c    (working copy)
>>> @@ -382,7 +382,7 @@ void
>>>  register_one_dump_file (struct opt_pass *pass)
>>>  {
>>>   char *dot_name, *flag_name, *glob_name;
>>> -  const char *name, *prefix;
>>> +  const char *name, *full_name, *prefix;
>>>   char num[10];
>>>   int flags, id;
>>>
>>> @@ -411,6 +411,8 @@ register_one_dump_file (struct opt_pass
>>>   glob_name = concat (prefix, name, NULL);
>>>   id = dump_register (dot_name, flag_name, glob_name, flags);
>>>   set_pass_for_id (id, pass);
>>> +  full_name = concat (prefix, pass->name, num, NULL);
>>> +  register_pass_name (pass, full_name);
>>>  }
>>>
>>>  /* Recursive worker function for register_dump_files.  */
>>> @@ -454,6 +456,298 @@ register_dump_files (struct opt_pass *pa
>>>   register_dump_files_1 (pass, properties);
>>>  }
>>>
>>> +struct pass_registry
>>> +{
>>> +  const char* unique_name;
>>> +  struct opt_pass *pass;
>>> +};
>>> +
>>> +/* Pass registry hash function.  */
>>> +
>>> +static hashval_t
>>> +passr_hash (const void *p)
>>> +{
>>> +  const struct pass_registry *const s = (const struct pass_registry *const) p;
>>> +  return htab_hash_string (s->unique_name);
>>> +}
>>> +
>>> +/* Hash equal function  */
>>> +
>>> +static int
>>> +passr_eq (const void *p1, const void *p2)
>>> +{
>>> +  const struct pass_registry *const s1 = (const struct pass_registry *const) p1;
>>> +  const struct pass_registry *const s2 = (const struct pass_registry *const) p2;
>>> +
>>> +  return !strcmp (s1->unique_name, s2->unique_name);
>>> +}
>>> +
>>> +static htab_t pass_name_tab = NULL;
>>> +
>>> +/* Register PASS with NAME.  */
>>> +
>>> +void
>>> +register_pass_name (struct opt_pass *pass, const char *name)
>>> +{
>>> +  struct pass_registry **slot;
>>> +  struct pass_registry pr;
>>> +
>>> +  if (!pass_name_tab)
>>> +    pass_name_tab = htab_create (10, passr_hash, passr_eq, NULL);
>>> +
>>> +  pr.unique_name = name;
>>> +  slot = (struct pass_registry **) htab_find_slot (pass_name_tab, &pr, INSERT);
>>> +  if (!*slot)
>>> +    {
>>> +      struct pass_registry *new_pr;
>>> +
>>> +      new_pr = XCNEW (struct pass_registry);
>>> +      new_pr->unique_name = xstrdup (name);
>>> +      new_pr->pass = pass;
>>> +      *slot = new_pr;
>>> +    }
>>> +  else
>>> +    gcc_assert ((*slot)->pass == pass);
>>> +}
>>> +
>>> +/* Returns the pass with NAME.  */
>>> +
>>> +struct opt_pass *
>>> +get_pass_by_name (const char *name)
>>> +{
>>> +  struct pass_registry **slot, pr;
>>> +
>>> +  gcc_assert (pass_name_tab);
>>> +  pr.unique_name = name;
>>> +  slot = (struct pass_registry **) htab_find_slot (pass_name_tab, &pr, NO_INSERT);
>>> +
>>> +  if (!slot || !*slot)
>>> +    return NULL;
>>> +
>>> +  return (*slot)->pass;
>>> +}
>>> +
>>> +
>>> +/* Range [start, last].  */
>>> +
>>> +struct uid_range
>>> +{
>>> +  struct opt_pass *pass;
>>> +  unsigned int start;
>>> +  unsigned int last;
>>> +  struct uid_range *next;
>>> +};
>>> +
>>> +/* Hash function for pass structure.  */
>>> +
>>> +static hashval_t
>>> +pass_hash (const void *s)
>>> +{
>>> +  const struct uid_range *const p = (const struct uid_range *const) s;
>>> +  return p->pass->static_pass_number;
>>> +}
>>> +
>>> +/* Pass equal function  */
>>> +
>>> +static int
>>> +pass_eq (const void *s1, const void *s2)
>>> +{
>>> +  const struct uid_range *const p1 = (const struct uid_range *const) s1;
>>> +  const struct uid_range *const p2 = (const struct uid_range *const) s2;
>>> +  return p1->pass->static_pass_number == p2->pass->static_pass_number;
>>> +}
>>> +
>>> +htab_t enabled_pass_uid_range_tab = NULL;
>>> +htab_t disabled_pass_uid_range_tab = NULL;
>>> +
>>> +/* Parse option string for -fdisable- and -fenabler-
>>> +   The syntax of the options:
>>> +
>>> +   -fenable-<pass_name>
>>> +   -fdisable-<pass_name>
>>> +
>>> +   -fenable-<pass_name>=s1:e1,s2:e2,...
>>> +   -fdisable-<pass_name>=s1:e1,s2:e2,...
>>> +*/
>>> +
>>> +void
>>> +enable_disable_pass (const char *arg, bool is_enable)
>>> +{
>>> +  struct opt_pass *pass;
>>> +  htab_t the_tab;
>>> +  char *range_str, *phase_name;
>>> +  char *argstr = xstrdup (arg);
>>> +
>>> +  range_str = strchr (argstr,'=');
>>> +  if (range_str)
>>> +    {
>>> +      *range_str = '\0';
>>> +      range_str++;
>>> +    }
>>> +
>>> +  phase_name = argstr;
>>> +  if (!*phase_name)
>>> +    {
>>> +      error ("Unrecognized option %s", is_enable ? "-fenable" : "-fdisable");
>>> +      free (argstr);
>>> +      return;
>>> +    }
>>> +  pass = get_pass_by_name (phase_name);
>>> +  if (!pass)
>>> +    {
>>> +      error ("Unknown pass %s specified in %s",
>>> +            phase_name,
>>> +            is_enable ? "-fenable" : "-fdisable");
>>> +      free (argstr);
>>> +      return;
>>> +    }
>>> +  if (is_enable)
>>> +    {
>>> +      if (!enabled_pass_uid_range_tab)
>>> +       enabled_pass_uid_range_tab = htab_create (10, pass_hash, pass_eq, NULL);
>>> +      the_tab = enabled_pass_uid_range_tab;
>>> +    }
>>> +  else
>>> +    {
>>> +      if (!disabled_pass_uid_range_tab)
>>> +       disabled_pass_uid_range_tab = htab_create (10, pass_hash, pass_eq, NULL);
>>> +      the_tab = disabled_pass_uid_range_tab;
>>> +    }
>>> +
>>> +  if (!range_str)
>>> +    {
>>> +      struct uid_range **slot;
>>> +      struct uid_range *new_range = XCNEW (struct uid_range);
>>> +
>>> +      new_range->pass = pass;
>>> +      new_range->start = 0;
>>> +      new_range->last = (unsigned)-1;
>>> +
>>> +      slot = (struct uid_range **) htab_find_slot (the_tab, new_range, INSERT);
>>> +      new_range->next = *slot;
>>> +      *slot = new_range;
>>> +      inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
>>> +              is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);
>>> +    }
>>> +  else
>>> +    {
>>> +      char *next_range = NULL;
>>> +      char *one_range = range_str;
>>> +      char *end_val = NULL;
>>> +
>>> +      do
>>> +       {
>>> +         struct uid_range **slot;
>>> +         struct uid_range *new_range;
>>> +         char *invalid = NULL;
>>> +         long start;
>>> +
>>> +         next_range = strchr (one_range, ',');
>>> +         if (next_range)
>>> +           {
>>> +             *next_range = '\0';
>>> +             next_range++;
>>> +           }
>>> +
>>> +         end_val = strchr (one_range, ':');
>>> +         if (end_val)
>>> +           {
>>> +             *end_val = '\0';
>>> +             end_val++;
>>> +           }
>>> +         start = strtol (one_range, &invalid, 10);
>>> +         if (*invalid || start < 0)
>>> +           {
>>> +             error ("Invalid range %s in option %s",
>>> +                    one_range,
>>> +                    is_enable ? "-fenable" : "-fdisable");
>>> +             free (argstr);
>>> +             return;
>>> +           }
>>> +         if (!end_val)
>>> +           {
>>> +             new_range = XCNEW (struct uid_range);
>>> +              new_range->pass = pass;
>>> +             new_range->start = (unsigned) start;
>>> +             new_range->last = (unsigned) start;
>>> +           }
>>> +         else
>>> +           {
>>> +             long last = strtol (end_val, &invalid, 10);
>>> +             if (*invalid || last < start)
>>> +               {
>>> +                 error ("Invalid range %s in option %s",
>>> +                        end_val,
>>> +                        is_enable ? "-fenable" : "-fdisable");
>>> +                 free (argstr);
>>> +                 return;
>>> +               }
>>> +             new_range = XCNEW (struct uid_range);
>>> +              new_range->pass = pass;
>>> +             new_range->start = (unsigned) start;
>>> +             new_range->last = (unsigned) last;
>>> +           }
>>> +         slot = (struct uid_range **) htab_find_slot (the_tab, new_range, INSERT);
>>> +         new_range->next = *slot;
>>> +         *slot = new_range;
>>> +          inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
>>> +                  is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);
>>> +
>>> +         one_range = next_range;
>>> +       } while (next_range);
>>> +    }
>>> +
>>> +  free (argstr);
>>> +}
>>> +
>>> +/* Returns true if PASS is explicitly enabled/disabled for FUNC.  */
>>> +
>>> +static bool
>>> +is_pass_explicitly_enabled_or_disabled (struct opt_pass *pass,
>>> +                                       tree func, htab_t tab)
>>> +{
>>> +  struct uid_range **slot, *range, key;
>>> +  int cgraph_uid;
>>> +
>>> +  if (!tab)
>>> +    return false;
>>> +
>>> +  key.pass = pass;
>>> +  slot = (struct uid_range **) htab_find_slot (tab, &key, NO_INSERT);
>>> +  if (!slot || !*slot)
>>> +    return false;
>>> +
>>> +  cgraph_uid = func ? cgraph_node (func)->uid : 0;
>>> +
>>> +  range = *slot;
>>> +  while (range)
>>> +    {
>>> +      if ((unsigned) cgraph_uid >= range->start
>>> +         && (unsigned) cgraph_uid <= range->last)
>>> +       return true;
>>> +      range = range->next;
>>> +    }
>>> +
>>> +  return false;
>>> +}
>>> +
>>> +/* Returns true if PASS is explicitly enabled for FUNC.  */
>>> +
>>> +bool
>>> +is_pass_explicitly_enabled (struct opt_pass *pass, tree func)
>>> +{
>>> +  return is_pass_explicitly_enabled_or_disabled (pass, func, enabled_pass_uid_range_tab);
>>> +}
>>> +
>>> +/* Returns true if PASS is explicitly disabled for FUNC.  */
>>> +
>>> +bool
>>> +is_pass_explicitly_disabled (struct opt_pass *pass, tree func)
>>> +{
>>> +  return is_pass_explicitly_enabled_or_disabled (pass, func, disabled_pass_uid_range_tab);
>>> +}
>>> +
>>> +
>>>  /* Look at the static_pass_number and duplicate the pass
>>>    if it is already added to a list. */
>>>
>>> @@ -1349,6 +1643,29 @@ verify_curr_properties (void *data)
>>>  }
>>>  #endif
>>>
>>> +void
>>> +pass_dump_function_header (FILE *dump_file, tree fdecl, struct function *fun)
>>> +{
>>> +  const char *dname, *aname;
>>> +  struct cgraph_node *node = cgraph_node (fdecl);
>>> +  dname = lang_hooks.decl_printable_name (fdecl, 2);
>>> +  aname = (IDENTIFIER_POINTER
>>> +          (DECL_ASSEMBLER_NAME (fdecl)));
>>> +  if (L_IPO_COMP_MODE)
>>> +    fprintf (dump_file, "\n;; Function %s (%s)[%d:%d][uid=%d]", dname, aname,
>>> +            FUNC_DECL_MODULE_ID (fun), FUNC_DECL_FUNC_ID (fun), node->uid);
>>> +  else
>>> +    fprintf (dump_file, "\n;; Function %s (%s)[uid=%d]", dname, aname, node->uid);
>>> +  fprintf (dump_file, "%s\n\n",
>>> +           node->frequency == NODE_FREQUENCY_HOT
>>> +           ? " (hot)"
>>> +           : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
>>> +           ? " (unlikely executed)"
>>> +           : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
>>> +           ? " (executed once)"
>>> +           : "");
>>> +}
>>> +
>>>  /* Initialize pass dump file.  */
>>>  /* This is non-static so that the plugins can use it.  */
>>>
>>> @@ -1362,26 +1679,7 @@ pass_init_dump_file (struct opt_pass *pa
>>>       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;
>>> -         struct cgraph_node *node = cgraph_node (current_function_decl);
>>> -         dname = lang_hooks.decl_printable_name (current_function_decl, 2);
>>> -         aname = (IDENTIFIER_POINTER
>>> -                  (DECL_ASSEMBLER_NAME (current_function_decl)));
>>> -         if (L_IPO_COMP_MODE)
>>> -           fprintf (dump_file, "\n;; Function %s (%s)[%d:%d]", dname, aname,
>>> -                    FUNC_DECL_MODULE_ID (cfun), FUNC_DECL_FUNC_ID (cfun));
>>> -         else
>>> -           fprintf (dump_file, "\n;; Function %s (%s)", dname, aname);
>>> -         fprintf (dump_file, "%s\n\n",
>>> -            node->frequency == NODE_FREQUENCY_HOT
>>> -            ? " (hot)"
>>> -            : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
>>> -            ? " (unlikely executed)"
>>> -            : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
>>> -            ? " (executed once)"
>>> -            : "");
>>> -       }
>>> +        pass_dump_function_header (dump_file, current_function_decl, cfun);
>>>       return initializing_dump;
>>>     }
>>>   else
>>> @@ -1525,6 +1823,8 @@ execute_one_pass (struct opt_pass *pass)
>>>  {
>>>   bool initializing_dump;
>>>   unsigned int todo_after = 0;
>>> +  bool explicitly_enabled = false;
>>> +  bool explicitly_disabled = false;
>>>
>>>   bool gate_status;
>>>
>>> @@ -1535,11 +1835,15 @@ execute_one_pass (struct opt_pass *pass)
>>>   else
>>>     gcc_assert (cfun && current_function_decl);
>>>
>>> +  explicitly_enabled = is_pass_explicitly_enabled (pass, current_function_decl);
>>> +  explicitly_disabled = is_pass_explicitly_disabled (pass, current_function_decl);
>>> +
>>>   current_pass = pass;
>>>
>>>   /* Check whether gate check should be avoided.
>>>      User controls the value of the gate through the parameter "gate_status". */
>>>   gate_status = (pass->gate == NULL) ? true : pass->gate();
>>> +  gate_status = !explicitly_disabled && (gate_status || explicitly_enabled);
>>>
>>>   /* Override gate with plugin.  */
>>>   invoke_plugin_callbacks (PLUGIN_OVERRIDE_GATE, &gate_status);
>>>
>>> --
>>> This patch is available for review at http://codereview.appspot.com/4550056
>>>
>>
>
Andi Kleen May 19, 2011, 6:04 p.m. UTC | #6
davidxl@google.com (David Li) writes:

> -fdisable-tree-ccp1    <--- disable ccp1 for all functions
> -fenable-tree-cunroll=1   <--- enable complete unroll for the function
>                            whose cgraphnode uid is 1
> -fdisable-rtl-gcse2=1:100,300,400:1000   <-- disable gcse2 for
>                                            functions at the following
>                                             ranges [1,1], [300,400],
> and [400,1000]

How are the ranges defined? I doubt numbers are a good interface here
to specify functions.

This would be better done with #pragmas? 

-Andi
Xinliang David Li May 19, 2011, 6:10 p.m. UTC | #7
On Thu, May 19, 2011 at 11:04 AM, Andi Kleen <andi@firstfloor.org> wrote:
> davidxl@google.com (David Li) writes:
>
>> -fdisable-tree-ccp1    <--- disable ccp1 for all functions
>> -fenable-tree-cunroll=1   <--- enable complete unroll for the function
>>                            whose cgraphnode uid is 1
>> -fdisable-rtl-gcse2=1:100,300,400:1000   <-- disable gcse2 for
>>                                            functions at the following
>>                                             ranges [1,1], [300,400],
>> and [400,1000]
>
> How are the ranges defined? I doubt numbers are a good interface here
> to specify functions.

The numbers are cgraph uids for the functions. The form that takes the
range is mainly for developers who use scripts to auto search (bug
triaging and optimization space traverse).

>
> This would be better done with #pragmas?

This is not good for automation. However, I do plan (later after this
patch is in) to add another form of the option which takes a comma
separated list of assembler names --- this form will be quite useful
to workaround compiler bugs temporarily in the make file.

David

>
> -Andi
>
>
>
> --
> ak@linux.intel.com -- Speaking for myself only
>
Andi Kleen May 19, 2011, 6:17 p.m. UTC | #8
On Thu, May 19, 2011 at 11:10:24AM -0700, Xinliang David Li wrote:
> On Thu, May 19, 2011 at 11:04 AM, Andi Kleen <andi@firstfloor.org> wrote:
> > davidxl@google.com (David Li) writes:
> >
> >> -fdisable-tree-ccp1    <--- disable ccp1 for all functions
> >> -fenable-tree-cunroll=1   <--- enable complete unroll for the function
> >>                            whose cgraphnode uid is 1
> >> -fdisable-rtl-gcse2=1:100,300,400:1000   <-- disable gcse2 for
> >>                                            functions at the following
> >>                                             ranges [1,1], [300,400],
> >> and [400,1000]
> >
> > How are the ranges defined? I doubt numbers are a good interface here
> > to specify functions.
> 
> The numbers are cgraph uids for the functions. The form that takes the
> range is mainly for developers who use scripts to auto search (bug
> triaging and optimization space traverse).

How about function names?


> > This would be better done with #pragmas?
> 
> This is not good for automation. However, I do plan (later after this

Why not? It should be easy enough to write a script to add such
pragmas given a dwarf2 symbol->file:line dump

I think pragmas would be a lot more useful for non compiler developers.

-Andi
Xinliang David Li May 19, 2011, 6:50 p.m. UTC | #9
On Thu, May 19, 2011 at 11:17 AM, Andi Kleen <andi@firstfloor.org> wrote:
> On Thu, May 19, 2011 at 11:10:24AM -0700, Xinliang David Li wrote:
>> On Thu, May 19, 2011 at 11:04 AM, Andi Kleen <andi@firstfloor.org> wrote:
>> > davidxl@google.com (David Li) writes:
>> >
>> >> -fdisable-tree-ccp1    <--- disable ccp1 for all functions
>> >> -fenable-tree-cunroll=1   <--- enable complete unroll for the function
>> >>                            whose cgraphnode uid is 1
>> >> -fdisable-rtl-gcse2=1:100,300,400:1000   <-- disable gcse2 for
>> >>                                            functions at the following
>> >>                                             ranges [1,1], [300,400],
>> >> and [400,1000]
>> >
>> > How are the ranges defined? I doubt numbers are a good interface here
>> > to specify functions.
>>
>> The numbers are cgraph uids for the functions. The form that takes the
>> range is mainly for developers who use scripts to auto search (bug
>> triaging and optimization space traverse).
>
> How about function names?

Not so easy for things like binary search.

>
>
>> > This would be better done with #pragmas?
>>
>> This is not good for automation. However, I do plan (later after this
>
> Why not? It should be easy enough to write a script to add such
> pragmas given a dwarf2 symbol->file:line dump

This may require changes many many sources files as compared to a
simple command line tweak -- for most of the cases, you don't even
need to know the id ranges, and can be blindly set to a large initial
value.

>
> I think pragmas would be a lot more useful for non compiler developers.
>

As compared with the -fdisable-tree-xxx=func1,func2?

The semantics of the pragma is also in question -- does it apply to
all inline instances of the function with pragma or just the emitted
instance?

(The pragma scheme can be implemented independently if it is considered useful).

Thanks,

David


> -Andi
>
Xinliang David Li May 20, 2011, 4:06 p.m. UTC | #10
Ok to check in this one?

Thanks,

David

On Wed, May 18, 2011 at 12:30 PM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> On Wed, 18 May 2011, David Li wrote:
>
>> +      error ("Unrecognized option %s", is_enable ? "-fenable" : "-fdisable");
>
>> +      error ("Unknown pass %s specified in %s",
>> +          phase_name,
>> +          is_enable ? "-fenable" : "-fdisable");
>
> Follow GNU Coding Standards for diagnostics (start with lowercase letter).
>
>> +      inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
>> +              is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);
>
> Use separate calls to inform for the enable and disable cases, so that
> full sentences can be extracted for translation.
>
>> +           error ("Invalid range %s in option %s",
>> +                  one_range,
>> +                  is_enable ? "-fenable" : "-fdisable");
>
> GNU Coding Standards.
>
>> +               error ("Invalid range %s in option %s",
>
> Likewise.
>
>> +          inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
>> +                  is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);
>
> Again needs GCS and i18n fixes.
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>
Xinliang David Li May 22, 2011, 11:17 p.m. UTC | #11
Ping.

David


On Fri, May 20, 2011 at 9:06 AM, Xinliang David Li <davidxl@google.com> wrote:
> Ok to check in this one?
>
> Thanks,
>
> David
>
> On Wed, May 18, 2011 at 12:30 PM, Joseph S. Myers
> <joseph@codesourcery.com> wrote:
>> On Wed, 18 May 2011, David Li wrote:
>>
>>> +      error ("Unrecognized option %s", is_enable ? "-fenable" : "-fdisable");
>>
>>> +      error ("Unknown pass %s specified in %s",
>>> +          phase_name,
>>> +          is_enable ? "-fenable" : "-fdisable");
>>
>> Follow GNU Coding Standards for diagnostics (start with lowercase letter).
>>
>>> +      inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
>>> +              is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);
>>
>> Use separate calls to inform for the enable and disable cases, so that
>> full sentences can be extracted for translation.
>>
>>> +           error ("Invalid range %s in option %s",
>>> +                  one_range,
>>> +                  is_enable ? "-fenable" : "-fdisable");
>>
>> GNU Coding Standards.
>>
>>> +               error ("Invalid range %s in option %s",
>>
>> Likewise.
>>
>>> +          inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
>>> +                  is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);
>>
>> Again needs GCS and i18n fixes.
>>
>> --
>> Joseph S. Myers
>> joseph@codesourcery.com
>>
>
Xinliang David Li May 25, 2011, 4:18 p.m. UTC | #12
Ping. The link to the message:

http://gcc.gnu.org/ml/gcc-patches/2011-05/msg01303.html

Thanks,

David

On Sun, May 22, 2011 at 4:17 PM, Xinliang David Li <davidxl@google.com> wrote:
> Ping.
>
> David
>
>
> On Fri, May 20, 2011 at 9:06 AM, Xinliang David Li <davidxl@google.com> wrote:
>> Ok to check in this one?
>>
>> Thanks,
>>
>> David
>>
>> On Wed, May 18, 2011 at 12:30 PM, Joseph S. Myers
>> <joseph@codesourcery.com> wrote:
>>> On Wed, 18 May 2011, David Li wrote:
>>>
>>>> +      error ("Unrecognized option %s", is_enable ? "-fenable" : "-fdisable");
>>>
>>>> +      error ("Unknown pass %s specified in %s",
>>>> +          phase_name,
>>>> +          is_enable ? "-fenable" : "-fdisable");
>>>
>>> Follow GNU Coding Standards for diagnostics (start with lowercase letter).
>>>
>>>> +      inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
>>>> +              is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);
>>>
>>> Use separate calls to inform for the enable and disable cases, so that
>>> full sentences can be extracted for translation.
>>>
>>>> +           error ("Invalid range %s in option %s",
>>>> +                  one_range,
>>>> +                  is_enable ? "-fenable" : "-fdisable");
>>>
>>> GNU Coding Standards.
>>>
>>>> +               error ("Invalid range %s in option %s",
>>>
>>> Likewise.
>>>
>>>> +          inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
>>>> +                  is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);
>>>
>>> Again needs GCS and i18n fixes.
>>>
>>> --
>>> Joseph S. Myers
>>> joseph@codesourcery.com
>>>
>>
>
Joseph Myers May 25, 2011, 4:53 p.m. UTC | #13
On Wed, 25 May 2011, Xinliang David Li wrote:

> Ping. The link to the message:
> 
> http://gcc.gnu.org/ml/gcc-patches/2011-05/msg01303.html

I don't consider this an option handling patch.  Patches adding whole new 
features involving new options should be reviewed by maintainers for the 
part of the compiler relevant to those features (since there isn't a pass 
manager maintainer, I guess that means middle-end).
Xinliang David Li May 25, 2011, 5:21 p.m. UTC | #14
Fair enough.  Richard?

Thanks,

David

On Wed, May 25, 2011 at 9:53 AM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> On Wed, 25 May 2011, Xinliang David Li wrote:
>
>> Ping. The link to the message:
>>
>> http://gcc.gnu.org/ml/gcc-patches/2011-05/msg01303.html
>
> I don't consider this an option handling patch.  Patches adding whole new
> features involving new options should be reviewed by maintainers for the
> part of the compiler relevant to those features (since there isn't a pass
> manager maintainer, I guess that means middle-end).
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>
diff mbox

Patch

Index: tree-pass.h
===================================================================
--- tree-pass.h	(revision 173635)
+++ tree-pass.h	(working copy)
@@ -644,4 +644,12 @@  extern bool first_pass_instance;
 /* Declare for plugins.  */
 extern void do_per_function_toporder (void (*) (void *), void *);
 
+extern void enable_disable_pass (const char *, bool);
+extern bool is_pass_explicitly_disabled (struct opt_pass *, tree);
+extern bool is_pass_explicitly_enabled (struct opt_pass *, tree);
+extern void register_pass_name (struct opt_pass *, const char *);
+extern struct opt_pass *get_pass_by_name (const char *);
+struct function;
+extern void pass_dump_function_header (FILE *, tree, struct function *);
+
 #endif /* GCC_TREE_PASS_H */
Index: final.c
===================================================================
--- final.c	(revision 173635)
+++ final.c	(working copy)
@@ -4456,19 +4456,7 @@  rest_of_clean_state (void)
 	}
       else
 	{
-	  const char *aname;
-	  struct cgraph_node *node = cgraph_node (current_function_decl);
-
-	  aname = (IDENTIFIER_POINTER
-		   (DECL_ASSEMBLER_NAME (current_function_decl)));
-	  fprintf (final_output, "\n;; Function (%s) %s\n\n", aname,
-	     node->frequency == NODE_FREQUENCY_HOT
-	     ? " (hot)"
-	     : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
-	     ? " (unlikely executed)"
-	     : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
-	     ? " (executed once)"
-	     : "");
+	  pass_dump_function_header (final_output, current_function_decl, cfun);
 
 	  flag_dump_noaddr = flag_dump_unnumbered = 1;
 	  if (flag_compare_debug_opt || flag_compare_debug)
Index: common.opt
===================================================================
--- common.opt	(revision 173635)
+++ common.opt	(working copy)
@@ -1018,6 +1018,14 @@  fdiagnostics-show-option
 Common Var(flag_diagnostics_show_option) Init(1)
 Amend appropriate diagnostic messages with the command line option that controls them
 
+fdisable-
+Common Joined RejectNegative Var(common_deferred_options) Defer
+-fdisable-[tree|rtl|ipa]-<pass>=range1+range2 disables an optimization pass
+
+fenable-
+Common Joined RejectNegative Var(common_deferred_options) Defer
+-fenable-[tree|rtl|ipa]-<pass>=range1+range2 enables an optimization pass
+
 fdump-
 Common Joined RejectNegative Var(common_deferred_options) Defer
 -fdump-<type>	Dump various compiler internals to a file
Index: opts-global.c
===================================================================
--- opts-global.c	(revision 173635)
+++ opts-global.c	(working copy)
@@ -411,6 +411,12 @@  handle_common_deferred_options (void)
 	    error ("unrecognized command line option %<-fdump-%s%>", opt->arg);
 	  break;
 
+	case OPT_fenable_:
+	case OPT_fdisable_:
+	  enable_disable_pass (opt->arg, (opt->opt_index == OPT_fenable_?
+	                       true : false));
+          break;
+
 	case OPT_ffixed_:
 	  /* Deferred.  */
 	  fix_register (opt->arg, 1, 1);
Index: tree-cfg.c
===================================================================
--- tree-cfg.c	(revision 173636)
+++ tree-cfg.c	(working copy)
@@ -2090,11 +2090,7 @@  gimple_dump_cfg (FILE *file, int flags)
 {
   if (flags & TDF_DETAILS)
     {
-      const char *funcname
-	= lang_hooks.decl_printable_name (current_function_decl, 2);
-
-      fputc ('\n', file);
-      fprintf (file, ";; Function %s\n\n", funcname);
+      pass_dump_function_header (file, current_function_decl, cfun);
       fprintf (file, ";; \n%d basic blocks, %d edges, last basic block %d.\n\n",
 	       n_basic_blocks, n_edges, last_basic_block);
 
Index: passes.c
===================================================================
--- passes.c	(revision 173635)
+++ passes.c	(working copy)
@@ -382,7 +382,7 @@  void
 register_one_dump_file (struct opt_pass *pass)
 {
   char *dot_name, *flag_name, *glob_name;
-  const char *name, *prefix;
+  const char *name, *full_name, *prefix;
   char num[10];
   int flags, id;
 
@@ -411,6 +411,8 @@  register_one_dump_file (struct opt_pass 
   glob_name = concat (prefix, name, NULL);
   id = dump_register (dot_name, flag_name, glob_name, flags);
   set_pass_for_id (id, pass);
+  full_name = concat (prefix, pass->name, num, NULL);
+  register_pass_name (pass, full_name);
 }
 
 /* Recursive worker function for register_dump_files.  */
@@ -454,6 +456,298 @@  register_dump_files (struct opt_pass *pa
   register_dump_files_1 (pass, properties);
 }
 
+struct pass_registry
+{
+  const char* unique_name;
+  struct opt_pass *pass;
+};
+
+/* Pass registry hash function.  */
+
+static hashval_t
+passr_hash (const void *p)
+{
+  const struct pass_registry *const s = (const struct pass_registry *const) p;
+  return htab_hash_string (s->unique_name);
+}
+
+/* Hash equal function  */
+
+static int
+passr_eq (const void *p1, const void *p2)
+{
+  const struct pass_registry *const s1 = (const struct pass_registry *const) p1;
+  const struct pass_registry *const s2 = (const struct pass_registry *const) p2;
+
+  return !strcmp (s1->unique_name, s2->unique_name);
+}
+
+static htab_t pass_name_tab = NULL;
+
+/* Register PASS with NAME.  */
+
+void
+register_pass_name (struct opt_pass *pass, const char *name)
+{
+  struct pass_registry **slot;
+  struct pass_registry pr;
+
+  if (!pass_name_tab)
+    pass_name_tab = htab_create (10, passr_hash, passr_eq, NULL);
+
+  pr.unique_name = name;
+  slot = (struct pass_registry **) htab_find_slot (pass_name_tab, &pr, INSERT);
+  if (!*slot)
+    {
+      struct pass_registry *new_pr;
+
+      new_pr = XCNEW (struct pass_registry);
+      new_pr->unique_name = xstrdup (name);
+      new_pr->pass = pass;
+      *slot = new_pr;
+    }
+  else
+    gcc_assert ((*slot)->pass == pass);
+}
+
+/* Returns the pass with NAME.  */
+
+struct opt_pass *
+get_pass_by_name (const char *name)
+{
+  struct pass_registry **slot, pr;
+
+  gcc_assert (pass_name_tab);
+  pr.unique_name = name;
+  slot = (struct pass_registry **) htab_find_slot (pass_name_tab, &pr, NO_INSERT);
+
+  if (!slot || !*slot)
+    return NULL;
+
+  return (*slot)->pass;
+}
+
+
+/* Range [start, last].  */
+
+struct uid_range
+{
+  struct opt_pass *pass;
+  unsigned int start;
+  unsigned int last;
+  struct uid_range *next;
+};
+
+/* Hash function for pass structure.  */
+
+static hashval_t
+pass_hash (const void *s)
+{
+  const struct uid_range *const p = (const struct uid_range *const) s;
+  return p->pass->static_pass_number;
+}
+
+/* Pass equal function  */
+
+static int
+pass_eq (const void *s1, const void *s2)
+{
+  const struct uid_range *const p1 = (const struct uid_range *const) s1;
+  const struct uid_range *const p2 = (const struct uid_range *const) s2;
+  return p1->pass->static_pass_number == p2->pass->static_pass_number;
+}
+
+htab_t enabled_pass_uid_range_tab = NULL;
+htab_t disabled_pass_uid_range_tab = NULL;
+
+/* Parse option string for -fdisable- and -fenabler-
+   The syntax of the options:
+
+   -fenable-<pass_name>
+   -fdisable-<pass_name>
+
+   -fenable-<pass_name>=s1:e1,s2:e2,...
+   -fdisable-<pass_name>=s1:e1,s2:e2,...
+*/
+
+void
+enable_disable_pass (const char *arg, bool is_enable)
+{
+  struct opt_pass *pass;
+  htab_t the_tab;
+  char *range_str, *phase_name;
+  char *argstr = xstrdup (arg);
+
+  range_str = strchr (argstr,'=');
+  if (range_str)
+    {
+      *range_str = '\0';
+      range_str++;
+    }
+
+  phase_name = argstr;
+  if (!*phase_name)
+    {
+      error ("Unrecognized option %s", is_enable ? "-fenable" : "-fdisable");
+      free (argstr);
+      return;
+    }
+  pass = get_pass_by_name (phase_name);
+  if (!pass)
+    {
+      error ("Unknown pass %s specified in %s",
+	     phase_name,
+	     is_enable ? "-fenable" : "-fdisable");
+      free (argstr);
+      return;
+    }
+  if (is_enable)
+    {
+      if (!enabled_pass_uid_range_tab)
+	enabled_pass_uid_range_tab = htab_create (10, pass_hash, pass_eq, NULL);
+      the_tab = enabled_pass_uid_range_tab;
+    }
+  else
+    {
+      if (!disabled_pass_uid_range_tab)
+	disabled_pass_uid_range_tab = htab_create (10, pass_hash, pass_eq, NULL);
+      the_tab = disabled_pass_uid_range_tab;
+    }
+
+  if (!range_str)
+    {
+      struct uid_range **slot;
+      struct uid_range *new_range = XCNEW (struct uid_range);
+
+      new_range->pass = pass;
+      new_range->start = 0;
+      new_range->last = (unsigned)-1;
+
+      slot = (struct uid_range **) htab_find_slot (the_tab, new_range, INSERT);
+      new_range->next = *slot;
+      *slot = new_range;
+      inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
+              is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);
+    }
+  else
+    {
+      char *next_range = NULL;
+      char *one_range = range_str;
+      char *end_val = NULL;
+
+      do
+	{
+	  struct uid_range **slot;
+	  struct uid_range *new_range;
+	  char *invalid = NULL;
+	  long start;
+
+	  next_range = strchr (one_range, ',');
+	  if (next_range)
+	    {
+	      *next_range = '\0';
+	      next_range++;
+	    }
+
+	  end_val = strchr (one_range, ':');
+	  if (end_val)
+	    {
+	      *end_val = '\0';
+	      end_val++;
+	    }
+	  start = strtol (one_range, &invalid, 10);
+	  if (*invalid || start < 0)
+	    {
+	      error ("Invalid range %s in option %s",
+		     one_range,
+		     is_enable ? "-fenable" : "-fdisable");
+	      free (argstr);
+	      return;
+	    }
+	  if (!end_val)
+	    {
+	      new_range = XCNEW (struct uid_range);
+              new_range->pass = pass;
+	      new_range->start = (unsigned) start;
+	      new_range->last = (unsigned) start;
+	    }
+	  else
+	    {
+	      long last = strtol (end_val, &invalid, 10);
+	      if (*invalid || last < start)
+		{
+		  error ("Invalid range %s in option %s",
+			 end_val,
+			 is_enable ? "-fenable" : "-fdisable");
+		  free (argstr);
+		  return;
+		}
+	      new_range = XCNEW (struct uid_range);
+              new_range->pass = pass;
+	      new_range->start = (unsigned) start;
+	      new_range->last = (unsigned) last;
+	    }
+	  slot = (struct uid_range **) htab_find_slot (the_tab, new_range, INSERT);
+	  new_range->next = *slot;
+	  *slot = new_range;
+          inform (UNKNOWN_LOCATION, "%s pass %s for functions in the range of [%u, %u]\n",
+                  is_enable? "Enable":"Disable", phase_name, new_range->start, new_range->last);
+
+	  one_range = next_range;
+	} while (next_range);
+    }
+
+  free (argstr);
+}
+
+/* Returns true if PASS is explicitly enabled/disabled for FUNC.  */
+
+static bool
+is_pass_explicitly_enabled_or_disabled (struct opt_pass *pass,
+					tree func, htab_t tab)
+{
+  struct uid_range **slot, *range, key;
+  int cgraph_uid;
+
+  if (!tab)
+    return false;
+
+  key.pass = pass;
+  slot = (struct uid_range **) htab_find_slot (tab, &key, NO_INSERT);
+  if (!slot || !*slot)
+    return false;
+
+  cgraph_uid = func ? cgraph_node (func)->uid : 0;
+
+  range = *slot;
+  while (range)
+    {
+      if ((unsigned) cgraph_uid >= range->start
+	  && (unsigned) cgraph_uid <= range->last)
+	return true;
+      range = range->next;
+    }
+
+  return false;
+}
+
+/* Returns true if PASS is explicitly enabled for FUNC.  */
+
+bool
+is_pass_explicitly_enabled (struct opt_pass *pass, tree func)
+{
+  return is_pass_explicitly_enabled_or_disabled (pass, func, enabled_pass_uid_range_tab);
+}
+
+/* Returns true if PASS is explicitly disabled for FUNC.  */
+
+bool
+is_pass_explicitly_disabled (struct opt_pass *pass, tree func)
+{
+  return is_pass_explicitly_enabled_or_disabled (pass, func, disabled_pass_uid_range_tab);
+}
+
+
 /* Look at the static_pass_number and duplicate the pass
    if it is already added to a list. */
 
@@ -1349,6 +1643,29 @@  verify_curr_properties (void *data)
 }
 #endif
 
+void
+pass_dump_function_header (FILE *dump_file, tree fdecl, struct function *fun)
+{
+  const char *dname, *aname;
+  struct cgraph_node *node = cgraph_node (fdecl);
+  dname = lang_hooks.decl_printable_name (fdecl, 2);
+  aname = (IDENTIFIER_POINTER
+	   (DECL_ASSEMBLER_NAME (fdecl)));
+  if (L_IPO_COMP_MODE)
+    fprintf (dump_file, "\n;; Function %s (%s)[%d:%d][uid=%d]", dname, aname,
+	     FUNC_DECL_MODULE_ID (fun), FUNC_DECL_FUNC_ID (fun), node->uid);
+  else
+    fprintf (dump_file, "\n;; Function %s (%s)[uid=%d]", dname, aname, node->uid);
+  fprintf (dump_file, "%s\n\n",
+           node->frequency == NODE_FREQUENCY_HOT
+           ? " (hot)"
+           : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
+           ? " (unlikely executed)"
+           : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
+           ? " (executed once)"
+           : "");
+}
+
 /* Initialize pass dump file.  */
 /* This is non-static so that the plugins can use it.  */
 
@@ -1362,26 +1679,7 @@  pass_init_dump_file (struct opt_pass *pa
       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;
-	  struct cgraph_node *node = cgraph_node (current_function_decl);
-	  dname = lang_hooks.decl_printable_name (current_function_decl, 2);
-	  aname = (IDENTIFIER_POINTER
-		   (DECL_ASSEMBLER_NAME (current_function_decl)));
-	  if (L_IPO_COMP_MODE)
-	    fprintf (dump_file, "\n;; Function %s (%s)[%d:%d]", dname, aname,
-		     FUNC_DECL_MODULE_ID (cfun), FUNC_DECL_FUNC_ID (cfun));
-	  else
-	    fprintf (dump_file, "\n;; Function %s (%s)", dname, aname);
-	  fprintf (dump_file, "%s\n\n",
-	     node->frequency == NODE_FREQUENCY_HOT
-	     ? " (hot)"
-	     : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
-	     ? " (unlikely executed)"
-	     : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
-	     ? " (executed once)"
-	     : "");
-	}
+        pass_dump_function_header (dump_file, current_function_decl, cfun);
       return initializing_dump;
     }
   else
@@ -1525,6 +1823,8 @@  execute_one_pass (struct opt_pass *pass)
 {
   bool initializing_dump;
   unsigned int todo_after = 0;
+  bool explicitly_enabled = false;
+  bool explicitly_disabled = false;
 
   bool gate_status;
 
@@ -1535,11 +1835,15 @@  execute_one_pass (struct opt_pass *pass)
   else
     gcc_assert (cfun && current_function_decl);
 
+  explicitly_enabled = is_pass_explicitly_enabled (pass, current_function_decl);
+  explicitly_disabled = is_pass_explicitly_disabled (pass, current_function_decl);
+
   current_pass = pass;
 
   /* Check whether gate check should be avoided.
      User controls the value of the gate through the parameter "gate_status". */
   gate_status = (pass->gate == NULL) ? true : pass->gate();
+  gate_status = !explicitly_disabled && (gate_status || explicitly_enabled);
 
   /* Override gate with plugin.  */
   invoke_plugin_callbacks (PLUGIN_OVERRIDE_GATE, &gate_status);