* update-copyright.py: Skip pdt-5.f03 in gfortran.dg subdir.
[platform/upstream/gcc.git] / gcc / tracer.c
index 73e3209..0c7a953 100644 (file)
@@ -1,7 +1,7 @@
 /* The tracer pass for the GNU compiler.
    Contributed by Jan Hubicka, SuSE Labs.
    Adapted to work on GIMPLE instead of RTL by Robert Kidd, UIUC.
-   Copyright (C) 2001-2014 Free Software Foundation, Inc.
+   Copyright (C) 2001-2017 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "tree.h"
+#include "backend.h"
 #include "rtl.h"
-#include "hard-reg-set.h"
-#include "basic-block.h"
-#include "fibheap.h"
-#include "flags.h"
-#include "params.h"
-#include "coverage.h"
-#include "tree-pass.h"
-#include "tree-ssa-alias.h"
-#include "internal-fn.h"
-#include "gimple-expr.h"
-#include "is-a.h"
+#include "tree.h"
 #include "gimple.h"
+#include "cfghooks.h"
+#include "tree-pass.h"
+#include "profile.h"
+#include "cfganal.h"
+#include "params.h"
 #include "gimple-iterator.h"
 #include "tree-cfg.h"
 #include "tree-ssa.h"
 #include "tree-inline.h"
 #include "cfgloop.h"
+#include "fibonacci_heap.h"
+#include "tracer.h"
 
 static int count_insns (basic_block);
-static bool ignore_bb_p (const_basic_block);
 static bool better_p (const_edge, const_edge);
 static edge find_best_successor (basic_block);
 static edge find_best_predecessor (basic_block);
@@ -70,7 +65,7 @@ static int branch_ratio_cutoff;
 
 /* A bit BB->index is set if BB has already been seen, i.e. it is
    connected to some trace already.  */
-sbitmap bb_seen;
+static sbitmap bb_seen;
 
 static inline void
 mark_bb_seen (basic_block bb)
@@ -90,21 +85,28 @@ bb_seen_p (basic_block bb)
 }
 
 /* Return true if we should ignore the basic block for purposes of tracing.  */
-static bool
+bool
 ignore_bb_p (const_basic_block bb)
 {
-  gimple g;
-
   if (bb->index < NUM_FIXED_BLOCKS)
     return true;
   if (optimize_bb_for_size_p (bb))
     return true;
 
-  /* A transaction is a single entry multiple exit region.  It must be
-     duplicated in its entirety or not at all.  */
-  g = last_stmt (CONST_CAST_BB (bb));
-  if (g && gimple_code (g) == GIMPLE_TRANSACTION)
-    return true;
+  if (gimple *g = last_stmt (CONST_CAST_BB (bb)))
+    {
+      /* A transaction is a single entry multiple exit region.  It
+        must be duplicated in its entirety or not at all.  */
+      if (gimple_code (g) == GIMPLE_TRANSACTION)
+       return true;
+
+      /* An IFN_UNIQUE call must be duplicated as part of its group,
+        or not at all.  */
+      if (is_gimple_call (g)
+         && gimple_call_internal_p (g)
+         && gimple_call_internal_unique_p (g))
+       return true;
+    }
 
   return false;
 }
@@ -115,7 +117,7 @@ static int
 count_insns (basic_block bb)
 {
   gimple_stmt_iterator gsi;
-  gimple stmt;
+  gimple *stmt;
   int n = 0;
 
   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
@@ -130,12 +132,9 @@ count_insns (basic_block bb)
 static bool
 better_p (const_edge e1, const_edge e2)
 {
-  if (e1->count != e2->count)
-    return e1->count > e2->count;
-  if (e1->src->frequency * e1->probability !=
-      e2->src->frequency * e2->probability)
-    return (e1->src->frequency * e1->probability
-           > e2->src->frequency * e2->probability);
+  if (e1->count ().initialized_p () && e2->count ().initialized_p ()
+      && ((e1->count () > e2->count ()) || (e1->count () < e2->count  ())))
+    return e1->count () > e2->count ();
   /* This is needed to avoid changes in the decision after
      CFG is modified.  */
   if (e1->src != e2->src)
@@ -157,7 +156,8 @@ find_best_successor (basic_block bb)
       best = e;
   if (!best || ignore_bb_p (best->dest))
     return NULL;
-  if (best->probability <= probability_cutoff)
+  if (best->probability.initialized_p ()
+      && best->probability.to_reg_br_prob_base () <= probability_cutoff)
     return NULL;
   return best;
 }
@@ -177,7 +177,7 @@ find_best_predecessor (basic_block bb)
   if (!best || ignore_bb_p (best->src))
     return NULL;
   if (EDGE_FREQUENCY (best) * REG_BR_PROB_BASE
-      < bb->frequency * branch_ratio_cutoff)
+      < bb->count.to_frequency (cfun) * branch_ratio_cutoff)
     return NULL;
   return best;
 }
@@ -192,7 +192,7 @@ find_trace (basic_block bb, basic_block *trace)
   edge e;
 
   if (dump_file)
