Commit 818b88a7 by Jan Hubicka Committed by Jan Hubicka

ipa-inline-analysis.c (reset_inline_summary): Clear fp_expressions


	* ipa-inline-analysis.c (reset_inline_summary): Clear fp_expressions
	(dump_inline_summary): Dump it.
	(fp_expression_p): New predicate.
	(estimate_function_body_sizes): Use it.
	(inline_merge_summary): Merge fp_expressions.
	(inline_read_section): Read fp_expressions.
	(inline_write_summary): Write fp_expressions.
	* ipa-inline.c (can_inline_edge_p): Permit inlining across fp math
	codegen boundary if either caller or callee is !fp_expressions.
	* ipa-inline.h (inline_summary): Add fp_expressions.
	* ipa-inline-transform.c (inline_call): When inlining !fp_expressions
	to fp_expressions be sure the fp generation flags are updated.

	* gcc.dg/ipa/inline-8.c: New testcase.

From-SVN: r235766
parent dd77684f
2016-05-02 Jan Hubicka <hubicka@ucw.cz>
* ipa-inline-analysis.c (reset_inline_summary): Clear fp_expressions
(dump_inline_summary): Dump it.
(fp_expression_p): New predicate.
(estimate_function_body_sizes): Use it.
(inline_merge_summary): Merge fp_expressions.
(inline_read_section): Read fp_expressions.
(inline_write_summary): Write fp_expressions.
* ipa-inline.c (can_inline_edge_p): Permit inlining across fp math
codegen boundary if either caller or callee is !fp_expressions.
* ipa-inline.h (inline_summary): Add fp_expressions.
* ipa-inline-transform.c (inline_call): When inlining !fp_expressions
to fp_expressions be sure the fp generation flags are updated.
2016-05-02 Jakub Jelinek <jakub@redhat.com> 2016-05-02 Jakub Jelinek <jakub@redhat.com>
PR rtl-optimization/70467 PR rtl-optimization/70467
......
...@@ -850,7 +850,8 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, ...@@ -850,7 +850,8 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
if (known_aggs.exists ()) if (known_aggs.exists ())
{ {
agg = known_aggs[c->operand_num]; agg = known_aggs[c->operand_num];
val = ipa_find_agg_cst_for_param (agg, c->offset, c->by_ref); val = ipa_find_agg_cst_for_param (agg, known_vals[c->operand_num],
c->offset, c->by_ref);
} }
else else
val = NULL_TREE; val = NULL_TREE;
...@@ -1069,6 +1070,7 @@ reset_inline_summary (struct cgraph_node *node, ...@@ -1069,6 +1070,7 @@ reset_inline_summary (struct cgraph_node *node,
reset_inline_edge_summary (e); reset_inline_edge_summary (e);
for (e = node->indirect_calls; e; e = e->next_callee) for (e = node->indirect_calls; e; e = e->next_callee)
reset_inline_edge_summary (e); reset_inline_edge_summary (e);
info->fp_expressions = false;
} }
/* Hook that is called by cgraph.c when a node is removed. */ /* Hook that is called by cgraph.c when a node is removed. */
...@@ -1423,6 +1425,8 @@ dump_inline_summary (FILE *f, struct cgraph_node *node) ...@@ -1423,6 +1425,8 @@ dump_inline_summary (FILE *f, struct cgraph_node *node)
fprintf (f, " inlinable"); fprintf (f, " inlinable");
if (s->contains_cilk_spawn) if (s->contains_cilk_spawn)
fprintf (f, " contains_cilk_spawn"); fprintf (f, " contains_cilk_spawn");
if (s->fp_expressions)
fprintf (f, " fp_expression");
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);
...@@ -2459,6 +2463,21 @@ clobber_only_eh_bb_p (basic_block bb, bool need_eh = true) ...@@ -2459,6 +2463,21 @@ clobber_only_eh_bb_p (basic_block bb, bool need_eh = true)
return true; return true;
} }
/* Return true if STMT compute a floating point expression that may be affected
by -ffast-math and similar flags. */
static bool
fp_expression_p (gimple *stmt)
{
ssa_op_iter i;
tree op;
FOR_EACH_SSA_TREE_OPERAND (op, stmt, i, SSA_OP_DEF|SSA_OP_USE)
if (FLOAT_TYPE_P (TREE_TYPE (op)))
return true;
return false;
}
/* Compute function body size parameters for NODE. /* Compute function body size parameters for NODE.
When EARLY is true, we compute only simple summaries without When EARLY is true, we compute only simple summaries without
non-trivial predicates to drive the early inliner. */ non-trivial predicates to drive the early inliner. */
...@@ -2733,6 +2752,13 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early) ...@@ -2733,6 +2752,13 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
this_time * (2 - prob), &p); this_time * (2 - prob), &p);
} }
if (!info->fp_expressions && fp_expression_p (stmt))
{
info->fp_expressions = true;
if (dump_file)
fprintf (dump_file, " fp_expression set\n");
}
gcc_assert (time >= 0); gcc_assert (time >= 0);
gcc_assert (size >= 0); gcc_assert (size >= 0);
} }
...@@ -3577,6 +3603,8 @@ inline_merge_summary (struct cgraph_edge *edge) ...@@ -3577,6 +3603,8 @@ inline_merge_summary (struct cgraph_edge *edge)
else else
toplev_predicate = true_predicate (); toplev_predicate = true_predicate ();
info->fp_expressions |= callee_info->fp_expressions;
if (callee_info->conds) if (callee_info->conds)
evaluate_properties_for_edge (edge, true, &clause, NULL, NULL, NULL); evaluate_properties_for_edge (edge, true, &clause, NULL, NULL, NULL);
if (ipa_node_params_sum && callee_info->conds) if (ipa_node_params_sum && callee_info->conds)
...@@ -4229,6 +4257,7 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data, ...@@ -4229,6 +4257,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); info->contains_cilk_spawn = bp_unpack_value (&bp, 1);
info->fp_expressions = bp_unpack_value (&bp, 1);
count2 = streamer_read_uhwi (&ib); count2 = streamer_read_uhwi (&ib);
gcc_assert (!info->conds); gcc_assert (!info->conds);
...@@ -4395,6 +4424,7 @@ inline_write_summary (void) ...@@ -4395,6 +4424,7 @@ inline_write_summary (void)
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); bp_pack_value (&bp, info->contains_cilk_spawn, 1);
bp_pack_value (&bp, info->fp_expressions, 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++)
......
...@@ -338,6 +338,63 @@ inline_call (struct cgraph_edge *e, bool update_original, ...@@ -338,6 +338,63 @@ inline_call (struct cgraph_edge *e, bool update_original,
DECL_FUNCTION_SPECIFIC_OPTIMIZATION (to->decl) DECL_FUNCTION_SPECIFIC_OPTIMIZATION (to->decl)
= build_optimization_node (&opts); = build_optimization_node (&opts);
} }
inline_summary *caller_info = inline_summaries->get (to);
inline_summary *callee_info = inline_summaries->get (callee);
if (!caller_info->fp_expressions && callee_info->fp_expressions)
{
caller_info->fp_expressions = true;
if (opt_for_fn (callee->decl, flag_rounding_math)
!= opt_for_fn (to->decl, flag_rounding_math)
|| opt_for_fn (callee->decl, flag_trapping_math)
!= opt_for_fn (to->decl, flag_trapping_math)
|| opt_for_fn (callee->decl, flag_unsafe_math_optimizations)
!= opt_for_fn (to->decl, flag_unsafe_math_optimizations)
|| opt_for_fn (callee->decl, flag_finite_math_only)
!= opt_for_fn (to->decl, flag_finite_math_only)
|| opt_for_fn (callee->decl, flag_signaling_nans)
!= opt_for_fn (to->decl, flag_signaling_nans)
|| opt_for_fn (callee->decl, flag_cx_limited_range)
!= opt_for_fn (to->decl, flag_cx_limited_range)
|| opt_for_fn (callee->decl, flag_signed_zeros)
!= opt_for_fn (to->decl, flag_signed_zeros)
|| opt_for_fn (callee->decl, flag_associative_math)
!= opt_for_fn (to->decl, flag_associative_math)
|| opt_for_fn (callee->decl, flag_reciprocal_math)
!= opt_for_fn (to->decl, flag_reciprocal_math)
|| opt_for_fn (callee->decl, flag_errno_math)
!= opt_for_fn (to->decl, flag_errno_math))
{
struct gcc_options opts = global_options;
cl_optimization_restore (&opts, opts_for_fn (to->decl));
opts.x_flag_rounding_math
= opt_for_fn (callee->decl, flag_rounding_math);
opts.x_flag_trapping_math
= opt_for_fn (callee->decl, flag_trapping_math);
opts.x_flag_unsafe_math_optimizations
= opt_for_fn (callee->decl, flag_unsafe_math_optimizations);
opts.x_flag_finite_math_only
= opt_for_fn (callee->decl, flag_finite_math_only);
opts.x_flag_signaling_nans
= opt_for_fn (callee->decl, flag_signaling_nans);
opts.x_flag_cx_limited_range
= opt_for_fn (callee->decl, flag_cx_limited_range);
opts.x_flag_signed_zeros
= opt_for_fn (callee->decl, flag_signed_zeros);
opts.x_flag_associative_math
= opt_for_fn (callee->decl, flag_associative_math);
opts.x_flag_reciprocal_math
= opt_for_fn (callee->decl, flag_reciprocal_math);
opts.x_flag_errno_math
= opt_for_fn (callee->decl, flag_errno_math);
if (dump_file)
fprintf (dump_file, "Copying FP flags from %s:%i to %s:%i\n",
callee->name (), callee->order, to->name (), to->order);
build_optimization_node (&opts);
DECL_FUNCTION_SPECIFIC_OPTIMIZATION (to->decl)
= build_optimization_node (&opts);
}
}
/* 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. */
......
...@@ -338,7 +338,7 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, ...@@ -338,7 +338,7 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
else if (e->call_stmt_cannot_inline_p) else if (e->call_stmt_cannot_inline_p)
{ {
if (e->inline_failed != CIF_FUNCTION_NOT_OPTIMIZED) if (e->inline_failed != CIF_FUNCTION_NOT_OPTIMIZED)
e->inline_failed = CIF_MISMATCHED_ARGUMENTS; e->inline_failed = e->caller->thunk.thunk_p ? CIF_THUNK : CIF_MISMATCHED_ARGUMENTS;
inlinable = false; inlinable = false;
} }
/* Don't inline if the functions have different EH personalities. */ /* Don't inline if the functions have different EH personalities. */
...@@ -396,6 +396,8 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, ...@@ -396,6 +396,8 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
(DECL_DISREGARD_INLINE_LIMITS (callee->decl) (DECL_DISREGARD_INLINE_LIMITS (callee->decl)
&& lookup_attribute ("always_inline", && lookup_attribute ("always_inline",
DECL_ATTRIBUTES (callee->decl))); DECL_ATTRIBUTES (callee->decl)));
inline_summary *caller_info = inline_summaries->get (caller);
inline_summary *callee_info = inline_summaries->get (callee);
/* Until GCC 4.9 we did not check the semantics alterning flags /* Until GCC 4.9 we did not check the semantics alterning flags
bellow and inline across optimization boundry. bellow and inline across optimization boundry.
...@@ -417,8 +419,10 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, ...@@ -417,8 +419,10 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
== !opt_for_fn (callee->decl, optimize) || !always_inline)) == !opt_for_fn (callee->decl, optimize) || !always_inline))
|| check_match (flag_wrapv) || check_match (flag_wrapv)
|| check_match (flag_trapv) || check_match (flag_trapv)
/* Strictly speaking only when the callee uses FP math. */ /* When caller or callee does FP math, be sure FP codegen flags
|| check_maybe_up (flag_rounding_math) compatible. */
|| ((caller_info->fp_expressions && callee_info->fp_expressions)
&& (check_maybe_up (flag_rounding_math)
|| check_maybe_up (flag_trapping_math) || check_maybe_up (flag_trapping_math)
|| check_maybe_down (flag_unsafe_math_optimizations) || check_maybe_down (flag_unsafe_math_optimizations)
|| check_maybe_down (flag_finite_math_only) || check_maybe_down (flag_finite_math_only)
...@@ -427,6 +431,9 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, ...@@ -427,6 +431,9 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
|| check_maybe_up (flag_signed_zeros) || check_maybe_up (flag_signed_zeros)
|| check_maybe_down (flag_associative_math) || check_maybe_down (flag_associative_math)
|| check_maybe_down (flag_reciprocal_math) || check_maybe_down (flag_reciprocal_math)
/* Strictly speaking only when the callee contains function
calls that may end up setting errno. */
|| check_maybe_up (flag_errno_math)))
/* We do not want to make code compiled with exceptions to be /* We do not want to make code compiled with exceptions to be
brought into a non-EH function unless we know that the callee brought into a non-EH function unless we know that the callee
does not throw. does not throw.
...@@ -435,9 +442,6 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, ...@@ -435,9 +442,6 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
&& DECL_FUNCTION_PERSONALITY (callee->decl)) && DECL_FUNCTION_PERSONALITY (callee->decl))
|| (check_maybe_up (flag_exceptions) || (check_maybe_up (flag_exceptions)
&& DECL_FUNCTION_PERSONALITY (callee->decl)) && DECL_FUNCTION_PERSONALITY (callee->decl))
/* Strictly speaking only when the callee contains function
calls that may end up setting errno. */
|| check_maybe_up (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. */
......
...@@ -132,6 +132,8 @@ struct GTY(()) inline_summary ...@@ -132,6 +132,8 @@ struct GTY(()) inline_summary
/* True wen there is only one caller of the function before small function /* True wen there is only one caller of the function before small function
inlining. */ inlining. */
unsigned int single_caller : 1; unsigned int single_caller : 1;
/* True if function contains any floating point expressions. */
unsigned int fp_expressions : 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
......
2016-05-02 Jan Hubicka <hubicka@ucw.cz>
* gcc.dg/ipa/inline-8.c: New testcase.
2016-05-02 Jakub Jelinek <jakub@redhat.com> 2016-05-02 Jakub Jelinek <jakub@redhat.com>
PR rtl-optimization/70467 PR rtl-optimization/70467
......
/* Verify that we do not inline isnanf test info -ffast-math code but that we
do inline trivial functions across -Ofast boundary. */
/* { dg-do run } */
/* { dg-options "-O2" } */
#include <math.h>
/* Can't be inlined because isnanf will be optimized out. */
int
cmp (float a)
{
return isnanf (a);
}
/* Can be inlined. */
int
move (int a)
{
return a;
}
float a;
void
set ()
{
a=nan("");
}
float b;
__attribute__ ((optimize("Ofast")))
int
main()
{
b++;
if (cmp(a))
__builtin_abort ();
float a = move (1);
if (!__builtin_constant_p (a))
__builtin_abort ();
return 0;
}
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