re PR fortran/48636 (Enable more inlining with -O2 and higher)
authorJan Hubicka <jh@suse.cz>
Tue, 21 Aug 2012 06:54:01 +0000 (08:54 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Tue, 21 Aug 2012 06:54:01 +0000 (06:54 +0000)
PR fortran/48636
* ipa-inline.c (want_inline_small_function_p): Take loop_iterations hint.
(edge_badness): Likewise.
* ipa-inline.h (inline_hints_vals): Add INLINE_HINT_loop_iterations.
(inline_summary): Add loop_iterations.
* ipa-inline-analysis.c: Include tree-scalar-evolution.h.
(dump_inline_hints): Dump loop_iterations.
(reset_inline_summary): Free loop_iterations.
(inline_node_duplication_hook): Update loop_iterations.
(dump_inline_summary): Dump loop_iterations.
(will_be_nonconstant_expr_predicate): New function.
(estimate_function_body_sizes): Analyze loops.
(estimate_node_size_and_time): Set hint loop_iterations.
(inline_merge_summary): Merge loop iterations.
(inline_read_section): Stream in loop_iterations.
(inline_write_summary): Stream out loop_iterations.

From-SVN: r190556

gcc/ChangeLog
gcc/ipa-inline-analysis.c
gcc/ipa-inline.c
gcc/ipa-inline.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/ipa/inlinehint-1.c [new file with mode: 0644]

index 6382a8f..477111f 100644 (file)
@@ -1,3 +1,22 @@
+2012-08-20  Jan Hubicka  <jh@suse.cz>
+
+       PR fortran/48636
+       * ipa-inline.c (want_inline_small_function_p): Take loop_iterations hint.
+       (edge_badness): Likewise.
+       * ipa-inline.h (inline_hints_vals): Add INLINE_HINT_loop_iterations.
+       (inline_summary): Add loop_iterations.
+       * ipa-inline-analysis.c: Include tree-scalar-evolution.h.
+       (dump_inline_hints): Dump loop_iterations.
+       (reset_inline_summary): Free loop_iterations.
+       (inline_node_duplication_hook): Update loop_iterations.
+       (dump_inline_summary): Dump loop_iterations.
+       (will_be_nonconstant_expr_predicate): New function.
+       (estimate_function_body_sizes): Analyze loops.
+       (estimate_node_size_and_time): Set hint loop_iterations.
+       (inline_merge_summary): Merge loop iterations.
+       (inline_read_section): Stream in loop_iterations.
+       (inline_write_summary): Stream out loop_iterations.
+
 2012-08-20  Florian Weimer  <fweimer@redhat.com>
 
        PR c++/19351
index c30e81a..ca80a8b 100644 (file)
@@ -88,6 +88,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-inline.h"
 #include "alloc-pool.h"
 #include "cfgloop.h"
+#include "cfgloop.h"
+#include "tree-scalar-evolution.h"
 
 /* Estimate runtime of function can easilly run into huge numbers with many
    nested loops.  Be sure we can compute time * INLINE_SIZE_SCALE * 2 in an
@@ -627,6 +629,11 @@ dump_inline_hints (FILE *f, inline_hints hints)
       hints &= ~INLINE_HINT_indirect_call;
       fprintf (f, " indirect_call");
     }
+  if (hints & INLINE_HINT_loop_iterations)
+    {
+      hints &= ~INLINE_HINT_loop_iterations;
+      fprintf (f, " loop_iterations");
+    }
   gcc_assert (!hints);
 }
 
@@ -941,6 +948,11 @@ reset_inline_summary (struct cgraph_node *node)
   info->stack_frame_offset = 0;
   info->size = 0;
   info->time = 0;
+  if (info->loop_iterations)
+    {
+      pool_free (edge_predicate_pool, info->loop_iterations);
+      info->loop_iterations = NULL;
+    }
   VEC_free (condition, gc, info->conds);
   VEC_free (size_time_entry,gc, info->entry);
   for (e = node->callees; e; e = e->next_callee)
@@ -1078,7 +1090,7 @@ inline_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
                                     * edge->frequency);
              edge->frequency = 0;
            }
-         *es->predicate = new_predicate;
+         edge_set_predicate (edge, &new_predicate);
        }
 
       /* Remap indirect edge predicates with the same simplificaiton as above. 
@@ -1110,7 +1122,29 @@ inline_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
                                     * edge->frequency);
              edge->frequency = 0;
            }
-         *es->predicate = new_predicate;
+         edge_set_predicate (edge, &new_predicate);
+       }
+      if (info->loop_iterations)
+       {
+         struct predicate new_predicate = true_predicate ();
+
+         for (j = 0; info->loop_iterations->clause[j]; j++)
+           if (!(possible_truths & info->loop_iterations->clause[j]))
+             {
+               new_predicate = false_predicate ();
+               break;
+             }
+           else
+             add_clause (info->conds, &new_predicate,
+                         possible_truths & info->loop_iterations->clause[j]);
+         if (false_predicate_p (&new_predicate)
+             || true_predicate_p (&new_predicate))
+           info->loop_iterations = NULL;
+         else
+           {
+             info->loop_iterations = (struct predicate *)pool_alloc (edge_predicate_pool);
+             *info->loop_iterations = new_predicate;
+           }
        }
 
       /* If inliner or someone after inliner will ever start producing
@@ -1136,7 +1170,15 @@ inline_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
        info->self_time = 0;
     }
   else
-    info->entry = VEC_copy (size_time_entry, gc, info->entry);
+    {
+      info->entry = VEC_copy (size_time_entry, gc, info->entry);
+      if (info->loop_iterations)
+       {
+         predicate p = *info->loop_iterations;
+         info->loop_iterations = (struct predicate *)pool_alloc (edge_predicate_pool);
+         *info->loop_iterations = p;
+       }
+    }
 }
 
 
@@ -1308,6 +1350,11 @@ dump_inline_summary (FILE * f, struct cgraph_node *node)
                   (double) e->time / INLINE_TIME_SCALE);
          dump_predicate (f, s->conds, &e->predicate);
        }
+      if (s->loop_iterations)
+       {
+         fprintf (f, "  loop iterations:");
+         dump_predicate (f, s->conds, s->loop_iterations);
+       }
       fprintf (f, "  calls:\n");
       dump_inline_edge_summary (f, 4, node, s);
       fprintf (f, "\n");
@@ -1780,6 +1827,46 @@ compute_bb_predicates (struct cgraph_node *node,
 typedef struct predicate predicate_t;
 DEF_VEC_O (predicate_t);
 DEF_VEC_ALLOC_O (predicate_t, heap);
+/* Return predicate specifying when the STMT might have result that is not
+   a compile time constant.  */
+
+static struct predicate
+will_be_nonconstant_expr_predicate (struct ipa_node_params *info,
+                                   struct inline_summary *summary,
+                                   tree expr,
+                                   VEC (predicate_t, heap) *nonconstant_names)
+{
+  tree parm;
+  int index;
+
+  while (UNARY_CLASS_P (expr))
+    expr = TREE_OPERAND (expr, 0);
+
+  parm = unmodified_parm (NULL, expr);
+  if (parm
+      && (index = ipa_get_param_decl_index (info, parm)) >= 0)
+    return add_condition (summary, index, NULL, CHANGED, NULL_TREE);
+  if (is_gimple_min_invariant (expr))
+    return false_predicate ();
+  if (TREE_CODE (expr) == SSA_NAME)
+    return VEC_index (predicate_t, nonconstant_names,
+                      SSA_NAME_VERSION (expr));
+  if (BINARY_CLASS_P (expr))
+    {
+      struct predicate p1 =  will_be_nonconstant_expr_predicate (info, summary, TREE_OPERAND (expr, 0), nonconstant_names);
+      struct predicate p2;
+      if (true_predicate_p (&p1))
+       return p1;
+      p2 = will_be_nonconstant_expr_predicate (info, summary, TREE_OPERAND (expr, 0), nonconstant_names);
+      return or_predicates (summary->conds, &p1, &p2);
+    }
+  else
+    {
+      debug_tree (expr);
+      gcc_unreachable ();
+    }
+  return false_predicate ();
+}
 
 
 /* Return predicate specifying when the STMT might have result that is not
@@ -2176,6 +2263,51 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
   time = (time + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE;
   if (time > MAX_TIME)
     time = MAX_TIME;
+
+  if (!early && nonconstant_names)
+    {
+      struct loop *loop;
+      loop_iterator li;
+      predicate loop_iterations = true_predicate ();
+
+      calculate_dominance_info (CDI_DOMINATORS);
+      loop_optimizer_init (LOOPS_NORMAL
+                          | LOOPS_HAVE_RECORDED_EXITS);
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       flow_loops_dump (dump_file, NULL, 0);
+      scev_initialize ();
+      FOR_EACH_LOOP (li, loop, 0)
+       {
+          VEC (edge, heap) *exits;
+          edge ex;
+         unsigned int j;
+         struct tree_niter_desc niter_desc;
+
+         exits = get_loop_exit_edges (loop);
+          FOR_EACH_VEC_ELT (edge, exits, j, ex)
+           if (number_of_iterations_exit (loop, ex, &niter_desc, false)
+               && !is_gimple_min_invariant (niter_desc.niter))
+             {
+               predicate will_be_nonconstant
+                = will_be_nonconstant_expr_predicate (parms_info, info,
+                                                      niter_desc.niter, nonconstant_names);
+               if (!true_predicate_p (&will_be_nonconstant)
+                   && !false_predicate_p (&will_be_nonconstant))
+                 /* This is slightly inprecise.  We may want to represent each loop with
+                    independent predicate.  */
+                 loop_iterations = and_predicates (info->conds, &loop_iterations, &will_be_nonconstant);
+             }
+          VEC_free (edge, heap, exits);
+       }
+      if (!true_predicate_p (&loop_iterations))
+       {
+          inline_summary (node)->loop_iterations = (struct predicate *)pool_alloc (edge_predicate_pool);
+          *inline_summary (node)->loop_iterations = loop_iterations;
+       }
+      scev_finalize ();
+      loop_optimizer_finalize ();
+      free_dominance_info (CDI_DOMINATORS);
+    }
   inline_summary (node)->self_time = time;
   inline_summary (node)->self_size = size;
   VEC_free (predicate_t, heap, nonconstant_names);