-    fprintf (dump_file, "Trace seed %i [%i]", bb->index, bb->frequency);
+    fprintf (dump_file, "Trace seed %i [%i]", bb->index, bb->count.to_frequency (cfun));
 
   while ((e = find_best_predecessor (bb)) != NULL)
     {
@@ -201,11 +201,11 @@ find_trace (basic_block bb, basic_block *trace)
          || find_best_successor (bb2) != e)
        break;
       if (dump_file)
-       fprintf (dump_file, ",%i [%i]", bb->index, bb->frequency);
+       fprintf (dump_file, ",%i [%i]", bb->index, bb->count.to_frequency (cfun));
       bb = bb2;
     }
   if (dump_file)
-    fprintf (dump_file, " forward %i [%i]", bb->index, bb->frequency);
+    fprintf (dump_file, " forward %i [%i]", bb->index, bb->count.to_frequency (cfun));
   trace[i++] = bb;
 
   /* Follow the trace in forward direction.  */
@@ -216,7 +216,7 @@ find_trace (basic_block bb, basic_block *trace)
          || find_best_predecessor (bb) != e)
        break;
       if (dump_file)
-       fprintf (dump_file, ",%i [%i]", bb->index, bb->frequency);
+       fprintf (dump_file, ",%i [%i]", bb->index, bb->count.to_frequency (cfun));
       trace[i++] = bb;
     }
   if (dump_file)
@@ -224,18 +224,38 @@ find_trace (basic_block bb, basic_block *trace)
   return i;
 }
 
+/* Duplicate block BB2, placing it after BB in the CFG.  Return the
+   newly created block.  */
+basic_block
+transform_duplicate (basic_block bb, basic_block bb2)
+{
+  edge e;
+  basic_block copy;
+
+  e = find_edge (bb, bb2);
+
+  copy = duplicate_block (bb2, e, bb);
+  flush_pending_stmts (e);
+
+  add_phi_args_after_copy (&copy, 1, NULL);
+
+  return (copy);
+}
+
 /* Look for basic blocks in frequency order, construct traces and tail duplicate
    if profitable.  */
 
 static bool
 tail_duplicate (void)
 {
-  fibnode_t *blocks = XCNEWVEC (fibnode_t, last_basic_block_for_fn (cfun));
+  auto_vec<fibonacci_node<long, basic_block_def>*> blocks;
+  blocks.safe_grow_cleared (last_basic_block_for_fn (cfun));
+
   basic_block *trace = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun));
   int *counts = XNEWVEC (int, last_basic_block_for_fn (cfun));
   int ninsns = 0, nduplicated = 0;
   gcov_type weighted_insns = 0, traced_insns = 0;
-  fibheap_t heap = fibheap_new ();
+  fibonacci_heap<long, basic_block_def> heap (LONG_MIN);
   gcov_type cover_insns;
   int max_dup_insns;
   basic_block bb;
@@ -247,7 +267,7 @@ tail_duplicate (void)
   bitmap_clear (bb_seen);
   initialize_original_copy_tables ();
 
-  if (profile_info && flag_branch_probabilities)
+  if (profile_info && profile_status_for_fn (cfun) == PROFILE_READ)
     probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY_FEEDBACK);
   else
     probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY);
@@ -260,15 +280,14 @@ tail_duplicate (void)
     {
       int n = count_insns (bb);
       if (!ignore_bb_p (bb))
-       blocks[bb->index] = fibheap_insert (heap, -bb->frequency,
-                                           bb);
+       blocks[bb->index] = heap.insert (-bb->count.to_frequency (cfun), bb);
 
       counts [bb->index] = n;
       ninsns += n;
-      weighted_insns += n * bb->frequency;
+      weighted_insns += n * bb->count.to_frequency (cfun);
     }
 
-  if (profile_info && flag_branch_probabilities)
+  if (profile_info && profile_status_for_fn (cfun) == PROFILE_READ)
     cover_insns = PARAM_VALUE (TRACER_DYNAMIC_COVERAGE_FEEDBACK);
   else
     cover_insns = PARAM_VALUE (TRACER_DYNAMIC_COVERAGE);
@@ -276,9 +295,9 @@ tail_duplicate (void)
   max_dup_insns = (ninsns * PARAM_VALUE (TRACER_MAX_CODE_GROWTH) + 50) / 100;
 
   while (traced_insns < cover_insns && nduplicated < max_dup_insns
-         && !fibheap_empty (heap))
+         && !heap.empty ())
     {
-      basic_block bb = (basic_block) fibheap_extract_min (heap);
+      basic_block bb = heap.extract_min ();
       int n, pos;
 
       if (!bb)
@@ -293,10 +312,10 @@ tail_duplicate (void)
       n = find_trace (bb, trace);
 
       bb = trace[0];
-      traced_insns += bb->frequency * counts [bb->index];
+      traced_insns += bb->count.to_frequency (cfun) * counts [bb->index];
       if (blocks[bb->index])
        {
-         fibheap_delete_node (heap, blocks[bb->index]);
+         heap.delete_node (blocks[bb->index]);
          blocks[bb->index] = NULL;
        }
 
@@ -306,40 +325,29 @@ tail_duplicate (void)
 
          if (blocks[bb2->index])
            {
-             fibheap_delete_node (heap, blocks[bb2->index]);
+             heap.delete_node (blocks[bb2->index]);
              blocks[bb2->index] = NULL;
            }
-         traced_insns += bb2->frequency * counts [bb2->index];
+         traced_insns += bb2->count.to_frequency (cfun) * counts [bb2->index];
          if (EDGE_COUNT (bb2->preds) > 1
              && can_duplicate_block_p (bb2)
              /* We have the tendency to duplicate the loop header
                 of all do { } while loops.  Do not do that - it is
                 not profitable and it might create a loop with multiple
                 entries or at least rotate the loop.  */
-             && (!current_loops
-                 || bb2->loop_father->header != bb2))
+             && bb2->loop_father->header != bb2)
            {
-             edge e;
-             basic_block copy;
-
              nduplicated += counts [bb2->index];
-
-             e = find_edge (bb, bb2);
-
-             copy = duplicate_block (bb2, e, bb);
-             flush_pending_stmts (e);
-
-             add_phi_args_after_copy (&copy, 1, NULL);
+             basic_block copy = transform_duplicate (bb, bb2);
 
              /* Reconsider the original copy of block we've duplicated.
                 Removing the most common predecessor may make it to be
                 head.  */
-             blocks[bb2->index] =
-               fibheap_insert (heap, -bb2->frequency, bb2);
+             blocks[bb2->index] = heap.insert (-bb2->count.to_frequency (cfun), bb2);
 
              if (dump_file)
                fprintf (dump_file, "Duplicated %i as %i [%i]\n",
-                        bb2->index, copy->index, copy->frequency);
+                        bb2->index, copy->index, copy->count.to_frequency (cfun));
 
              bb2 = copy;
              changed = true;
@@ -360,50 +368,12 @@ tail_duplicate (void)
 
   free_original_copy_tables ();
   sbitmap_free (bb_seen);
-  free (blocks);
   free (trace);
   free (counts);
-  fibheap_delete (heap);
 
   return changed;
 }
-
-/* Main entry point to this file.  */
-
-static unsigned int
-tracer (void)
-{
-  bool changed;
-
-  if (n_basic_blocks_for_fn (cfun) <= NUM_FIXED_BLOCKS + 1)
-    return 0;
-
-  mark_dfs_back_edges ();
-  if (dump_file)
-    brief_dump_cfg (dump_file, dump_flags);
-
-  /* Trace formation is done on the fly inside tail_duplicate */
-  changed = tail_duplicate ();
-  if (changed)
-    {
-      free_dominance_info (CDI_DOMINATORS);
-      /* If we changed the CFG schedule loops for fixup by cleanup_cfg.  */
-      if (current_loops)
-       loops_state_set (LOOPS_NEED_FIXUP);
-    }
-
-  if (dump_file)
-    brief_dump_cfg (dump_file, dump_flags);
-
-  return changed ? TODO_cleanup_cfg : 0;
-}
 \f
-static bool
-gate_tracer (void)
-{
-  return (optimize > 0 && flag_tracer && flag_reorder_blocks);
-}
-
 namespace {
 
 const pass_data pass_data_tracer =
@@ -411,13 +381,12 @@ const pass_data pass_data_tracer =
   GIMPLE_PASS, /* type */
   "tracer", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_execute */
   TV_TRACER, /* tv_id */
   0, /* properties_required */
   0, /* properties_provided */
   0, /* properties_destroyed */
   0, /* todo_flags_start */
-  ( TODO_update_ssa | TODO_verify_ssa ), /* todo_flags_finish */
+  TODO_update_ssa, /* todo_flags_finish */
 };
 
 class pass_tracer : public gimple_opt_pass
@@ -428,11 +397,41 @@ public:
   {}
 
   /* opt_pass methods: */
-  bool gate () { return gate_tracer (); }
-  unsigned int execute () { return tracer (); }
+  virtual bool gate (function *)
+    {
+      return (optimize > 0 && flag_tracer && flag_reorder_blocks);
+    }
+
+  virtual unsigned int execute (function *);
 
 }; // class pass_tracer
 
+unsigned int
+pass_tracer::execute (function *fun)
+{
+  bool changed;
+
+  if (n_basic_blocks_for_fn (fun) <= NUM_FIXED_BLOCKS + 1)
+    return 0;
+
+  mark_dfs_back_edges ();
+  if (dump_file)
+    brief_dump_cfg (dump_file, dump_flags);
+
+  /* Trace formation is done on the fly inside tail_duplicate */
+  changed = tail_duplicate ();
+  if (changed)
+    {
+      free_dominance_info (CDI_DOMINATORS);
+      /* If we changed the CFG schedule loops for fixup by cleanup_cfg.  */
+      loops_state_set (LOOPS_NEED_FIXUP);
+    }
+
+  if (dump_file)
+    brief_dump_cfg (dump_file, dump_flags);
+
+  return changed ? TODO_cleanup_cfg : 0;
+}
 } // anon namespace
 
 gimple_opt_pass *