diff options
author | Jan Hubicka <jh@suse.cz> | 2013-09-01 17:14:24 +0200 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2013-09-01 15:14:24 +0000 |
commit | bbc9396b62a65e8ecc67bb2f8df870e2b5040ac7 (patch) | |
tree | a04f98f7e7873d1c147343271471b27491c59a96 | |
parent | 0cea211ebd67d10e93649074d348d12df67c4d97 (diff) | |
download | gcc-bbc9396b62a65e8ecc67bb2f8df870e2b5040ac7.zip gcc-bbc9396b62a65e8ecc67bb2f8df870e2b5040ac7.tar.gz gcc-bbc9396b62a65e8ecc67bb2f8df870e2b5040ac7.tar.bz2 |
common.opt (fdevirtualize-speculatively): New function.
* common.opt (fdevirtualize-speculatively): New function.
* invoke.texi (fdevirtualize-speculatively): Document.
* ipa-devirt.c: Include ipa-inline.h
(likely_target_p): New function.
(ipa_devirt): New function.
(gate_ipa_devirt): New function.
(pass_data_ipa_devirt): New static var.
(pass_ipa_devirt): Likewise.
(make_pass_ipa_devirt): New function.
* opts.c (default_options): Add OPT_fdevirtualize_speculatively.
(common_handle_option): Disable devirtualization when
value range profiling is available.
* passes.def (pass_ipa_devirt): Add.
* timever.def (TV_IPA_DEVIRT): New timevar.
* tree-pass.h (make_pass_ipa_devirt):
From-SVN: r202145
-rw-r--r-- | gcc/ChangeLog | 18 | ||||
-rw-r--r-- | gcc/common.opt | 6 | ||||
-rw-r--r-- | gcc/doc/invoke.texi | 13 | ||||
-rw-r--r-- | gcc/ipa-devirt.c | 266 | ||||
-rw-r--r-- | gcc/opts.c | 6 | ||||
-rw-r--r-- | gcc/passes.def | 1 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ipa/devirt-11.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/tree-ssa/pr45453.C | 2 | ||||
-rw-r--r-- | gcc/timevar.def | 1 | ||||
-rw-r--r-- | gcc/tree-pass.h | 1 |
11 files changed, 316 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 34e5d33..c4cc9b7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2013-09-01 Jan Hubicka <jh@suse.cz> + + * common.opt (fdevirtualize-speculatively): New function. + * invoke.texi (fdevirtualize-speculatively): Document. + * ipa-devirt.c: Include ipa-inline.h + (likely_target_p): New function. + (ipa_devirt): New function. + (gate_ipa_devirt): New function. + (pass_data_ipa_devirt): New static var. + (pass_ipa_devirt): Likewise. + (make_pass_ipa_devirt): New function. + * opts.c (default_options): Add OPT_fdevirtualize_speculatively. + (common_handle_option): Disable devirtualization when + value range profiling is available. + * passes.def (pass_ipa_devirt): Add. + * timever.def (TV_IPA_DEVIRT): New timevar. + * tree-pass.h (make_pass_ipa_devirt): + 2013-09-01 Iain Sandoe <iain@codesourcery.com> * config/darwin.h (LINK_COMMAND_SPEC_A): Revise sanitizer specs to diff --git a/gcc/common.opt b/gcc/common.opt index caf624f..a18a42b 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1007,6 +1007,10 @@ fdevirtualize Common Report Var(flag_devirtualize) Optimization Try to convert virtual calls to direct ones. +fdevirtualize-speculatively +Common Report Var(flag_devirtualize_speculatively) Optimization +Perform speculative devirtualization + fdiagnostics-show-location= Common Joined RejectNegative Enum(diagnostic_prefixing_rule) -fdiagnostics-show-location=[once|every-line] How often to emit source location at the beginning of line-wrapped diagnostics @@ -1366,7 +1370,7 @@ Common RejectNegative Joined fipa-cp Common Report Var(flag_ipa_cp) Optimization -Perform Interprocedural constant propagation +Perform interprocedural constant propagation fipa-cp-clone Common Report Var(flag_ipa_cp_clone) Optimization diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 1365f65..9dfb4d7 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -365,7 +365,7 @@ Objective-C and Objective-C++ Dialects}. -fcse-follow-jumps -fcse-skip-blocks -fcx-fortran-rules @gol -fcx-limited-range @gol -fdata-sections -fdce -fdelayed-branch @gol --fdelete-null-pointer-checks -fdevirtualize -fdse @gol +-fdelete-null-pointer-checks -fdevirtualize -fdevirtualize-speculatively -fdse @gol -fearly-inlining -fipa-sra -fexpensive-optimizations -ffat-lto-objects @gol -ffast-math -ffinite-math-only -ffloat-store -fexcess-precision=@var{style} @gol -fforward-propagate -ffp-contract=@var{style} -ffunction-sections @gol @@ -6712,7 +6712,7 @@ also turns on the following optimization flags: -fcrossjumping @gol -fcse-follow-jumps -fcse-skip-blocks @gol -fdelete-null-pointer-checks @gol --fdevirtualize @gol +-fdevirtualize -fdevirtualize-speculatively @gol -fexpensive-optimizations @gol -fgcse -fgcse-lm @gol -fhoist-adjacent-loads @gol @@ -7257,6 +7257,15 @@ indirect inlining (@code{-findirect-inlining}) and interprocedural constant propagation (@option{-fipa-cp}). Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}. +@item -fdevirtualize-speculatively +@opindex fdevirtualize-speculatively +Attempt to convert calls to virtual functions to speculative direct calls. +Based on the analysis of the type inheritance graph, determine for a given call +the set of likely targets. If the set is small, preferably of size 1, change +the call into an conditional deciding on direct and indirect call. The +speculative calls enable more optimizations, such as inlining. When they seem +useless after further optimization, they are converted back into original form. + @item -fexpensive-optimizations @opindex fexpensive-optimizations Perform a number of minor optimizations that are relatively expensive. diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c index 0b678bd..cab583e 100644 --- a/gcc/ipa-devirt.c +++ b/gcc/ipa-devirt.c @@ -101,6 +101,8 @@ along with GCC; see the file COPYING3. If not see possible_polymorphic_call_targets returns, given an parameters found in indirect polymorphic edge all possible polymorphic call targets of the call. + + pass_ipa_devirt performs simple speculative devirtualization. */ #include "config.h" @@ -116,6 +118,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-pretty-print.h" #include "ipa-utils.h" #include "gimple.h" +#include "ipa-inline.h" /* Pointer set of all call targets appearing in the cache. */ static pointer_set_t *cached_polymorphic_call_targets; @@ -728,4 +731,267 @@ update_type_inheritance_graph (void) get_odr_type (method_class_type (TREE_TYPE (n->symbol.decl)), true); timevar_pop (TV_IPA_INHERITANCE); } + + +/* Return true if N looks like likely target of a polymorphic call. + Rule out cxa_pure_virtual, noreturns, function declared cold and + other obvious cases. */ + +bool +likely_target_p (struct cgraph_node *n) +{ + int flags; + /* cxa_pure_virtual and similar things are not likely. */ + if (TREE_CODE (TREE_TYPE (n->symbol.decl)) != METHOD_TYPE) + return false; + flags = flags_from_decl_or_type (n->symbol.decl); + if (flags & ECF_NORETURN) + return false; + if (lookup_attribute ("cold", + DECL_ATTRIBUTES (n->symbol.decl))) + return false; + if (n->frequency < NODE_FREQUENCY_NORMAL) + return false; + return true; +} + +/* The ipa-devirt pass. + This performs very trivial devirtualization: + 1) when polymorphic call is known to have precisely one target, + turn it into direct call + 2) when polymorphic call has only one likely target in the unit, + turn it into speculative call. */ + +static unsigned int +ipa_devirt (void) +{ + struct cgraph_node *n; + struct pointer_set_t *bad_call_targets = pointer_set_create (); + struct cgraph_edge *e; + + int npolymorphic = 0, nspeculated = 0, nconverted = 0, ncold = 0; + int nmultiple = 0, noverwritable = 0, ndevirtualized = 0, nnotdefined = 0; + int nwrong = 0, nok = 0, nexternal = 0;; + + FOR_EACH_DEFINED_FUNCTION (n) + { + bool update = false; + if (dump_file && n->indirect_calls) + fprintf (dump_file, "\n\nProcesing function %s/%i\n", + cgraph_node_name (n), n->symbol.order); + for (e = n->indirect_calls; e; e = e->next_callee) + if (e->indirect_info->polymorphic) + { + struct cgraph_node *likely_target = NULL; + void *cache_token; + bool final; + vec <cgraph_node *>targets + = possible_polymorphic_call_targets + (e, &final, &cache_token); + unsigned int i; + + if (dump_file) + dump_possible_polymorphic_call_targets + (dump_file, e); + npolymorphic++; + + if (final) + { + gcc_assert (targets.length()); + if (targets.length() == 1) + { + if (dump_file) + fprintf (dump_file, + "Devirtualizing call in %s/%i to %s/%i\n", + cgraph_node_name (n), n->symbol.order, + cgraph_node_name (targets[0]), targets[0]->symbol.order); + cgraph_make_edge_direct (e, targets[0]); + ndevirtualized++; + update = true; + continue; + } + } + if (!flag_devirtualize_speculatively) + continue; + if (!cgraph_maybe_hot_edge_p (e)) + { + if (dump_file) + fprintf (dump_file, "Call is cold\n"); + ncold++; + continue; + } + if (e->speculative) + { + if (dump_file) + fprintf (dump_file, "Call is aready speculated\n"); + nspeculated++; + + /* When dumping see if we agree with speculation. */ + if (!dump_file) + continue; + } + if (pointer_set_contains (bad_call_targets, + cache_token)) + { + if (dump_file) + fprintf (dump_file, "Target list is known to be useless\n"); + nmultiple++; + continue; + } + for (i = 0; i < targets.length(); i++) + if (likely_target_p (targets[i])) + { + if (likely_target) + { + likely_target = NULL; + if (dump_file) + fprintf (dump_file, "More than one likely target\n"); + nmultiple++; + break; + } + likely_target = targets[i]; + } + if (!likely_target) + { + pointer_set_insert (bad_call_targets, cache_token); + continue; + } + /* This is reached only when dumping; check if we agree or disagree + with the speculation. */ + if (e->speculative) + { + struct cgraph_edge *e2; + struct ipa_ref *ref; + cgraph_speculative_call_info (e, e2, e, ref); + if (cgraph_function_or_thunk_node (e2->callee, NULL) + == cgraph_function_or_thunk_node (likely_target, NULL)) + { + fprintf (dump_file, "We agree with speculation\n"); + nok++; + } + else + { + fprintf (dump_file, "We disagree with speculation\n"); + nwrong++; + } + continue; + } + if (!likely_target->symbol.definition) + { + if (dump_file) + fprintf (dump_file, "Target is not an definition\n"); + nnotdefined++; + continue; + } + /* Do not introduce new references to external symbols. While we + can handle these just well, it is common for programs to + incorrectly with headers defining methods they are linked + with. */ + if (DECL_EXTERNAL (likely_target->symbol.decl)) + { + if (dump_file) + fprintf (dump_file, "Target is external\n"); + nexternal++; + continue; + } + if (cgraph_function_body_availability (likely_target) + <= AVAIL_OVERWRITABLE + && symtab_can_be_discarded ((symtab_node) likely_target)) + { + if (dump_file) + fprintf (dump_file, "Target is overwritable\n"); + noverwritable++; + continue; + } + else + { + if (dump_file) + fprintf (dump_file, + "Speculatively devirtualizing call in %s/%i to %s/%i\n", + cgraph_node_name (n), n->symbol.order, + cgraph_node_name (likely_target), + likely_target->symbol.order); + if (!symtab_can_be_discarded ((symtab_node) likely_target)) + likely_target = cgraph (symtab_nonoverwritable_alias ((symtab_node)likely_target)); + nconverted++; + update = true; + cgraph_turn_edge_to_speculative + (e, likely_target, e->count * 8 / 10, e->frequency * 8 / 10); + } + } + if (update) + inline_update_overall_summary (n); + } + pointer_set_destroy (bad_call_targets); + + if (dump_file) + fprintf (dump_file, + "%i polymorphic calls, %i devirtualized," + " %i speculatively devirtualized, %i cold\n" + "%i have multiple targets, %i overwritable," + " %i already speculated (%i agree, %i disagree)," + " %i external, %i not defined\n", + npolymorphic, ndevirtualized, nconverted, ncold, + nmultiple, noverwritable, nspeculated, nok, nwrong, + nexternal, nnotdefined); + return ndevirtualized ? TODO_remove_functions : 0; +} + +/* Gate for IPCP optimization. */ + +static bool +gate_ipa_devirt (void) +{ + /* FIXME: We should remove the optimize check after we ensure we never run + IPA passes when not optimizing. */ + return (flag_devirtualize || flag_devirtualize_speculatively) && !in_lto_p; +} + +namespace { + +const pass_data pass_data_ipa_devirt = +{ + IPA_PASS, /* type */ + "devirt", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + true, /* has_gate */ + true, /* has_execute */ + TV_IPA_DEVIRT, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + ( TODO_dump_symtab ), /* todo_flags_finish */ +}; + +class pass_ipa_devirt : public ipa_opt_pass_d +{ +public: + pass_ipa_devirt(gcc::context *ctxt) + : ipa_opt_pass_d(pass_data_ipa_devirt, ctxt, + NULL, /* generate_summary */ + NULL, /* write_summary */ + NULL, /* read_summary */ + NULL, /* write_optimization_summary */ + NULL, /* read_optimization_summary */ + NULL, /* stmt_fixup */ + 0, /* function_transform_todo_flags_start */ + NULL, /* function_transform */ + NULL) /* variable_transform */ + {} + + /* opt_pass methods: */ + bool gate () { return gate_ipa_devirt (); } + unsigned int execute () { return ipa_devirt (); } + +}; // class pass_ipa_devirt + +} // anon namespace + +ipa_opt_pass_d * +make_pass_ipa_devirt (gcc::context *ctxt) +{ + return new pass_ipa_devirt (ctxt); +} + #include "gt-ipa-devirt.h" @@ -479,6 +479,7 @@ static const struct default_options default_options_table[] = { OPT_LEVELS_2_PLUS, OPT_ftree_switch_conversion, NULL, 1 }, { OPT_LEVELS_2_PLUS, OPT_fipa_cp, NULL, 1 }, { OPT_LEVELS_2_PLUS, OPT_fdevirtualize, NULL, 1 }, + { OPT_LEVELS_2_PLUS, OPT_fdevirtualize_speculatively, NULL, 1 }, { OPT_LEVELS_2_PLUS, OPT_fipa_sra, NULL, 1 }, { OPT_LEVELS_2_PLUS, OPT_falign_loops, NULL, 1 }, { OPT_LEVELS_2_PLUS, OPT_falign_jumps, NULL, 1 }, @@ -1665,6 +1666,11 @@ common_handle_option (struct gcc_options *opts, opts->x_flag_vect_cost_model = value; if (!opts_set->x_flag_tree_loop_distribute_patterns) opts->x_flag_tree_loop_distribute_patterns = value; + /* Indirect call profiling should do all useful transformations + speculative devirutalization does. */ + if (!opts_set->x_flag_devirtualize_speculatively + && opts->x_flag_value_profile_transformations) + opts->x_flag_devirtualize_speculatively = false; break; case OPT_fprofile_generate_: diff --git a/gcc/passes.def b/gcc/passes.def index aa45d51..736a28b 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -104,6 +104,7 @@ along with GCC; see the file COPYING3. If not see INSERT_PASSES_AFTER (all_regular_ipa_passes) NEXT_PASS (pass_ipa_whole_program_visibility); NEXT_PASS (pass_ipa_profile); + NEXT_PASS (pass_ipa_devirt); NEXT_PASS (pass_ipa_cp); NEXT_PASS (pass_ipa_cdtor_merge); NEXT_PASS (pass_ipa_inline); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9cbc427..d36b9f5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2013-08-31 Jan Hubicka <jh@suse.cz> + * g++.dg/ipa/devirt-11.C: Use -fno-devirtualize-speuclatively + * g++.dg/tree-ssa/pr45453.C: Likewise. + +2013-08-31 Jan Hubicka <jh@suse.cz> + * gcc.dg/fork-instrumentation.c: New testcase. 2013-08-30 Uros Bizjak <ubizjak@gmail.com> diff --git a/gcc/testsuite/g++.dg/ipa/devirt-11.C b/gcc/testsuite/g++.dg/ipa/devirt-11.C index c139f8f..53f95bb 100644 --- a/gcc/testsuite/g++.dg/ipa/devirt-11.C +++ b/gcc/testsuite/g++.dg/ipa/devirt-11.C @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-ipa-inline" } */ +/* { dg-options "-O2 -fdump-ipa-inline -fno-devirtualize-speuclatively" } */ int baz (); struct A { diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr45453.C b/gcc/testsuite/g++.dg/tree-ssa/pr45453.C index 78c6460..c8ef895 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/pr45453.C +++ b/gcc/testsuite/g++.dg/tree-ssa/pr45453.C @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-options "-O2 -fdump-tree-optimized -fno-devirtualize-speculatively" } */ struct S { S(); diff --git a/gcc/timevar.def b/gcc/timevar.def index bd1ee76..5fe9095 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -66,6 +66,7 @@ DEFTIMEVAR (TV_CGRAPH , "callgraph construction") DEFTIMEVAR (TV_CGRAPHOPT , "callgraph optimization") DEFTIMEVAR (TV_IPA_INHERITANCE , "ipa inheritance graph") DEFTIMEVAR (TV_IPA_VIRTUAL_CALL , "ipa virtual call target") +DEFTIMEVAR (TV_IPA_DEVIRT , "ipa devirtualization") DEFTIMEVAR (TV_IPA_CONSTANT_PROP , "ipa cp") DEFTIMEVAR (TV_IPA_INLINING , "ipa inlining heuristics") DEFTIMEVAR (TV_IPA_FNSPLIT , "ipa function splitting") diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index a6d8a83..ea1a62f 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -468,6 +468,7 @@ extern simple_ipa_opt_pass *make_pass_ipa_free_lang_data (gcc::context *ctxt); extern simple_ipa_opt_pass *make_pass_ipa_free_inline_summary (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_cp (gcc::context *ctxt); +extern ipa_opt_pass_d *make_pass_ipa_devirt (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_reference (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_pure_const (gcc::context *ctxt); extern simple_ipa_opt_pass *make_pass_ipa_pta (gcc::context *ctxt); |