@@ -2459,6 +2591,10 @@ estimate_node_size_and_time (struct cgraph_node *node,
                                                 
       }
 
+  if (info->loop_iterations
+      && !evaluate_predicate (info->loop_iterations, possible_truths))
+    hints |=INLINE_HINT_loop_iterations;
+
   if (time > MAX_TIME * INLINE_TIME_SCALE)
     time = MAX_TIME * INLINE_TIME_SCALE;
 
@@ -2842,6 +2978,28 @@ inline_merge_summary (struct cgraph_edge *edge)
     }
   remap_edge_summaries (edge, edge->callee, info, callee_info, operand_map,
                        offset_map, clause, &toplev_predicate);
+  if (callee_info->loop_iterations)
+    {
+      predicate p = remap_predicate (info, callee_info,
+                                    callee_info->loop_iterations,
+                                    operand_map, offset_map,
+                                    clause,
+                                    &toplev_predicate);
+      if (!false_predicate_p (&p)
+         && !true_predicate_p (&p))
+       {
+         if (!info->loop_iterations)
+           {
+             info->loop_iterations
+                = (struct predicate *)pool_alloc (edge_predicate_pool);
+             *info->loop_iterations = p;
+           }
+         else
+           *info->loop_iterations = and_predicates (info->conds, 
+                                                    info->loop_iterations,
+                                                    &p);
+       }
+    }
 
   inline_update_callee_summaries (edge->callee,
                                  inline_edge_summary (edge)->loop_depth);
