Will fix the Changelog, and add documentation.

Thanks,

David



On Wed, May 18, 2011 at 1:26 PM, Richard Guenther
<richard.guent...@gmail.com> wrote:
> On Wed, May 18, 2011 at 8:37 PM, David Li <davi...@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  <davi...@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
>>
>

Reply via email to