+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>
PR rtl-optimization/70467
if (known_aggs.exists ())
{
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
val = NULL_TREE;
reset_inline_edge_summary (e);
for (e = node->indirect_calls; e; e = e->next_callee)
reset_inline_edge_summary (e);
+ info->fp_expressions = false;
}
/* Hook that is called by cgraph.c when a node is removed. */
fprintf (f, " inlinable");
if (s->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, " global time: %i\n", s->time);
fprintf (f, " self size: %i\n", s->self_size);
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.
When EARLY is true, we compute only simple summaries without
non-trivial predicates to drive the early inliner. */
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 (size >= 0);
}
else
toplev_predicate = true_predicate ();
+ info->fp_expressions |= callee_info->fp_expressions;
+
if (callee_info->conds)
evaluate_properties_for_edge (edge, true, &clause, NULL, NULL, NULL);
if (ipa_node_params_sum && callee_info->conds)
bp = streamer_read_bitpack (&ib);
info->inlinable = 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);
gcc_assert (!info->conds);
bp = bitpack_create (ob->main_stream);
bp_pack_value (&bp, info->inlinable, 1);
bp_pack_value (&bp, info->contains_cilk_spawn, 1);
+ bp_pack_value (&bp, info->fp_expressions, 1);
streamer_write_bitpack (&bp);
streamer_write_uhwi (ob, vec_safe_length (info->conds));
for (i = 0; vec_safe_iterate (info->conds, i, &c); i++)
DECL_FUNCTION_SPECIFIC_OPTIMIZATION (to->decl)
= 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
possibly remove the aliases. */
else if (e->call_stmt_cannot_inline_p)
{
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;
}
/* Don't inline if the functions have different EH personalities. */
(DECL_DISREGARD_INLINE_LIMITS (callee->decl)
&& lookup_attribute ("always_inline",
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
bellow and inline across optimization boundry.
== !opt_for_fn (callee->decl, optimize) || !always_inline))
|| check_match (flag_wrapv)
|| check_match (flag_trapv)
- /* Strictly speaking only when the callee uses FP math. */
- || check_maybe_up (flag_rounding_math)
- || check_maybe_up (flag_trapping_math)
- || check_maybe_down (flag_unsafe_math_optimizations)
- || check_maybe_down (flag_finite_math_only)
- || check_maybe_up (flag_signaling_nans)
- || check_maybe_down (flag_cx_limited_range)
- || check_maybe_up (flag_signed_zeros)
- || check_maybe_down (flag_associative_math)
- || check_maybe_down (flag_reciprocal_math)
+ /* When caller or callee does FP math, be sure FP codegen flags
+ compatible. */
+ || ((caller_info->fp_expressions && callee_info->fp_expressions)
+ && (check_maybe_up (flag_rounding_math)
+ || check_maybe_up (flag_trapping_math)
+ || check_maybe_down (flag_unsafe_math_optimizations)
+ || check_maybe_down (flag_finite_math_only)
+ || check_maybe_up (flag_signaling_nans)
+ || check_maybe_down (flag_cx_limited_range)
+ || check_maybe_up (flag_signed_zeros)
+ || check_maybe_down (flag_associative_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
brought into a non-EH function unless we know that the callee
does not throw.
&& DECL_FUNCTION_PERSONALITY (callee->decl))
|| (check_maybe_up (flag_exceptions)
&& 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
to inline it as we possibly mangled the type info.
Allow early inlining of always inlines. */
/* True wen there is only one caller of the function before small function
inlining. */
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
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>
PR rtl-optimization/70467
--- /dev/null
+/* 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;
+}