@@ -3269,6 +3427,7 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
       lto_symtab_encoder_t encoder;
       struct bitpack_d bp;
       struct cgraph_edge *e;
+      predicate p;
 
       index = streamer_read_uhwi (&ib);
       encoder = file_data->symtab_node_encoder;
@@ -3310,6 +3469,13 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
 
          VEC_safe_push (size_time_entry, gc, info->entry, &e);
        }
+     
+      p = read_predicate (&ib);
+      if (!true_predicate_p (&p))
+       {
+         info->loop_iterations = (struct predicate *)pool_alloc (edge_predicate_pool);
+         *info->loop_iterations = p;
+       }
       for (e = node->callees; e; e = e->next_callee)
        read_inline_edge_summary (&ib, e);
       for (e = node->indirect_calls; e; e = e->next_callee)
@@ -3456,6 +3622,7 @@ inline_write_summary (void)
              streamer_write_uhwi (ob, e->time);
              write_predicate (ob, &e->predicate);
            }
+         write_predicate (ob, info->loop_iterations);
          for (edge = node->callees; edge; edge = edge->next_callee)
            write_inline_edge_summary (ob, edge);
          for (edge = node->indirect_calls; edge; edge = edge->next_callee)
index 55d9a52..a1d703a 100644 (file)
@@ -480,7 +480,8 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report)
         hints suggests that inlining given function is very profitable.  */
       else if (DECL_DECLARED_INLINE_P (callee->symbol.decl)
               && growth >= MAX_INLINE_INSNS_SINGLE
-              && !(hints & INLINE_HINT_indirect_call))
+              && !(hints & (INLINE_HINT_indirect_call
+                            | INLINE_HINT_loop_iterations)))
        {
           e->inline_failed = CIF_MAX_INLINE_INSNS_SINGLE_LIMIT;
          want_inline = false;
@@ -863,7 +864,8 @@ edge_badness (struct cgraph_edge *edge, bool dump)
          if (dump)
            fprintf (dump_file, "Badness overflow\n");
        }
