OSDN Git Service

PR middle-end/48636
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 11 Nov 2012 18:14:35 +0000 (18:14 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 11 Nov 2012 18:14:35 +0000 (18:14 +0000)
* ipa-inline.c (want_inline_small_function_p): Take aray index hint.
(edge_badness): Likewise.
* ipa-inline.h (inline_hints_vals): Add array_index and comments.
(inline_summary_: Add ARRAY_INDEX.
* ipa-inline-analysis.c (dump_inline_hints): Dump array_index hint.
(reset_inline_summary): Handle array_index hint.
(inline_node_duplication_hook): Likewise.
(dump_inline_summary): Likewise.
(array_index_predicate): New function.
(estimate_function_body_sizes): Use it.
(estimate_node_size_and_time): Use array_index hint.
(inline_merge_summary, inline_read_section): Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@193406 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/ipa-inline-analysis.c
gcc/ipa-inline.c
gcc/ipa-inline.h

index 5a96bdd..535c0ef 100644 (file)
@@ -1,3 +1,19 @@
+2012-11-10  Jan Hubicka  <jh@suse.cz>
+
+       PR middle-end/48636
+       * ipa-inline.c (want_inline_small_function_p): Take aray index hint.
+       (edge_badness): Likewise.
+       * ipa-inline.h (inline_hints_vals): Add array_index and comments.
+       (inline_summary_: Add ARRAY_INDEX.
+       * ipa-inline-analysis.c (dump_inline_hints): Dump array_index hint.
+       (reset_inline_summary): Handle array_index hint.
+       (inline_node_duplication_hook): Likewise.
+       (dump_inline_summary): Likewise.
+       (array_index_predicate): New function.
+       (estimate_function_body_sizes): Use it.
+       (estimate_node_size_and_time): Use array_index hint.
+       (inline_merge_summary, inline_read_section): Likewise.
+
 2012-11-10  Sandra Loosemore  <sandra@codesourcery.com>
 
        * doc/extend.texi: Copy-edit to use "bit-field" consistently
index 75dc308..f7b3af1 100644 (file)
@@ -659,6 +659,11 @@ dump_inline_hints (FILE *f, inline_hints hints)
       hints &= ~INLINE_HINT_declared_inline;
       fprintf (f, " declared_inline");
     }
+  if (hints & INLINE_HINT_array_index)
+    {
+      hints &= ~INLINE_HINT_array_index;
+      fprintf (f, " array_index");
+    }
   gcc_assert (!hints);
 }
 
@@ -1007,6 +1012,11 @@ reset_inline_summary (struct cgraph_node *node)
       pool_free (edge_predicate_pool, info->loop_stride);
       info->loop_stride = NULL;
     }
+  if (info->array_index)
+    {
+      pool_free (edge_predicate_pool, info->array_index);
+      info->array_index = NULL;
+    }
   VEC_free (condition, gc, info->conds);
   VEC_free (size_time_entry,gc, info->entry);
   for (e = node->callees; e; e = e->next_callee)
@@ -1201,6 +1211,9 @@ inline_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
       remap_hint_predicate_after_duplication (&info->loop_stride,
                                              possible_truths,
                                              info);
+      remap_hint_predicate_after_duplication (&info->array_index,
+                                             possible_truths,
+                                             info);
 
       /* If inliner or someone after inliner will ever start producing
         non-trivial clones, we will get trouble with lack of information
@@ -1224,6 +1237,12 @@ inline_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
          info->loop_stride = NULL;
          set_hint_predicate (&info->loop_stride, p);
        }
+      if (info->array_index)
+       {
+         predicate p = *info->array_index;
+         info->array_index = NULL;
+         set_hint_predicate (&info->array_index, p);
+       }
     }
   inline_update_overall_summary (dst);
 }
@@ -1413,6 +1432,11 @@ dump_inline_summary (FILE * f, struct cgraph_node *node)
          fprintf (f, "  loop stride:");
          dump_predicate (f, s->conds, s->loop_stride);
        }
+      if (s->array_index)
+       {
+         fprintf (f, "  array index:");
+         dump_predicate (f, s->conds, s->array_index);
+       }
       fprintf (f, "  calls:\n");
       dump_inline_edge_summary (f, 4, node, s);
       fprintf (f, "\n");
@@ -2262,6 +2286,28 @@ predicate_for_phi_result (struct inline_summary *summary, gimple phi,
               SSA_NAME_VERSION (gimple_phi_result (phi)), *p);
 }
 
+/* Return predicate specifying when array index in access OP becomes non-constant.  */
+
+static struct predicate
+array_index_predicate (struct inline_summary *info,
+                      VEC (predicate_t, heap) *nonconstant_names, tree op)
+{
+  struct predicate p = false_predicate ();
+  while (handled_component_p (op))
+    {
+      if (TREE_CODE (op) == ARRAY_REF
+         || TREE_CODE (op) == ARRAY_RANGE_REF)
+        {
+         if (TREE_CODE (TREE_OPERAND (op, 1)) == SSA_NAME)
+            p = or_predicates (info->conds, &p,
+                               &VEC_index (predicate_t, nonconstant_names,
+                                            SSA_NAME_VERSION (TREE_OPERAND (op, 1))));
+        }
+      op = TREE_OPERAND (op, 0);
+    }
+  return p;
+}
+
 /* 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.  */
