Commit 5058c037 by Jan Hubicka Committed by Jan Hubicka

ipa-inline-analysis.c (redirect_to_unreachable): New function.

	* ipa-inline-analysis.c (redirect_to_unreachable): New function.
	(edge_set_predicate): Use it to mark unreachable edges.
	(inline_summary_t::duplicate): Remove unnecesary code.
	(remap_edge_summaries): Likewise.
	(dump_inline_summary): Report contains_cilk_spawn.
	(compute_inline_parameters): Compute contains_cilk_spawn.
	(inline_read_section, inline_write_summary): Stream
	contains_cilk_spawn.
	* ipa-inline.c (can_inline_edge_p): Do not tuch 
	DECL_STRUCT_FUNCTION that may not be available;
	use CIF_CILK_SPAWN for cilk; fix optimization attribute checks;
	remove check for callee_fun->can_throw_non_call_exceptions and
	replace it by optimization attribute check; check for flag_exceptions.
	* ipa-inline-transform.c (inline_call): Maintain
	DECL_FUNCTION_PERSONALITY
	* ipa-inline.h (inline_summary): Add contains_cilk_spawn.

From-SVN: r221706
parent 08227658
2015-03-26 Jan Hubicka <hubicka@ucw.cz>
* ipa-inline-analysis.c (redirect_to_unreachable): New function.
(edge_set_predicate): Use it to mark unreachable edges.
(inline_summary_t::duplicate): Remove unnecesary code.
(remap_edge_summaries): Likewise.
(dump_inline_summary): Report contains_cilk_spawn.
(compute_inline_parameters): Compute contains_cilk_spawn.
(inline_read_section, inline_write_summary): Stream
contains_cilk_spawn.
* ipa-inline.c (can_inline_edge_p): Do not tuch
DECL_STRUCT_FUNCTION that may not be available;
use CIF_CILK_SPAWN for cilk; fix optimization attribute checks;
remove check for callee_fun->can_throw_non_call_exceptions and
replace it by optimization attribute check; check for flag_exceptions.
* ipa-inline-transform.c (inline_call): Maintain
DECL_FUNCTION_PERSONALITY
* ipa-inline.h (inline_summary): Add contains_cilk_spawn.
2015-03-26 Jakub Jelinek <jakub@redhat.com> 2015-03-26 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/65551 PR tree-optimization/65551
......
...@@ -760,6 +760,31 @@ account_size_time (struct inline_summary *summary, int size, int time, ...@@ -760,6 +760,31 @@ account_size_time (struct inline_summary *summary, int size, int time,
} }
} }
/* We proved E to be unreachable, redirect it to __bultin_unreachable. */
static void
redirect_to_unreachable (struct cgraph_edge *e)
{
struct cgraph_node *callee = !e->inline_failed ? e->callee : NULL;
struct inline_edge_summary *es = inline_edge_summary (e);
if (e->speculative)
e->resolve_speculation (builtin_decl_implicit (BUILT_IN_UNREACHABLE));
if (!e->callee)
e->make_direct (cgraph_node::get_create
(builtin_decl_implicit (BUILT_IN_UNREACHABLE)));
else
e->redirect_callee (cgraph_node::get_create
(builtin_decl_implicit (BUILT_IN_UNREACHABLE)));
e->inline_failed = CIF_UNREACHABLE;
e->frequency = 0;
e->count = 0;
es->call_stmt_size = 0;
es->call_stmt_time = 0;
if (callee)
callee->remove_symbol_and_inline_clones ();
}
/* Set predicate for edge E. */ /* Set predicate for edge E. */
static void static void
...@@ -769,18 +794,8 @@ edge_set_predicate (struct cgraph_edge *e, struct predicate *predicate) ...@@ -769,18 +794,8 @@ edge_set_predicate (struct cgraph_edge *e, struct predicate *predicate)
/* If the edge is determined to be never executed, redirect it /* If the edge is determined to be never executed, redirect it
to BUILTIN_UNREACHABLE to save inliner from inlining into it. */ to BUILTIN_UNREACHABLE to save inliner from inlining into it. */
if (predicate && false_predicate_p (predicate) && e->callee) if (predicate && false_predicate_p (predicate))
{ redirect_to_unreachable (e);
struct cgraph_node *callee = !e->inline_failed ? e->callee : NULL;
e->redirect_callee (cgraph_node::get_create
(builtin_decl_implicit (BUILT_IN_UNREACHABLE)));
e->inline_failed = CIF_UNREACHABLE;
es->call_stmt_size = 0;
es->call_stmt_time = 0;
if (callee)
callee->remove_symbol_and_inline_clones ();
}
if (predicate && !true_predicate_p (predicate)) if (predicate && !true_predicate_p (predicate))
{ {
if (!es->predicate) if (!es->predicate)
...@@ -1228,10 +1243,7 @@ inline_summary_t::duplicate (cgraph_node *src, ...@@ -1228,10 +1243,7 @@ inline_summary_t::duplicate (cgraph_node *src,
info); info);
if (false_predicate_p (&new_predicate) if (false_predicate_p (&new_predicate)
&& !false_predicate_p (es->predicate)) && !false_predicate_p (es->predicate))
{ optimized_out_size += es->call_stmt_size * INLINE_SIZE_SCALE;
optimized_out_size += es->call_stmt_size * INLINE_SIZE_SCALE;
edge->frequency = 0;
}
edge_set_predicate (edge, &new_predicate); edge_set_predicate (edge, &new_predicate);
} }
...@@ -1250,10 +1262,7 @@ inline_summary_t::duplicate (cgraph_node *src, ...@@ -1250,10 +1262,7 @@ inline_summary_t::duplicate (cgraph_node *src,
info); info);
if (false_predicate_p (&new_predicate) if (false_predicate_p (&new_predicate)
&& !false_predicate_p (es->predicate)) && !false_predicate_p (es->predicate))
{ optimized_out_size += es->call_stmt_size * INLINE_SIZE_SCALE;
optimized_out_size += es->call_stmt_size * INLINE_SIZE_SCALE;
edge->frequency = 0;
}
edge_set_predicate (edge, &new_predicate); edge_set_predicate (edge, &new_predicate);
} }
remap_hint_predicate_after_duplication (&info->loop_iterations, remap_hint_predicate_after_duplication (&info->loop_iterations,
...@@ -1441,6 +1450,8 @@ dump_inline_summary (FILE *f, struct cgraph_node *node) ...@@ -1441,6 +1450,8 @@ dump_inline_summary (FILE *f, struct cgraph_node *node)
fprintf (f, " always_inline"); fprintf (f, " always_inline");
if (s->inlinable) if (s->inlinable)
fprintf (f, " inlinable"); fprintf (f, " inlinable");
if (s->contains_cilk_spawn)
fprintf (f, " contains_cilk_spawn");
fprintf (f, "\n self time: %i\n", s->self_time); fprintf (f, "\n self time: %i\n", s->self_time);
fprintf (f, " global time: %i\n", s->time); fprintf (f, " global time: %i\n", s->time);
fprintf (f, " self size: %i\n", s->self_size); fprintf (f, " self size: %i\n", s->self_size);
...@@ -2925,6 +2936,8 @@ compute_inline_parameters (struct cgraph_node *node, bool early) ...@@ -2925,6 +2936,8 @@ compute_inline_parameters (struct cgraph_node *node, bool early)
else else
info->inlinable = tree_inlinable_function_p (node->decl); info->inlinable = tree_inlinable_function_p (node->decl);
info->contains_cilk_spawn = fn_contains_cilk_spawn_p (cfun);
/* Type attributes can use parameter indices to describe them. */ /* Type attributes can use parameter indices to describe them. */
if (TYPE_ATTRIBUTES (TREE_TYPE (node->decl))) if (TYPE_ATTRIBUTES (TREE_TYPE (node->decl)))
node->local.can_change_signature = false; node->local.can_change_signature = false;
...@@ -3487,14 +3500,6 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge, ...@@ -3487,14 +3500,6 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
es->predicate, operand_map, offset_map, es->predicate, operand_map, offset_map,
possible_truths, toplev_predicate); possible_truths, toplev_predicate);
edge_set_predicate (e, &p); edge_set_predicate (e, &p);
/* TODO: We should remove the edge for code that will be
optimized out, but we need to keep verifiers and tree-inline
happy. Make it cold for now. */
if (false_predicate_p (&p))
{
e->count = 0;
e->frequency = 0;
}
} }
else else
edge_set_predicate (e, toplev_predicate); edge_set_predicate (e, toplev_predicate);
...@@ -3516,14 +3521,6 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge, ...@@ -3516,14 +3521,6 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
es->predicate, operand_map, offset_map, es->predicate, operand_map, offset_map,
possible_truths, toplev_predicate); possible_truths, toplev_predicate);
edge_set_predicate (e, &p); edge_set_predicate (e, &p);
/* TODO: We should remove the edge for code that will be optimized
out, but we need to keep verifiers and tree-inline happy.
Make it cold for now. */
if (false_predicate_p (&p))
{
e->count = 0;
e->frequency = 0;
}
} }
else else
edge_set_predicate (e, toplev_predicate); edge_set_predicate (e, toplev_predicate);
...@@ -4228,6 +4225,7 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data, ...@@ -4228,6 +4225,7 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
bp = streamer_read_bitpack (&ib); bp = streamer_read_bitpack (&ib);
info->inlinable = bp_unpack_value (&bp, 1); info->inlinable = bp_unpack_value (&bp, 1);
info->contains_cilk_spawn = bp_unpack_value (&bp, 1);
count2 = streamer_read_uhwi (&ib); count2 = streamer_read_uhwi (&ib);
gcc_assert (!info->conds); gcc_assert (!info->conds);
...@@ -4393,6 +4391,7 @@ inline_write_summary (void) ...@@ -4393,6 +4391,7 @@ inline_write_summary (void)
streamer_write_hwi (ob, info->self_time); streamer_write_hwi (ob, info->self_time);
bp = bitpack_create (ob->main_stream); bp = bitpack_create (ob->main_stream);
bp_pack_value (&bp, info->inlinable, 1); bp_pack_value (&bp, info->inlinable, 1);
bp_pack_value (&bp, info->contains_cilk_spawn, 1);
streamer_write_bitpack (&bp); streamer_write_bitpack (&bp);
streamer_write_uhwi (ob, vec_safe_length (info->conds)); streamer_write_uhwi (ob, vec_safe_length (info->conds));
for (i = 0; vec_safe_iterate (info->conds, i, &c); i++) for (i = 0; vec_safe_iterate (info->conds, i, &c); i++)
......
...@@ -322,6 +322,10 @@ inline_call (struct cgraph_edge *e, bool update_original, ...@@ -322,6 +322,10 @@ inline_call (struct cgraph_edge *e, bool update_original,
if (to->global.inlined_to) if (to->global.inlined_to)
to = to->global.inlined_to; to = to->global.inlined_to;
if (DECL_FUNCTION_PERSONALITY (callee->decl))
DECL_FUNCTION_PERSONALITY (to->decl)
= DECL_FUNCTION_PERSONALITY (callee->decl);
/* If aliases are involved, redirect edge to the actual destination and /* If aliases are involved, redirect edge to the actual destination and
possibly remove the aliases. */ possibly remove the aliases. */
if (e->callee != callee) if (e->callee != callee)
......
...@@ -142,7 +142,6 @@ along with GCC; see the file COPYING3. If not see ...@@ -142,7 +142,6 @@ along with GCC; see the file COPYING3. If not see
#include "ipa-utils.h" #include "ipa-utils.h"
#include "sreal.h" #include "sreal.h"
#include "auto-profile.h" #include "auto-profile.h"
#include "cilk.h"
#include "builtins.h" #include "builtins.h"
#include "fibonacci_heap.h" #include "fibonacci_heap.h"
#include "lto-streamer.h" #include "lto-streamer.h"
...@@ -329,8 +328,6 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, ...@@ -329,8 +328,6 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
tree caller_tree = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (caller->decl); tree caller_tree = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (caller->decl);
tree callee_tree tree callee_tree
= callee ? DECL_FUNCTION_SPECIFIC_OPTIMIZATION (callee->decl) : NULL; = callee ? DECL_FUNCTION_SPECIFIC_OPTIMIZATION (callee->decl) : NULL;
struct function *caller_fun = caller->get_fun ();
struct function *callee_fun = callee ? callee->get_fun () : NULL;
if (!callee->definition) if (!callee->definition)
{ {
...@@ -342,12 +339,6 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, ...@@ -342,12 +339,6 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
e->inline_failed = CIF_USES_COMDAT_LOCAL; e->inline_failed = CIF_USES_COMDAT_LOCAL;
inlinable = false; inlinable = false;
} }
else if (!inline_summaries->get (callee)->inlinable
|| (caller_fun && fn_contains_cilk_spawn_p (caller_fun)))
{
e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
inlinable = false;
}
else if (avail <= AVAIL_INTERPOSABLE) else if (avail <= AVAIL_INTERPOSABLE)
{ {
e->inline_failed = CIF_OVERWRITABLE; e->inline_failed = CIF_OVERWRITABLE;
...@@ -375,16 +366,6 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, ...@@ -375,16 +366,6 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
e->inline_failed = CIF_UNSPECIFIED; e->inline_failed = CIF_UNSPECIFIED;
inlinable = false; inlinable = false;
} }
/* Don't inline if the callee can throw non-call exceptions but the
caller cannot.
FIXME: this is obviously wrong for LTO where STRUCT_FUNCTION is missing.
Move the flag into cgraph node or mirror it in the inline summary. */
else if (callee_fun && callee_fun->can_throw_non_call_exceptions
&& !(caller_fun && caller_fun->can_throw_non_call_exceptions))
{
e->inline_failed = CIF_NON_CALL_EXCEPTIONS;
inlinable = false;
}
/* Check compatibility of target optimization options. */ /* Check compatibility of target optimization options. */
else if (!targetm.target_option.can_inline_p (caller->decl, else if (!targetm.target_option.can_inline_p (caller->decl,
callee->decl)) callee->decl))
...@@ -392,6 +373,16 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, ...@@ -392,6 +373,16 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
e->inline_failed = CIF_TARGET_OPTION_MISMATCH; e->inline_failed = CIF_TARGET_OPTION_MISMATCH;
inlinable = false; inlinable = false;
} }
else if (!inline_summaries->get (callee)->inlinable)
{
e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
inlinable = false;
}
else if (inline_summaries->get (caller)->contains_cilk_spawn)
{
e->inline_failed = CIF_CILK_SPAWN;
inlinable = false;
}
/* Don't inline a function with mismatched sanitization attributes. */ /* Don't inline a function with mismatched sanitization attributes. */
else if (!sanitize_attrs_match_for_inline_p (caller->decl, callee->decl)) else if (!sanitize_attrs_match_for_inline_p (caller->decl, callee->decl))
{ {
...@@ -416,38 +407,51 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, ...@@ -416,38 +407,51 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
/* Strictly speaking only when the callee contains signed integer /* Strictly speaking only when the callee contains signed integer
math where overflow is undefined. */ math where overflow is undefined. */
if ((opt_for_fn (caller->decl, flag_strict_overflow) if ((opt_for_fn (caller->decl, flag_strict_overflow)
!= opt_for_fn (caller->decl, flag_strict_overflow)) != opt_for_fn (callee->decl, flag_strict_overflow))
|| (opt_for_fn (caller->decl, flag_wrapv) || (opt_for_fn (caller->decl, flag_wrapv)
!= opt_for_fn (caller->decl, flag_wrapv)) != opt_for_fn (callee->decl, flag_wrapv))
|| (opt_for_fn (caller->decl, flag_trapv) || (opt_for_fn (caller->decl, flag_trapv)
!= opt_for_fn (caller->decl, flag_trapv)) != opt_for_fn (callee->decl, flag_trapv))
/* Strictly speaking only when the callee contains memory /* Strictly speaking only when the callee contains memory
accesses that are not using alias-set zero anyway. */ accesses that are not using alias-set zero anyway. */
|| (opt_for_fn (caller->decl, flag_strict_aliasing) || (opt_for_fn (caller->decl, flag_strict_aliasing)
!= opt_for_fn (caller->decl, flag_strict_aliasing)) != opt_for_fn (callee->decl, flag_strict_aliasing))
/* Strictly speaking only when the callee uses FP math. */ /* Strictly speaking only when the callee uses FP math. */
|| (opt_for_fn (caller->decl, flag_rounding_math) || (opt_for_fn (caller->decl, flag_rounding_math)
!= opt_for_fn (caller->decl, flag_rounding_math)) != opt_for_fn (callee->decl, flag_rounding_math))
|| (opt_for_fn (caller->decl, flag_trapping_math) || (opt_for_fn (caller->decl, flag_trapping_math)
!= opt_for_fn (caller->decl, flag_trapping_math)) != opt_for_fn (callee->decl, flag_trapping_math))
|| (opt_for_fn (caller->decl, flag_unsafe_math_optimizations) || (opt_for_fn (caller->decl, flag_unsafe_math_optimizations)
!= opt_for_fn (caller->decl, flag_unsafe_math_optimizations)) != opt_for_fn (callee->decl, flag_unsafe_math_optimizations))
|| (opt_for_fn (caller->decl, flag_finite_math_only) || (opt_for_fn (caller->decl, flag_finite_math_only)
!= opt_for_fn (caller->decl, flag_finite_math_only)) != opt_for_fn (callee->decl, flag_finite_math_only))
|| (opt_for_fn (caller->decl, flag_signaling_nans) || (opt_for_fn (caller->decl, flag_signaling_nans)
!= opt_for_fn (caller->decl, flag_signaling_nans)) != opt_for_fn (callee->decl, flag_signaling_nans))
|| (opt_for_fn (caller->decl, flag_cx_limited_range) || (opt_for_fn (caller->decl, flag_cx_limited_range)
!= opt_for_fn (caller->decl, flag_cx_limited_range)) != opt_for_fn (callee->decl, flag_cx_limited_range))
|| (opt_for_fn (caller->decl, flag_signed_zeros) || (opt_for_fn (caller->decl, flag_signed_zeros)
!= opt_for_fn (caller->decl, flag_signed_zeros)) != opt_for_fn (callee->decl, flag_signed_zeros))
|| (opt_for_fn (caller->decl, flag_associative_math) || (opt_for_fn (caller->decl, flag_associative_math)
!= opt_for_fn (caller->decl, flag_associative_math)) != opt_for_fn (callee->decl, flag_associative_math))
|| (opt_for_fn (caller->decl, flag_reciprocal_math) || (opt_for_fn (caller->decl, flag_reciprocal_math)
!= opt_for_fn (caller->decl, flag_reciprocal_math)) != opt_for_fn (callee->decl, flag_reciprocal_math))
/* We do not want to make code compiled with exceptions to be brought
into a non-EH function unless we know that the callee does not
throw. This is tracked by DECL_FUNCTION_PERSONALITY. */
|| (opt_for_fn (caller->decl, flag_non_call_exceptions)
!= opt_for_fn (callee->decl, flag_non_call_exceptions)
/* TODO: We also may allow bringing !flag_non_call_exceptions
to flag_non_call_exceptions function, but that may need
extra work in tree-inline to add the extra EH edges. */
&& (!opt_for_fn (callee->decl, flag_non_call_exceptions)
|| DECL_FUNCTION_PERSONALITY (callee->decl)))
|| (!opt_for_fn (caller->decl, flag_exceptions)
&& opt_for_fn (callee->decl, flag_exceptions)
&& DECL_FUNCTION_PERSONALITY (callee->decl))
/* Strictly speaking only when the callee contains function /* Strictly speaking only when the callee contains function
calls that may end up setting errno. */ calls that may end up setting errno. */
|| (opt_for_fn (caller->decl, flag_errno_math) || (opt_for_fn (caller->decl, flag_errno_math)
!= opt_for_fn (caller->decl, flag_errno_math)) != opt_for_fn (callee->decl, flag_errno_math))
/* When devirtualization is diabled for callee, it is not safe /* When devirtualization is diabled for callee, it is not safe
to inline it as we possibly mangled the type info. to inline it as we possibly mangled the type info.
Allow early inlining of always inlines. */ Allow early inlining of always inlines. */
......
...@@ -126,6 +126,9 @@ struct GTY(()) inline_summary ...@@ -126,6 +126,9 @@ struct GTY(()) inline_summary
/* False when there something makes inlining impossible (such as va_arg). */ /* False when there something makes inlining impossible (such as va_arg). */
unsigned inlinable : 1; unsigned inlinable : 1;
/* True when function contains cilk spawn (and thus we can not inline
into it). */
unsigned contains_cilk_spawn : 1;
/* Information about function that will result after applying all the /* Information about function that will result after applying all the
inline decisions present in the callgraph. Generally kept up to inline decisions present in the callgraph. Generally kept up to
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment