Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / gcc / cfghooks.c
index c4c51cc..5e3eeb5 100644 (file)
@@ -1,6 +1,5 @@
 /* Hooks for cfg representation specific functions.
-   Copyright (C) 2003, 2004, 2005, 2007, 2008, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 2003-2013 Free Software Foundation, Inc.
    Contributed by Sebastian Pop <s.pop@laposte.net>
 
 This file is part of GCC.
@@ -22,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "dumpfile.h"
 #include "tm.h"
 #include "tree.h"
 #include "rtl.h"
@@ -183,9 +183,9 @@ verify_flow_info (void)
              error ("verify_flow_info: Basic block %d succ edge is corrupted",
                     bb->index);
              fprintf (stderr, "Predecessor: ");
-             dump_edge_info (stderr, e, 0);
+             dump_edge_info (stderr, e, TDF_DETAILS, 0);
              fprintf (stderr, "\nSuccessor: ");
-             dump_edge_info (stderr, e, 1);
+             dump_edge_info (stderr, e, TDF_DETAILS, 1);
              fprintf (stderr, "\n");
              err = 1;
            }
@@ -204,9 +204,9 @@ verify_flow_info (void)
            {
              error ("basic block %d pred edge is corrupted", bb->index);
              fputs ("Predecessor: ", stderr);
-             dump_edge_info (stderr, e, 0);
+             dump_edge_info (stderr, e, TDF_DETAILS, 0);
              fputs ("\nSuccessor: ", stderr);
-             dump_edge_info (stderr, e, 1);
+             dump_edge_info (stderr, e, TDF_DETAILS, 1);
              fputc ('\n', stderr);
              err = 1;
            }
@@ -217,9 +217,9 @@ verify_flow_info (void)
              error ("its dest_idx should be %d, not %d",
                     ei.index, e->dest_idx);
              fputs ("Predecessor: ", stderr);
-             dump_edge_info (stderr, e, 0);
+             dump_edge_info (stderr, e, TDF_DETAILS, 0);
              fputs ("\nSuccessor: ", stderr);
-             dump_edge_info (stderr, e, 1);
+             dump_edge_info (stderr, e, TDF_DETAILS, 1);
              fputc ('\n', stderr);
              err = 1;
            }
@@ -260,50 +260,60 @@ verify_flow_info (void)
   timevar_pop (TV_CFG_VERIFY);
 }
 
-/* Print out one basic block.  This function takes care of the purely
-   graph related information.  The cfg hook for the active representation
-   should dump representation-specific information.  */
+/* Print out one basic block BB to file OUTF.  INDENT is printed at the
+   start of each new line.  FLAGS are the TDF_* flags in dumpfile.h.
+
+   This function takes care of the purely graph related information.
+   The cfg hook for the active representation should dump
+   representation-specific information.  */
 
 void
-dump_bb (basic_block bb, FILE *outf, int indent)
+dump_bb (FILE *outf, basic_block bb, int indent, int flags)
 {
-  edge e;
-  edge_iterator ei;
-  char *s_indent;
+  if (flags & TDF_BLOCKS)
+    dump_bb_info (outf, bb, indent, flags, true, false);
+  if (cfg_hooks->dump_bb)
+    cfg_hooks->dump_bb (outf, bb, indent, flags);
+  if (flags & TDF_BLOCKS)
+    dump_bb_info (outf, bb, indent, flags, false, true);
+  fputc ('\n', outf);
+}
 
-  s_indent = (char *) alloca ((size_t) indent + 1);
-  memset (s_indent, ' ', (size_t) indent);
-  s_indent[indent] = '\0';
+/* Dumps basic block BB to pretty-printer PP, for use as a label of
+   a DOT graph record-node.  The implementation of this hook is
+   expected to write the label to the stream that is attached to PP.
+   Field separators between instructions are pipe characters printed
+   verbatim.  Instructions should be written with some characters
+   escaped, using pp_write_text_as_dot_label_to_stream().  */
 
-  fprintf (outf, ";;%s basic block %d, loop depth %d, count ",
-          s_indent, bb->index, bb->loop_depth);
-  fprintf (outf, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT) bb->count);
-  putc ('\n', outf);
+void
+dump_bb_for_graph (pretty_printer *pp, basic_block bb)
+{
+  if (!cfg_hooks->dump_bb_for_graph)
+    internal_error ("%s does not support dump_bb_for_graph",
+                   cfg_hooks->name);
+  cfg_hooks->dump_bb_for_graph (pp, bb);
+}
 
-  fprintf (outf, ";;%s prev block ", s_indent);
-  if (bb->prev_bb)
-    fprintf (outf, "%d, ", bb->prev_bb->index);
-  else
-    fprintf (outf, "(nil), ");
-  fprintf (outf, "next block ");
-  if (bb->next_bb)
-    fprintf (outf, "%d", bb->next_bb->index);
-  else
-    fprintf (outf, "(nil)");
-  putc ('\n', outf);
+/* Dump the complete CFG to FILE.  FLAGS are the TDF_* flags in dumpfile.h.  */
+void
+dump_flow_info (FILE *file, int flags)
+{
+  basic_block bb;
 
-  fprintf (outf, ";;%s pred:      ", s_indent);
-  FOR_EACH_EDGE (e, ei, bb->preds)
-    dump_edge_info (outf, e, 0);
-  putc ('\n', outf);
+  fprintf (file, "\n%d basic blocks, %d edges.\n", n_basic_blocks, n_edges);
+  FOR_ALL_BB (bb)
+    dump_bb (file, bb, 0, flags);
 
-  fprintf (outf, ";;%s succ:      ", s_indent);
-  FOR_EACH_EDGE (e, ei, bb->succs)
-    dump_edge_info (outf, e, 1);
-  putc ('\n', outf);
+  putc ('\n', file);
+}
 
-  if (cfg_hooks->dump_bb)
-    cfg_hooks->dump_bb (bb, outf, indent, 0);
+/* Like above, but dump to stderr.  To be called from debuggers.  */
+void debug_flow_info (void);
+DEBUG_FUNCTION void
+debug_flow_info (void)
+{
+  dump_flow_info (stderr, TDF_DETAILS);
 }
 
 /* Redirect edge E to the given basic block DEST and update underlying program
@@ -377,9 +387,40 @@ remove_edge (edge e)
   if (current_loops != NULL)
     rescan_loop_exit (e, false, true);
 
+  /* This is probably not needed, but it doesn't hurt.  */
+  /* FIXME: This should be called via a remove_edge hook.  */
+  if (current_ir_type () == IR_GIMPLE)
+    redirect_edge_var_map_clear (e);
+
   remove_edge_raw (e);
 }
 
+/* Like redirect_edge_succ but avoid possible duplicate edge.  */
+
+edge
+redirect_edge_succ_nodup (edge e, basic_block new_succ)
+{
+  edge s;
+
+  s = find_edge (e->src, new_succ);
+  if (s && s != e)
+    {
+      s->flags |= e->flags;
+      s->probability += e->probability;
+      if (s->probability > REG_BR_PROB_BASE)
+       s->probability = REG_BR_PROB_BASE;
+      s->count += e->count;
+      /* FIXME: This should be called via a hook and only for IR_GIMPLE.  */
+      redirect_edge_var_map_dup (s, e);
+      remove_edge (e);
+      e = s;
+    }
+  else
+    redirect_edge_succ (e, new_succ);
+
+  return e;
+}
+
 /* Redirect the edge E to basic block DEST even if it requires creating
    of a new basic block; then it returns the newly created basic block.
    Aborts when redirection is impossible.  */
@@ -436,7 +477,6 @@ split_block (basic_block bb, void *i)
 
   new_bb->count = bb->count;
   new_bb->frequency = bb->frequency;
-  new_bb->loop_depth = bb->loop_depth;
   new_bb->discriminator = bb->discriminator;
 
   if (dom_info_available_p (CDI_DOMINATORS))
@@ -508,6 +548,7 @@ delete_basic_block (basic_block bb)
        {
          loop->header = NULL;
          loop->latch = NULL;
+         loops_state_set (LOOPS_NEED_FIXUP);
        }
 
       remove_bb_from_loops (bb);
@@ -683,7 +724,29 @@ merge_blocks (basic_block a, basic_block b)
   cfg_hooks->merge_blocks (a, b);
 
   if (current_loops != NULL)
-    remove_bb_from_loops (b);
+    {
+      /* If the block we merge into is a loop header do nothing unless ... */
+      if (a->loop_father->header == a)
+       {
+         /* ... we merge two loop headers, in which case we kill
+            the inner loop.  */
+         if (b->loop_father->header == b)
+           {
+             b->loop_father->header = NULL;
+             b->loop_father->latch = NULL;
+             loops_state_set (LOOPS_NEED_FIXUP);
+           }
+       }
+      /* If we merge a loop header into its predecessor, update the loop
+        structure.  */
+      else if (b->loop_father->header == b)
+       {
+         remove_bb_from_loops (a);
+         add_bb_to_loop  (a, b->loop_father);
+         a->loop_father->header = a;
+       }
+      remove_bb_from_loops (b);
+    }
 
   /* Normally there should only be one successor of A and that is B, but
      partway though the merge of blocks for conditional_execution we'll
@@ -698,7 +761,12 @@ merge_blocks (basic_block a, basic_block b)
     {
       e->src = a;
       if (current_loops != NULL)
-       rescan_loop_exit (e, true, false);
+       {
+         /* If b was a latch, a now is.  */
+         if (e->dest->loop_father->latch == b)
+           e->dest->loop_father->latch = a;
+         rescan_loop_exit (e, true, false);
+       }
     }
   a->succs = b->succs;
   a->flags |= b->flags;
@@ -778,11 +846,12 @@ make_forwarder_block (basic_block bb, bool (*redirect_edge_p) (edge),
 
   if (dom_info_available_p (CDI_DOMINATORS))
     {
-      VEC (basic_block, heap) *doms_to_fix = VEC_alloc (basic_block, heap, 2);
-      VEC_quick_push (basic_block, doms_to_fix, dummy);
-      VEC_quick_push (basic_block, doms_to_fix, bb);
+      vec<basic_block> doms_to_fix;
+      doms_to_fix.create (2);
+      doms_to_fix.quick_push (dummy);
+      doms_to_fix.quick_push (bb);
       iterate_fix_dominators (CDI_DOMINATORS, doms_to_fix, false);
-      VEC_free (basic_block, heap, doms_to_fix);
+      doms_to_fix.release ();
     }
 
   if (current_loops != NULL)
@@ -948,7 +1017,6 @@ duplicate_block (basic_block bb, edge e, basic_block after)
   if (after)
     move_block_after (new_bb, after);
 
-  new_bb->loop_depth = bb->loop_depth;
   new_bb->flags = bb->flags;
   FOR_EACH_EDGE (s, ei, bb->succs)
     {
@@ -998,7 +1066,29 @@ duplicate_block (basic_block bb, edge e, basic_block after)
     {
       struct loop *cloop = bb->loop_father;
       struct loop *copy = get_loop_copy (cloop);
-      add_bb_to_loop (new_bb, copy ? copy : cloop);
+      /* If we copied the loop header block but not the loop
+        we have created a loop with multiple entries.  Ditch the loop,
+        add the new block to the outer loop and arrange for a fixup.  */
+      if (!copy
+         && cloop->header == bb)
+       {
+         add_bb_to_loop (new_bb, loop_outer (cloop));
+         cloop->header = NULL;
+         cloop->latch = NULL;
+         loops_state_set (LOOPS_NEED_FIXUP);
+       }
+      else
+       {
+         add_bb_to_loop (new_bb, copy ? copy : cloop);
+         /* If we copied the loop latch block but not the loop, adjust
+            loop state.  */
+         if (!copy
+             && cloop->latch == bb)
+           {
+             cloop->latch = NULL;
+             loops_state_set (LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
+           }
+       }
     }
 
   return new_bb;
@@ -1087,7 +1177,7 @@ bool
 cfg_hook_duplicate_loop_to_header_edge (struct loop *loop, edge e,
                                        unsigned int ndupl,
                                        sbitmap wont_exit, edge orig,
-                                       VEC (edge, heap) **to_remove,
+                                       vec<edge> *to_remove,
                                        int flags)
 {
   gcc_assert (cfg_hooks->cfg_hook_duplicate_loop_to_header_edge);
@@ -1128,3 +1218,199 @@ lv_add_condition_to_bb (basic_block first, basic_block second,
   gcc_assert (cfg_hooks->lv_add_condition_to_bb);
   cfg_hooks->lv_add_condition_to_bb (first, second, new_block, cond);
 }
+
+/* Checks whether all N blocks in BBS array can be copied.  */
+bool
+can_copy_bbs_p (basic_block *bbs, unsigned n)
+{
+  unsigned i;
+  edge e;
+  int ret = true;
+
+  for (i = 0; i < n; i++)
+    bbs[i]->flags |= BB_DUPLICATED;
+
+  for (i = 0; i < n; i++)
+    {
+      /* In case we should redirect abnormal edge during duplication, fail.  */
+      edge_iterator ei;
+      FOR_EACH_EDGE (e, ei, bbs[i]->succs)
+       if ((e->flags & EDGE_ABNORMAL)
+           && (e->dest->flags & BB_DUPLICATED))
+         {
+           ret = false;
+           goto end;
+         }
+
+      if (!can_duplicate_block_p (bbs[i]))
+       {
+         ret = false;
+         break;
+       }
+    }
+
+end:
+  for (i = 0; i < n; i++)
+    bbs[i]->flags &= ~BB_DUPLICATED;
+
+  return ret;
+}
+
+/* Duplicates N basic blocks stored in array BBS.  Newly created basic blocks
+   are placed into array NEW_BBS in the same order.  Edges from basic blocks
+   in BBS are also duplicated and copies of those of them
+   that lead into BBS are redirected to appropriate newly created block.  The
+   function assigns bbs into loops (copy of basic block bb is assigned to
+   bb->loop_father->copy loop, so this must be set up correctly in advance)
+   and updates dominators locally (LOOPS structure that contains the information
+   about dominators is passed to enable this).
+
+   BASE is the superloop to that basic block belongs; if its header or latch
+   is copied, we do not set the new blocks as header or latch.
+
+   Created copies of N_EDGES edges in array EDGES are stored in array NEW_EDGES,
+   also in the same order.
+
+   Newly created basic blocks are put after the basic block AFTER in the
+   instruction stream, and the order of the blocks in BBS array is preserved.  */
+
+void
+copy_bbs (basic_block *bbs, unsigned n, basic_block *new_bbs,
+         edge *edges, unsigned num_edges, edge *new_edges,
+         struct loop *base, basic_block after)
+{
+  unsigned i, j;
+  basic_block bb, new_bb, dom_bb;
+  edge e;
+
+  /* Duplicate bbs, update dominators, assign bbs to loops.  */
+  for (i = 0; i < n; i++)
+    {
+      /* Duplicate.  */
+      bb = bbs[i];
+      new_bb = new_bbs[i] = duplicate_block (bb, NULL, after);
+      after = new_bb;
+      bb->flags |= BB_DUPLICATED;
+      if (bb->loop_father)
+       {
+         /* Possibly set loop header.  */
+         if (bb->loop_father->header == bb && bb->loop_father != base)
+           new_bb->loop_father->header = new_bb;
+         /* Or latch.  */
+         if (bb->loop_father->latch == bb && bb->loop_father != base)
+           new_bb->loop_father->latch = new_bb;
+       }
+    }
+
+  /* Set dominators.  */
+  for (i = 0; i < n; i++)
+    {
+      bb = bbs[i];
+      new_bb = new_bbs[i];
+
+      dom_bb = get_immediate_dominator (CDI_DOMINATORS, bb);
+      if (dom_bb->flags & BB_DUPLICATED)
+       {
+         dom_bb = get_bb_copy (dom_bb);
+         set_immediate_dominator (CDI_DOMINATORS, new_bb, dom_bb);
+       }
+    }
+
+  /* Redirect edges.  */
+  for (j = 0; j < num_edges; j++)
+    new_edges[j] = NULL;
+  for (i = 0; i < n; i++)
+    {
+      edge_iterator ei;
+      new_bb = new_bbs[i];
+      bb = bbs[i];
+
+      FOR_EACH_EDGE (e, ei, new_bb->succs)
+       {
+         for (j = 0; j < num_edges; j++)
+           if (edges[j] && edges[j]->src == bb && edges[j]->dest == e->dest)
+             new_edges[j] = e;
+
+         if (!(e->dest->flags & BB_DUPLICATED))
+           continue;
+         redirect_edge_and_branch_force (e, get_bb_copy (e->dest));
+       }
+    }
+
+  /* Clear information about duplicates.  */
+  for (i = 0; i < n; i++)
+    bbs[i]->flags &= ~BB_DUPLICATED;
+}
+
+/* Return true if BB contains only labels or non-executable
+   instructions */
+bool
+empty_block_p (basic_block bb)
+{
+  gcc_assert (cfg_hooks->empty_block_p);
+  return cfg_hooks->empty_block_p (bb);
+}
+
+/* Split a basic block if it ends with a conditional branch and if
+   the other part of the block is not empty.  */
+basic_block
+split_block_before_cond_jump (basic_block bb)
+{
+  gcc_assert (cfg_hooks->split_block_before_cond_jump);
+  return cfg_hooks->split_block_before_cond_jump (bb);
+}
+
+/* Work-horse for passes.c:check_profile_consistency.
+   Do book-keeping of the CFG for the profile consistency checker.
+   If AFTER_PASS is 0, do pre-pass accounting, or if AFTER_PASS is 1
+   then do post-pass accounting.  Store the counting in RECORD.  */
+
+void
+account_profile_record (struct profile_record *record, int after_pass)
+{
+  basic_block bb;
+  edge_iterator ei;
+  edge e;
+  int sum;
+  gcov_type lsum;
+
+  FOR_ALL_BB (bb)
+   {
+      if (bb != EXIT_BLOCK_PTR_FOR_FUNCTION (cfun)
+         && profile_status != PROFILE_ABSENT)
+       {
+         sum = 0;
+         FOR_EACH_EDGE (e, ei, bb->succs)
+           sum += e->probability;
+         if (EDGE_COUNT (bb->succs) && abs (sum - REG_BR_PROB_BASE) > 100)
+           record->num_mismatched_freq_out[after_pass]++;
+         lsum = 0;
+         FOR_EACH_EDGE (e, ei, bb->succs)
+           lsum += e->count;
+         if (EDGE_COUNT (bb->succs)
+             && (lsum - bb->count > 100 || lsum - bb->count < -100))
+           record->num_mismatched_count_out[after_pass]++;
+       }
+      if (bb != ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun)
+         && profile_status != PROFILE_ABSENT)
+       {
+         sum = 0;
+         FOR_EACH_EDGE (e, ei, bb->preds)
+           sum += EDGE_FREQUENCY (e);
+         if (abs (sum - bb->frequency) > 100
+             || (MAX (sum, bb->frequency) > 10
+                 && abs ((sum - bb->frequency) * 100 / (MAX (sum, bb->frequency) + 1)) > 10))
+           record->num_mismatched_freq_in[after_pass]++;
+         lsum = 0;
+         FOR_EACH_EDGE (e, ei, bb->preds)
+           lsum += e->count;
+         if (lsum - bb->count > 100 || lsum - bb->count < -100)
+           record->num_mismatched_count_in[after_pass]++;
+       }
+      if (bb == ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun)
+         || bb == EXIT_BLOCK_PTR_FOR_FUNCTION (cfun))
+       continue;
+      gcc_assert (cfg_hooks->account_profile_record);
+      cfg_hooks->account_profile_record(bb, after_pass, record);
+   }
+}