@@ -2284,6 +2330,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
   VEC (predicate_t, heap) *nonconstant_names = NULL;
   int nblocks, n;
   int *order;
+  predicate array_index = true_predicate ();
 
   info->conds = 0;
   info->entry = 0;
@@ -2380,6 +2427,24 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
                       ((double)freq)/CGRAPH_FREQ_BASE, this_size, this_time);
            }
 
+         if (gimple_assign_load_p (stmt) && nonconstant_names)
+           {
+             struct predicate this_array_index;
+             this_array_index = array_index_predicate (info, nonconstant_names,
+                                                       gimple_assign_rhs1 (stmt));
+             if (!false_predicate_p (&this_array_index))
+               array_index = and_predicates (info->conds, &array_index, &this_array_index);
+           }
+         if (gimple_store_p (stmt) && nonconstant_names)
+           {
+             struct predicate this_array_index;
+             this_array_index = array_index_predicate (info, nonconstant_names,
+                                                       gimple_get_lhs (stmt));
+             if (!false_predicate_p (&this_array_index))
+               array_index = and_predicates (info->conds, &array_index, &this_array_index);
+           }
+          
+
          if (is_gimple_call (stmt))
            {
              struct cgraph_edge *edge = cgraph_edge (node, stmt);
@@ -2476,21 +2541,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
            }
        }
     }
