New option to disable/enable optimization passes.

From-SVN: r174423
This commit is contained in:
Xinliang David Li 2011-05-30 04:38:42 +00:00 committed by Xinliang David Li
parent d84ab7d2d4
commit 226c52aafb
7 changed files with 452 additions and 2 deletions

View File

@ -1,3 +1,18 @@
2011-05-29 Xinliang David Li <davidxl@google.com>
* opts-global.c (handle_common_deferred_options): Handle new options.
* passes.c (register_one_dump_file): Call register_pass_name.
(execute_one_pass): Check explicit enable/disable flag.
(passr_hash): New function.
(passr_eq): Ditto.
(register_pass_name): Ditto.
(get_pass_by_name): Ditto.
(pass_hash): Ditto.
(pass_eq): Ditto.
(enable_pass): Ditto.
(disable_pass): Ditto.
(is_pass_explicitly_enabled_or_disabled): Ditto.
2011-05-29 Uros Bizjak <ubizjak@gmail.com>
* config/i386/i386.md (*movoi_internal_avx): Use

View File

@ -985,6 +985,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

View File

@ -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,8 @@ 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-@var{kind}-@var{pass} @gol
-fenable-@var{kind}-@var{pass}=@var{range-list} @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
@ -5017,6 +5024,7 @@ more closely, if you do not optimize.
@opindex fdbg-cnt-list
Print the name and the counter upper bound for all debug counters.
@item -fdbg-cnt=@var{counter-value-list}
@opindex fdbg-cnt
Set the internal debug counter upper bound. @var{counter-value-list}
@ -5026,7 +5034,73 @@ All debug counters have the initial upper bound of @var{UINT_MAX},
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.
@itemx -fenable-@var{kind}-@var{pass}
@itemx -fdisable-@var{kind}-@var{pass}=@var{range-list}
@opindex fdisable-
@opindex fenable-
This is a set of debugging options that are used to explicitly disable/enable
optimization passes. For compiler users, regular options for enabling/disabling
passes should be used instead.
@itemize
@item -fdisable-ipa-@var{pass}
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}
@item -fdisable-rtl-@var{pass}=@var{range-list}
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}
@item -fdisable-tree-@var{pass}=@var{range-list}
Disable tree pass @var{pass}. See @option{-fdisable-rtl} for the description of
option arguments.
@item -fenable-ipa-@var{pass}
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}
@item -fenable-rtl-@var{pass}=@var{range-list}
Enable rtl pass @var{pass}. See @option{-fdisable-rtl} for option argument
description and examples.
@item -fenable-tree-@var{pass}
@item -fenable-tree-@var{pass}=@var{range-list}
Enable 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
# enable tree full unroll
-fenable-tree-unroll
@end smallexample
@end itemize
@item -d@var{letters}
@itemx -fdump-rtl-@var{pass}

View File

@ -370,6 +370,14 @@ handle_common_deferred_options (void)
error ("unrecognized command line option %<-fdump-%s%>", opt->arg);
break;
case OPT_fenable_:
case OPT_fdisable_:
if (opt->opt_index == OPT_fenable_)
enable_pass (opt->arg);
else
disable_pass (opt->arg);
break;
case OPT_ffixed_:
/* Deferred. */
fix_register (opt->arg, 1, 1);

View File

