public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Xinliang David Li <davidxl@google.com>
To: Richard Guenther <richard.guenther@gmail.com>
Cc: reply@codereview.appspotmail.com, gcc-patches@gcc.gnu.org
Subject: Re: New options to disable/enable any pass for any functions (issue4550056)
Date: Thu, 19 May 2011 08:04:00 -0000	[thread overview]
Message-ID: <BANLkTimQ_f2NMpT9_67fkYMRy=k5dP-bWg@mail.gmail.com> (raw)
In-Reply-To: <BANLkTin3MwJgtBNxGiPdiK9XLhhr+sQ2ew@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 20983 bytes --]

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
>>>
>>
>

[-- Attachment #2: pass_option4.p --]
[-- Type: text/x-pascal, Size: 20685 bytes --]

Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi	(revision 173837)
+++ doc/invoke.texi	(working copy)
@@ -282,6 +282,11 @@ Objective-C and Objective-C++ Dialects}.
 @xref{Debugging Options,,Options for Debugging Your Program or GCC}.
 @gccoptlist{-d@var{letters}  -dumpspecs  -dumpmachine  -dumpversion @gol
 -fdbg-cnt-list -fdbg-cnt=@var{counter-value-list} @gol
+-fdisable-ipa-@var{pass_name} @gol
+-fdisable-rtl-@var{pass_name} @gol
+-fdisable-rtl-@var{pass-name}=@var{range-list} @gol
+-fdisable-tree-@var{pass_name} @gol
+-fdisable-tree-@var{pass-name}=@var{range-list} @gol
 -fdump-noaddr -fdump-unnumbered -fdump-unnumbered-links @gol
 -fdump-translation-unit@r{[}-@var{n}@r{]} @gol
 -fdump-class-hierarchy@r{[}-@var{n}@r{]} @gol
@@ -313,6 +318,10 @@ Objective-C and Objective-C++ Dialects}.
 -fcompare-debug@r{[}=@var{opts}@r{]}  -fcompare-debug-second @gol
 -feliminate-dwarf2-dups -feliminate-unused-debug-types @gol
 -feliminate-unused-debug-symbols -femit-class-debug-always @gol
+-fenable-ipa-@var{pass} @gol
+-fenable-rtl-@var{pass} @gol
+-fenable-rtl-@var{pass}=@var{range-list} @gol
+-fenable-tree-@var{pass} @gol
 -fdebug-types-section @gol
 -fmem-report -fpre-ipa-mem-report -fpost-ipa-mem-report -fprofile-arcs @gol
 -frandom-seed=@var{string} -fsched-verbose=@var{n} @gol
@@ -4993,7 +5002,36 @@ All debug counters have the initial uppe
 thus dbg_cnt() returns true always unless the upper bound is set by this option.
 e.g. With -fdbg-cnt=dce:10,tail_call:0
 dbg_cnt(dce) will return true only for first 10 invocations
-and dbg_cnt(tail_call) will return false always.
+
+@item -fdisable-ipa-@var{pass}
+@opindex fdisable-ipa
+Disable ipa pass @var{pass}. @var{pass} is the pass name. If the same pass is statically invoked in the compiler multiple times, the pass name should be appended with a sequential number starting from 1.
+
+@item -fdisable-rtl-@var{pass}
+@itemx -fdisable-rtl-@var{pass}=@var{range-list} 
+@opindex fdisable-rtl
+Disable rtl pass @var{pass}. @var{pass} is the pass name. If the same pass is statically invoked in the compiler multiple times, the pass name should be appended with a sequential number starting from 1. @var{range-list} is a comma seperated list of function ranges. Each range is a number pair seperated by a colon. The range is inclusive in both ends. If the range is trivial, the number pair can be simplified a a single number. If the function's cgraph node's @var{uid} is falling within one of the specified ranges, the @var{pass} is disabled for that function. The @var{uid} is shown in the function header of a dump file.
+
+@item -fdisable-tree-@var{pass}
+@itemx -fdisable-tree-@var{pass}=@var{range-list} 
+@opindex fdisable-tree
+Disable tree pass @var{pass}. See @option{-fdisable-rtl} for the description of option arguments.
+
+@smallexample
+
+# disable ccp1 for all functions
+   -fdisable-tree-ccp1 
+# disable complete unroll for function whose cgraph node uid is 1
+   -fenable-tree-cunroll=1   
+# disable gcse2 for functions at the following ranges [1,1],
+# [300,400], and [400,1000]                          
+   -fdisable-rtl-gcse2=1:100,300,400:1000 
+# disable early inlining
+   -fdisable-tree-einline
+# disable ipa inlining
+   -fdisable-ipa-inline 
+
+@end smallexample
 
 @item -d@var{letters}
 @itemx -fdump-rtl-@var{pass}