-  FOR_ALL_BB_FN (bb, my_function)
-    {
-      edge e;
-      edge_iterator ei;
-
-      if (bb->aux)
-       pool_free (edge_predicate_pool, bb->aux);
-      bb->aux = NULL;
-      FOR_EACH_EDGE (e, ei, bb->succs)
-       {
-         if (e->aux)
-           pool_free (edge_predicate_pool, e->aux);
-         e->aux = NULL;
-       }
-    }
+  set_hint_predicate (&inline_summary (node)->array_index, array_index);
   time = (time + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE;
   if (time > MAX_TIME)
     time = MAX_TIME;
@@ -2513,6 +2564,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
          unsigned int j, i;
          struct tree_niter_desc niter_desc;
          basic_block *body = get_loop_body (loop);
+         bb_predicate = *(struct predicate *)loop->header->aux;
 
          exits = get_loop_exit_edges (loop);
           FOR_EACH_VEC_ELT (edge, exits, j, ex)
@@ -2522,6 +2574,10 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
                predicate will_be_nonconstant
                 = will_be_nonconstant_expr_predicate (parms_info, info,
                                                       niter_desc.niter, nonconstant_names);
+               if (!true_predicate_p (&will_be_nonconstant))
+                 will_be_nonconstant = and_predicates (info->conds,
+                                                       &bb_predicate,
+                                                       &will_be_nonconstant);
                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
@@ -2533,6 +2589,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
           for (i = 0; i < loop->num_nodes; i++)
            {
              gimple_stmt_iterator gsi;
+             bb_predicate = *(struct predicate *)body[i]->aux;
              for (gsi = gsi_start_bb (body[i]); !gsi_end_p (gsi); gsi_next (&gsi))
                {
                  gimple stmt = gsi_stmt (gsi);
@@ -2550,6 +2607,10 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
                      will_be_nonconstant
                       = will_be_nonconstant_expr_predicate (parms_info, info,
                                                             iv.step, nonconstant_names);
+                     if (!true_predicate_p (&will_be_nonconstant))
+                       will_be_nonconstant = and_predicates (info->conds,
+                                                             &bb_predicate,
+                                                             &will_be_nonconstant);
                      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
@@ -2564,6 +2625,21 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
       set_hint_predicate (&inline_summary (node)->loop_stride, loop_stride);
       scev_finalize ();
     }
+  FOR_ALL_BB_FN (bb, my_function)
+    {
+      edge e;
+      edge_iterator ei;
+
+      if (bb->aux)
+       pool_free (edge_predicate_pool, bb->aux);
+      bb->aux = NULL;
+      FOR_EACH_EDGE (e, ei, bb->succs)
+       {
+         if (e->aux)
+           pool_free (edge_predicate_pool, e->aux);
+         e->aux = NULL;
+       }
+    }
   inline_summary (node)->self_time = time;
   inline_summary (node)->self_size = size;
   VEC_free (predicate_t, heap, nonconstant_names);
@@ -2881,6 +2957,9 @@ estimate_node_size_and_time (struct cgraph_node *node,
   if (info->loop_stride
       && !evaluate_predicate (info->loop_stride, possible_truths))
     hints |=INLINE_HINT_loop_stride;
+  if (info->array_index
+      && !evaluate_predicate (info->array_index, possible_truths))
+    hints |=INLINE_HINT_array_index;
   if (info->scc_no)
     hints |= INLINE_HINT_in_scc;
   if (DECL_DECLARED_INLINE_P (node->symbol.decl))
@@ -3311,6 +3390,10 @@ inline_merge_summary (struct cgraph_edge *edge)
                        &callee_info->loop_stride,
                        operand_map, offset_map,
                        clause, &toplev_predicate);
+  remap_hint_predicate (info, callee_info,
+                       &callee_info->array_index,
+                       operand_map, offset_map,
+                       clause, &toplev_predicate);
 
   inline_update_callee_summaries (edge->callee,
                                  inline_edge_summary (edge)->loop_depth);
@@ -3803,6 +3886,8 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
       set_hint_predicate (&info->loop_iterations, p);
       p = read_predicate (&ib);
       set_hint_predicate (&info->loop_stride, p);
+      p = read_predicate (&ib);
+      set_hint_predicate (&info->array_index, 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)
@@ -3954,6 +4039,7 @@ inline_write_summary (void)
            }
          write_predicate (ob, info->loop_iterations);
          write_predicate (ob, info->loop_stride);
+         write_predicate (ob, info->array_index);
          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 fa3d456..9f792ff 100644 (file)
@@ -541,6 +541,7 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report)
               && !big_speedup
               && !(hints & (INLINE_HINT_indirect_call
                             | INLINE_HINT_loop_iterations
+                            | INLINE_HINT_array_index
                             | INLINE_HINT_loop_stride)))
        {
           e->inline_failed = CIF_MAX_INLINE_INSNS_SINGLE_LIMIT;
@@ -595,6 +596,7 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report)
               && !big_speedup
               && growth >= ((hints & (INLINE_HINT_indirect_call
                                       | INLINE_HINT_loop_iterations
+                                      | INLINE_HINT_array_index
                                       | INLINE_HINT_loop_stride))
                             ? MAX (MAX_INLINE_INSNS_AUTO,
                                    MAX_INLINE_INSNS_SINGLE)
@@ -919,6 +921,7 @@ edge_badness (struct cgraph_edge *edge, bool dump)
       gcc_checking_assert (badness <=0 && badness >= INT_MIN / 16);
       if ((hints & (INLINE_HINT_indirect_call
                    | INLINE_HINT_loop_iterations
+                   | INLINE_HINT_array_index
                    | INLINE_HINT_loop_stride))
          || callee_info->growth <= 0)
        badness *= 8;
index 4791bf0..1e9658c 100644 (file)
@@ -44,16 +44,32 @@ typedef struct GTY(()) condition
     unsigned by_ref : 1;
   } condition;
 
-/* Inline hints are reasons why inline heuristics should preffer inlining given function.
-   They are represtented as bitmap of the following values.  */
+/* 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 {
+  /* When inlining turns indirect call into a direct call,
+     it is good idea to do so.  */
   INLINE_HINT_indirect_call = 1,
+  /* Inlining may make loop iterations or loop stride known.  It is good idea
+     to do so because it enables loop optimizatoins.  */
   INLINE_HINT_loop_iterations = 2,
   INLINE_HINT_loop_stride = 4,
+  /* Inlining withing same strongly connected component of callgraph is often
+     a loss due to increased stack frame usage and prologue setup costs.  */
   INLINE_HINT_same_scc = 8,
+  /* Inlining functions in strongly connected component is not such a great
+     win.  */
   INLINE_HINT_in_scc = 16,
+  /* If function is declared inline by user, it may be good idea to inline
+     it.  */
   INLINE_HINT_declared_inline = 32,
-  INLINE_HINT_cross_module = 64
+  /* Programs are usually still organized for non-LTO compilation and thus
+     if functions are in different modules, inlining may not be so important. 
+   */
+  INLINE_HINT_cross_module = 64,
+  /* If array indexes of loads/stores become known there may be room for
+     futher optimization.  */
+  INLINE_HINT_array_index = 128
 };
 typedef int inline_hints;
 
@@ -133,6 +149,8 @@ struct GTY(()) inline_summary
   /* Predicate on when some loop in the function becomes to have known
      stride.   */
   struct predicate * GTY((skip)) loop_stride;
+  /* Predicate on when some array indexes become constants.  */
+  struct predicate * GTY((skip)) array_index;
   /* Estimated growth for inlining all copies of the function before start
      of small functions inlining.
      This value will get out of date as the callers are duplicated, but