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
This commit is contained in:
parent
0cea211ebd
commit
bbc9396b62
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
266
gcc/ipa-devirt.c
266
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_:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
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.
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue