New option to disable/enable optimization passes.
From-SVN: r174423
This commit is contained in:
parent
d84ab7d2d4
commit
226c52aafb
@ -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
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
|
@ -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);
|
||||
|
322
gcc/passes.c
322
gcc/passes.c
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user