@@ -5583,6 +5621,20 @@ is made by appending @file{.vrp} to the 
 Enable all the available tree dumps with the flags provided in this option.
 @end table
 
+@item -fenable-ipa-@var{pass}
+@opindex fenable-ipa
+Enable ipa pass @var{pass}. @var{pass} is the pass name. If the same pass is statically invoked in the compiler multiple times, the pass name should be appended with a sequential number starting from 1.
+
+@item -fenable-rtl-@var{pass}
+@itemx -fenable-rtl-@var{pass}=@var{range-list} 
+@opindex fenable-rtl
+Enable rtl pass @var{pass}. See @option{-fdisable-rtl} for option argument description and examples.
+
+@item -fenable-tree-@var{pass}
+@itemx -fenable-tree-@var{pass}=@var{range-list} 
+@opindex fenable-tree
+Enable tree pass @var{pass}. See @option{-fdisable-rtl} for the description of option arguments and examples.
+
 @item -ftree-vectorizer-verbose=@var{n}
 @opindex ftree-vectorizer-verbose
 This option controls the amount of debugging output the vectorizer prints.
Index: tree-pass.h
===================================================================
--- tree-pass.h	(revision 173837)
+++ tree-pass.h	(working copy)
@@ -637,4 +637,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 173837)
+++ final.c	(working copy)
@@ -4360,20 +4360,7 @@ rest_of_clean_state (void)
 	}
       else
 	{
-	  const char *aname;
-	  struct cgraph_node *node = cgraph_get_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)
 	    dump_flags |= TDF_NOUID;
Index: tree-ssa-loop-ivopts.c
===================================================================
--- tree-ssa-loop-ivopts.c	(revision 173837)
+++ tree-ssa-loop-ivopts.c	(working copy)
@@ -3968,7 +3968,7 @@ get_computation_cost_at (struct ivopts_d
                          int *inv_expr_id)
 {
   tree ubase = use->iv->base, ustep = use->iv->step;
-  tree cbase, cstep;
+  tree cbase, cstep, cbase_strip;
   tree utype = TREE_TYPE (ubase), ctype;
   unsigned HOST_WIDE_INT cstepi, offset = 0;
   HOST_WIDE_INT ratio, aratio;
@@ -4026,6 +4026,13 @@ get_computation_cost_at (struct ivopts_d
   if (!constant_multiple_of (ustep, cstep, &rat))
     return infinite_cost;
 
+  cbase_strip = STRIP_NOPS (cbase);
+  /* Avoid confusing aliaser.  */
+  if (TREE_CODE (cbase_strip) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (cbase_strip, 0)) == VAR_DECL
+      && (HOST_WIDE_INT) cstepi < 0)
+    return infinite_cost;
+
   if (double_int_fits_in_shwi_p (rat))
     ratio = double_int_to_shwi (rat);
   else
Index: common.opt
===================================================================
--- common.opt	(revision 173837)
+++ common.opt	(working copy)
@@ -974,6 +974,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 173837)
+++ opts-global.c	(working copy)
@@ -370,6 +370,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 173837)
+++ tree-cfg.c	(working copy)
@@ -2052,11 +2052,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 173837)
+++ passes.c	(working copy)
@@ -375,7 +375,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;
 
