summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/common.opt8
-rw-r--r--gcc/doc/invoke.texi76
-rw-r--r--gcc/opts-global.c8
-rw-r--r--gcc/passes.c322
-rw-r--r--gcc/tree-pass.h3
-rw-r--r--gcc/tree-pretty-print.c22
7 files changed, 452 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 02c1bf734ce..ad6be6da202 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/common.opt b/gcc/common.opt
index 3ee9ded4624..5a5360785bd 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -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
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index f53d6107114..4b54c4abdae 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -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}
diff --git a/gcc/opts-global.c b/gcc/opts-global.c
index 1134e3a2745..6fdc9519ca9 100644
--- a/gcc/opts-global.c
+++ b/gcc/opts-global.c
@@ -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);
diff --git a/gcc/passes.c b/gcc/passes.c
index e176d1c05ba..4cfc4d37ee6 100644
--- a/gcc/passes.c
+++ b/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);
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 9520c178c96..daf7202f4f6 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -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 */
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index f2f5a220018..b62417a7797 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -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