-      if (hints & INLINE_HINT_indirect_call)
+      if (hints & (INLINE_HINT_indirect_call
+                  | INLINE_HINT_loop_iterations))
        badness /= 8;
       if (dump)
        {
index fca99e6..839bc23 100644 (file)
@@ -45,7 +45,8 @@ typedef struct GTY(()) condition
 /* Inline hints are reasons why inline heuristics should preffer inlining given function.
    They are represtented as bitmap of the following values.  */
 enum inline_hints_vals {
-  INLINE_HINT_indirect_call = 1
+  INLINE_HINT_indirect_call = 1,
+  INLINE_HINT_loop_iterations = 2
 };
 typedef int inline_hints;
 
@@ -118,6 +119,10 @@ struct GTY(()) inline_summary
      merged during inlining.  */
   conditions conds;
   VEC(size_time_entry,gc) *entry;
+
+  /* Predicate on when some loop in the function sbecomes to have known
+     bounds.   */
+  struct predicate * GTY((skip)) loop_iterations;
 };
 
 
index 84895e1..f6151fc 100644 (file)
@@ -1,3 +1,8 @@
+2012-08-20  Jan Hubicka  <jh@suse.cz>
+
+       PR fortran/48636
+       * gcc.dg/ipa/inlinehint-1.c: New.
+
 2012-08-20  Florian Weimer  <fweimer@redhat.com>
 
        PR c++/19351
diff --git a/gcc/testsuite/gcc.dg/ipa/inlinehint-1.c b/gcc/testsuite/gcc.dg/ipa/inlinehint-1.c
new file mode 100644 (file)
index 0000000..9810e25
--- /dev/null
@@ -0,0 +1,16 @@
+/* { dg-options "-O3 -c -fdump-ipa-inline-details -fno-early-inlining -fno-ipa-cp"  } */
+test (int a)
+{
+   int i;
+   for (i=0; i<a; i++)
+{
+     test2(a);
+     test2(a);
+}
+}
+m()
+{
+  test (10);
+}
+/* { dg-final { scan-ipa-dump "loop_iterations"  "inline"  } } */
+/* { dg-final { cleanup-ipa-dump "inline" } } */