@@ -404,6 +404,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.  */
@@ -447,6 +449,317 @@ 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
+    return; /* Ignore plugin passes.  */
+}
+
+/* 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 -fenable-
+   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)
+    {
+      if (is_enable)
+        error ("unrecognized option -fenable");
+      else
+        error ("unrecognized option -fdisable");
+      free (argstr);
+      return;
+    }
+  pass = get_pass_by_name (phase_name);
+  if (!pass)
+    {
+      if (is_enable)
+        error ("unknown pass %s specified in -fenable", phase_name);
+      else
+        error ("unknown pass %s specified in -fdisble", phase_name);
+      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;
+      if (is_enable)
+        inform (UNKNOWN_LOCATION, "enable pass %s for functions in the range "
+                "of [%u, %u]", phase_name, new_range->start, new_range->last);
+      else
+        inform (UNKNOWN_LOCATION, "disable pass %s for functions in the range "
+                "of [%u, %u]", 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;
+          if (is_enable)
+            inform (UNKNOWN_LOCATION,
+                    "enable pass %s for functions in the range of [%u, %u]",
+                    phase_name, new_range->start, new_range->last);
+          else
+            inform (UNKNOWN_LOCATION,
+                    "disable pass %s for functions in the range of [%u, %u]",
+                    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_get_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. */
 
@@ -1329,6 +1642,26 @@ 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_get_node (fdecl);
+  dname = lang_hooks.decl_printable_name (fdecl, 2);
+  aname = (IDENTIFIER_POINTER
+	   (DECL_ASSEMBLER_NAME (fdecl)));
+  fprintf (dump_file, "\n;; Function %s (%s)[fundef_no:%d][uid=%d]",
+           dname, aname, fun->funcdef_no, 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.  */
 
@@ -1342,21 +1675,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_get_node (current_function_decl);
-	  dname = lang_hooks.decl_printable_name (current_function_decl, 2);
-	  aname = (IDENTIFIER_POINTER
-		   (DECL_ASSEMBLER_NAME (current_function_decl)));
-	  fprintf (dump_file, "\n;; Function %s (%s)%s\n\n", dname, aname,
-	     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
@@ -1500,6 +1819,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;
 
@@ -1510,11 +1831,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);

  reply	other threads:[~2011-05-18 22:39 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-05-18 19:49 David Li
2011-05-18 20:21 ` Joseph S. Myers
2011-05-18 20:33   ` Xinliang David Li
2011-05-20 16:44   ` Xinliang David Li
2011-05-23  9:17     ` Xinliang David Li
2011-05-25 17:21       ` Xinliang David Li
2011-05-25 17:44         ` Joseph S. Myers
2011-05-25 18:07           ` Xinliang David Li
2011-05-26 10:20           ` Richard Guenther
2011-05-26 13:00             ` Joseph S. Myers
2011-05-26 23:48             ` Xinliang David Li
2011-05-27  2:32               ` Xinliang David Li
2011-05-27 12:50                 ` Richard Guenther
2011-05-31  4:54                   ` Xinliang David Li
2011-05-31  7:05                     ` Xinliang David Li
2011-05-31 10:03                       ` Richard Guenther
2011-06-01  0:02                         ` Xinliang David Li
2011-06-01 19:19                       ` H.J. Lu
2011-05-31  9:57                     ` Richard Guenther
2011-05-31 17:30                       ` Xinliang David Li
2011-06-01  0:01                         ` Xinliang David Li
2011-06-01  0:04                           ` Xinliang David Li
2011-06-01  8:14                             ` Jan Hubicka
2011-06-01  9:23                             ` Richard Guenther
2011-06-01  9:27                               ` Jan Hubicka
2011-05-18 21:01 ` Richard Guenther
2011-05-18 21:20   ` Xinliang David Li
2011-05-19  8:04     ` Xinliang David Li [this message]
2011-05-19 19:23 ` Andi Kleen
2011-05-19 19:33   ` Xinliang David Li
2011-05-19 20:25     ` Andi Kleen
2011-05-19 21:36       ` Xinliang David Li

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='BANLkTimQ_f2NMpT9_67fkYMRy=k5dP-bWg@mail.gmail.com' \
    --to=davidxl@google.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=reply@codereview.appspotmail.com \
    --cc=richard.guenther@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).