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);
next prev parent 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).