From 818b88a7a1be36183bc4bbc24535329389d6178e Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Mon, 2 May 2016 18:55:56 +0200 Subject: [PATCH] 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 --- gcc/ChangeLog | 15 ++++++++ gcc/ipa-inline-analysis.c | 32 +++++++++++++++- gcc/ipa-inline-transform.c | 57 +++++++++++++++++++++++++++++ gcc/ipa-inline.c | 32 +++++++++------- gcc/ipa-inline.h | 2 + gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/gcc.dg/ipa/inline-8.c | 36 ++++++++++++++++++ 7 files changed, 163 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/ipa/inline-8.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a5339da2527..9464a950556 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2016-05-02 Jan Hubicka + + * 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 PR rtl-optimization/70467 diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c index f8ca825e24f..a2f31285506 100644 --- a/gcc/ipa-inline-analysis.c +++ b/gcc/ipa-inline-analysis.c @@ -850,7 +850,8 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, 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; @@ -1069,6 +1070,7 @@ reset_inline_summary (struct cgraph_node *node, 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. */ @@ -1423,6 +1425,8 @@ dump_inline_summary (FILE *f, struct cgraph_node *node) 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); @@ -2459,6 +2463,21 @@ clobber_only_eh_bb_p (basic_block bb, bool need_eh = 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. When EARLY is true, we compute only simple summaries without non-trivial predicates to drive the early inliner. */ @@ -2733,6 +2752,13 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early) 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); } @@ -3577,6 +3603,8 @@ inline_merge_summary (struct cgraph_edge *edge) 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) @@ -4229,6 +4257,7 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data, 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); @@ -4395,6 +4424,7 @@ inline_write_summary (void) 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++) diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c index f966fb00ffb..759617bb72f 100644 --- a/gcc/ipa-inline-transform.c +++ b/gcc/ipa-inline-transform.c @@ -338,6 +338,63 @@ inline_call (struct cgraph_edge *e, bool update_original, 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. */ diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index b855fc7f07c..d520c556d43 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -338,7 +338,7 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, 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. */ @@ -396,6 +396,8 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, (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. @@ -417,16 +419,21 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, == !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. @@ -435,9 +442,6 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, && 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. */ diff --git a/gcc/ipa-inline.h b/gcc/ipa-inline.h index 4bf00243e4b..df535d06316 100644 --- a/gcc/ipa-inline.h +++ b/gcc/ipa-inline.h @@ -132,6 +132,8 @@ struct GTY(()) inline_summary /* 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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 328a9a5f056..45af33f0de5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2016-05-02 Jan Hubicka + + * gcc.dg/ipa/inline-8.c: New testcase. + 2016-05-02 Jakub Jelinek PR rtl-optimization/70467 diff --git a/gcc/testsuite/gcc.dg/ipa/inline-8.c b/gcc/testsuite/gcc.dg/ipa/inline-8.c new file mode 100644 index 00000000000..a4ac5d0487b --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/inline-8.c @@ -0,0 +1,36 @@ +/* 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 +/* 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; +} -- 2.30.2