Will fix the Changelog, and add documentation. Thanks,
David On Wed, May 18, 2011 at 1:26 PM, Richard Guenther <richard.guent...@gmail.com> wrote: > On Wed, May 18, 2011 at 8:37 PM, David Li <davi...@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 <davi...@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 >> >