ipa-inline-analysis.c (reset_inline_summary): Clear fp_expressions
authorJan Hubicka <hubicka@ucw.cz>
Mon, 2 May 2016 16:55:56 +0000 (18:55 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Mon, 2 May 2016 16:55:56 +0000 (16:55 +0000)
* 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
gcc/ipa-inline-analysis.c
gcc/ipa-inline-transform.c
gcc/ipa-inline.c
gcc/ipa-inline.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/ipa/inline-8.c [new file with mode: 0644]

index a5339da2527fd73008aa4205c208ccd791894ce2..9464a9505562257a370a9b13ae7492e15713299b 100644 (file)
@@ -1,3 +1,18 @@
+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
index f8ca825e24f3a894cf40cda1a656085124961139..a2f31285506e5dbed302d6abe2fa85afc6c0c303 100644 (file)
@@ -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++)
index f966fb00ffb7819a43fff55f2e9d3787a64215b6..759617bb72f5b41a564b99c045db69799de86f4a 100644 (file)
@@ -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.  */
index b855fc7f07cfb0854574a2934f3914d01e6729f3..d520c556d435593a44ea9a759e709649acceba33 100644 (file)
@@ -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.  */
index 4bf00243e4b8111fcbb5594e8d9dab66539c9e03..df535d06316f474ca18c097756d071e216e9f5c2 100644 (file)
@@ -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
index 328a9a5f056052a5a9e7fc10c7be46a7d3f1bd1a..45af33f0de5c28fff8e21ac22913bc6a0e613519 100644 (file)
@@ -1,3 +1,7 @@
+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
diff --git a/gcc/testsuite/gcc.dg/ipa/inline-8.c b/gcc/testsuite/gcc.dg/ipa/inline-8.c
new file mode 100644 (file)
index 0000000..a4ac5d0
--- /dev/null
@@ -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 <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;
+}