aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2013-09-01 17:14:24 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2013-09-01 15:14:24 +0000
commitbbc9396b62a65e8ecc67bb2f8df870e2b5040ac7 (patch)
treea04f98f7e7873d1c147343271471b27491c59a96
parent0cea211ebd67d10e93649074d348d12df67c4d97 (diff)
downloadgcc-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/ChangeLog18
-rw-r--r--gcc/common.opt6
-rw-r--r--gcc/doc/invoke.texi13
-rw-r--r--gcc/ipa-devirt.c266
-rw-r--r--gcc/opts.c6
-rw-r--r--gcc/passes.def1
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-11.C2
-rw-r--r--gcc/testsuite/g++.dg/tree-ssa/pr45453.C2
-rw-r--r--gcc/timevar.def1
-rw-r--r--gcc/tree-pass.h1
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"
diff --git a/gcc/opts.c b/gcc/opts.c
index 133fe0f..6b6652d 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -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);