@ -97,6 +97,8 @@ along with GCC; see the file COPYING3. If not see
The variable current_pass is also used for statistics and plugins. */
struct opt_pass *current_pass;
static void register_pass_name (struct opt_pass *, const char *);
/* Call from anywhere to find out what pass this is. Useful for
printing out debugging information deep inside an service
routine. */
@ -375,7 +377,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 +406,8 @@ register_one_dump_file (struct opt_pass *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 +451,297 @@ register_dump_files (struct opt_pass *pass,int properties)
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. */
static 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 (256, 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. */
static 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
{
unsigned int start;
unsigned int last;
struct uid_range *next;
};
typedef struct uid_range *uid_range_p;
DEF_VEC_P(uid_range_p);
DEF_VEC_ALLOC_P(uid_range_p, heap);
static VEC(uid_range_p, heap) *enabled_pass_uid_range_tab = NULL;
static VEC(uid_range_p, heap) *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,...
*/
static void
enable_disable_pass (const char *arg, bool is_enable)
{
struct opt_pass *pass;
char *range_str, *phase_name;
char *argstr = xstrdup (arg);
VEC(uid_range_p, heap) **tab = 0;
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 || pass->static_pass_number == -1)
{
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)
tab = &enabled_pass_uid_range_tab;
else
tab = &disabled_pass_uid_range_tab;
if ((unsigned) pass->static_pass_number >= VEC_length (uid_range_p, *tab))
VEC_safe_grow_cleared (uid_range_p, heap,
*tab, pass->static_pass_number + 1);
if (!range_str)
{
uid_range_p slot;
uid_range_p new_range = XCNEW (struct uid_range);
new_range->start = 0;
new_range->last = (unsigned)-1;
slot = VEC_index (uid_range_p, *tab, pass->static_pass_number);
new_range->next = slot;
VEC_replace (uid_range_p, *tab, pass->static_pass_number,
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
{
uid_range_p slot;
uid_range_p 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->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->start = (unsigned) start;
new_range->last = (unsigned) last;
}
slot = VEC_index (uid_range_p, *tab, pass->static_pass_number);
new_range->next = slot;
VEC_replace (uid_range_p, *tab, pass->static_pass_number,
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);
}
/* Enable pass specified by ARG. */
void
enable_pass (const char *arg)
{
enable_disable_pass (arg, true);
}
/* Disable pass specified by ARG. */
void
disable_pass (const char *arg)
{
enable_disable_pass (arg, false);
}
/* Returns true if PASS is explicitly enabled/disabled for FUNC. */
static bool
is_pass_explicitly_enabled_or_disabled (struct opt_pass *pass,
tree func,
VEC(uid_range_p, heap) *tab)
{
uid_range_p slot, range;
int cgraph_uid;
if (!tab
|| (unsigned) pass->static_pass_number >= VEC_length (uid_range_p, tab)
|| pass->static_pass_number == -1)
return false;
slot = VEC_index (uid_range_p, tab, pass->static_pass_number);
if (!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;
}
/* Look at the static_pass_number and duplicate the pass
if it is already added to a list. */
@ -1493,6 +1788,30 @@ execute_all_ipa_transforms (void)
}
}
/* Check if PASS is explicitly disabled or enabled and return
the gate status. FUNC is the function to be processed, and
GATE_STATUS is the gate status determined by pass manager by
default. */
static bool
override_gate_status (struct opt_pass *pass, tree func, bool gate_status)
{
bool explicitly_enabled = false;
bool explicitly_disabled = false;
explicitly_enabled
= is_pass_explicitly_enabled_or_disabled (pass, func,
enabled_pass_uid_range_tab);
explicitly_disabled
= is_pass_explicitly_enabled_or_disabled (pass, func,
disabled_pass_uid_range_tab);
gate_status = !explicitly_disabled && (gate_status || explicitly_enabled);
return gate_status;
}
/* Execute PASS. */
bool
@ -1515,6 +1834,7 @@ execute_one_pass (struct opt_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 = override_gate_status (pass, current_function_decl, gate_status);
/* Override gate with plugin. */
invoke_plugin_callbacks (PLUGIN_OVERRIDE_GATE, &gate_status);

View File

@ -637,4 +637,7 @@ extern bool first_pass_instance;
/* Declare for plugins. */
extern void do_per_function_toporder (void (*) (void *), void *);
extern void disable_pass (const char *);
extern void enable_pass (const char *);
#endif /* GCC_TREE_PASS_H */

View File

@ -3013,3 +3013,25 @@ pp_base_tree_identifier (pretty_printer *pp, tree id)
pp_append_text (pp, IDENTIFIER_POINTER (id),
IDENTIFIER_POINTER (id) + IDENTIFIER_LENGTH (id));
}
#if 0
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)"
: "");
}
#endif