]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/cfghooks.c
libgo: update to Go 1.12.2
[thirdparty/gcc.git] / gcc / cfghooks.c
index d436f011fac35409b214e4e2661d1856ff61c40a..a1d603a207ec7791a3101060e1126c395507ea62 100644 (file)
@@ -1,12 +1,12 @@
 /* Hooks for cfg representation specific functions.
-   Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2003-2019 Free Software Foundation, Inc.
    Contributed by Sebastian Pop <s.pop@laposte.net>
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -15,20 +15,21 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "tree.h"
+#include "backend.h"
 #include "rtl.h"
-#include "basic-block.h"
-#include "tree-flow.h"
+#include "cfghooks.h"
 #include "timevar.h"
-#include "toplev.h"
+#include "pretty-print.h"
+#include "diagnostic-core.h"
+#include "dumpfile.h"
+#include "cfganal.h"
+#include "tree-ssa.h"
 #include "cfgloop.h"
 
 /* A pointer to one of the hooks containers.  */
@@ -51,9 +52,21 @@ cfg_layout_rtl_register_cfg_hooks (void)
 /* Initialization of functions specific to the tree IR.  */
 
 void
-tree_register_cfg_hooks (void)
+gimple_register_cfg_hooks (void)
 {
-  cfg_hooks = &tree_cfg_hooks;
+  cfg_hooks = &gimple_cfg_hooks;
+}
+
+struct cfg_hooks
+get_cfg_hooks (void)
+{
+  return *cfg_hooks;
+}
+
+void
+set_cfg_hooks (struct cfg_hooks new_cfg_hooks)
+{
+  *cfg_hooks = new_cfg_hooks;
 }
 
 /* Returns current ir type.  */
@@ -61,7 +74,7 @@ tree_register_cfg_hooks (void)
 enum ir_type
 current_ir_type (void)
 {
-  if (cfg_hooks == &tree_cfg_hooks)
+  if (cfg_hooks == &gimple_cfg_hooks)
     return IR_GIMPLE;
   else if (cfg_hooks == &rtl_cfg_hooks)
     return IR_RTL_CFGRTL;
@@ -76,7 +89,7 @@ current_ir_type (void)
    Currently it does following: checks edge and basic block list correctness
    and calls into IL dependent checking then.  */
 
-void
+DEBUG_FUNCTION void
 verify_flow_info (void)
 {
   size_t *edge_checksum;
@@ -85,15 +98,15 @@ verify_flow_info (void)
   basic_block *last_visited;
 
   timevar_push (TV_CFG_VERIFY);
-  last_visited = XCNEWVEC (basic_block, last_basic_block);
-  edge_checksum = XCNEWVEC (size_t, last_basic_block);
+  last_visited = XCNEWVEC (basic_block, last_basic_block_for_fn (cfun));
+  edge_checksum = XCNEWVEC (size_t, last_basic_block_for_fn (cfun));
 
   /* Check bb chain & numbers.  */
-  last_bb_seen = ENTRY_BLOCK_PTR;
-  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR->next_bb, NULL, next_bb)
+  last_bb_seen = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb, NULL, next_bb)
     {
-      if (bb != EXIT_BLOCK_PTR
-         && bb != BASIC_BLOCK (bb->index))
+      if (bb != EXIT_BLOCK_PTR_FOR_FN (cfun)
+         && bb != BASIC_BLOCK_FOR_FN (cfun, bb->index))
        {
          error ("bb %d on wrong place", bb->index);
          err = 1;
@@ -110,7 +123,7 @@ verify_flow_info (void)
     }
 
   /* Now check the basic blocks (boundaries etc.) */
-  FOR_EACH_BB_REVERSE (bb)
+  FOR_EACH_BB_REVERSE_FN (bb, cfun)
     {
       int n_fallthru = 0;
       edge e;
@@ -128,18 +141,20 @@ verify_flow_info (void)
          err = 1;
        }
 
-      if (bb->count < 0)
+      if (!bb->count.verify ())
        {
-         error ("verify_flow_info: Wrong count of block %i %i",
-                bb->index, (int)bb->count);
+         error ("verify_flow_info: Wrong count of block %i", bb->index);
          err = 1;
        }
-      if (bb->frequency < 0)
+      /* FIXME: Graphite and SLJL and target code still tends to produce
+        edges with no probablity.  */
+      if (profile_status_for_fn (cfun) >= PROFILE_GUESSED
+          && !bb->count.initialized_p () && !flag_graphite && 0)
        {
-         error ("verify_flow_info: Wrong frequency of block %i %i",
-                bb->index, bb->frequency);
+         error ("verify_flow_info: Missing count of block %i", bb->index);
          err = 1;
        }
+
       FOR_EACH_EDGE (e, ei, bb->succs)
        {
          if (last_visited [e->dest->index] == bb)
@@ -148,16 +163,19 @@ verify_flow_info (void)
                     e->src->index, e->dest->index);
              err = 1;
            }
-         if (e->probability < 0 || e->probability > REG_BR_PROB_BASE)
+         /* FIXME: Graphite and SLJL and target code still tends to produce
+            edges with no probablity.  */
+         if (profile_status_for_fn (cfun) >= PROFILE_GUESSED
+             && !e->probability.initialized_p () && !flag_graphite && 0)
            {
-             error ("verify_flow_info: Wrong probability of edge %i->%i %i",
-                    e->src->index, e->dest->index, e->probability);
+             error ("Uninitialized probability of edge %i->%i", e->src->index,
+                    e->dest->index);
              err = 1;
            }
-         if (e->count < 0)
+         if (!e->probability.verify ())
            {
-             error ("verify_flow_info: Wrong count of edge %i->%i %i",
-                    e->src->index, e->dest->index, (int)e->count);
+             error ("verify_flow_info: Wrong probability of edge %i->%i",
+                    e->src->index, e->dest->index);
              err = 1;
            }
 
@@ -171,9 +189,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;
            }
@@ -192,9 +210,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;
            }
@@ -205,9 +223,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;
            }
@@ -221,21 +239,21 @@ verify_flow_info (void)
     edge e;
     edge_iterator ei;
 
-    FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
+    FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs)
       edge_checksum[e->dest->index] += (size_t) e;
 
-    FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
+    FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
       edge_checksum[e->dest->index] -= (size_t) e;
   }
 
-  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
     if (edge_checksum[bb->index])
       {
        error ("basic block %i edge lists are corrupted", bb->index);
        err = 1;
       }
 
-  last_bb_seen = ENTRY_BLOCK_PTR;
+  last_bb_seen = ENTRY_BLOCK_PTR_FOR_FN (cfun);
 
   /* Clean up.  */
   free (last_visited);
@@ -248,50 +266,90 @@ 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, dump_flags_t flags)
 {
-  edge e;
-  edge_iterator ei;
-  char *s_indent;
-
-  s_indent = (char *) alloca ((size_t) indent + 1);
-  memset (s_indent, ' ', (size_t) indent);
-  s_indent[indent] = '\0';
+  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);
+}
 
-  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);
+DEBUG_FUNCTION void
+debug (basic_block_def &ref)
+{
+  dump_bb (stderr, &ref, 0, TDF_NONE);
+}
 
-  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);
+DEBUG_FUNCTION void
+debug (basic_block_def *ptr)
+{
+  if (ptr)
+    debug (*ptr);
   else
-    fprintf (outf, "(nil)");
-  putc ('\n', outf);
+    fprintf (stderr, "<nil>\n");
+}
+
+static void
+debug_slim (basic_block ptr)
+{
+  fprintf (stderr, "<basic_block %p (%d)>", (void *) ptr, ptr->index);
+}
 
-  fprintf (outf, ";;%s pred:      ", s_indent);
-  FOR_EACH_EDGE (e, ei, bb->preds)
-    dump_edge_info (outf, e, 0);
-  putc ('\n', outf);
+DEFINE_DEBUG_VEC (basic_block_def *)
+DEFINE_DEBUG_HASH_SET (basic_block_def *)
 
-  fprintf (outf, ";;%s succ:      ", s_indent);
-  FOR_EACH_EDGE (e, ei, bb->succs)
-    dump_edge_info (outf, e, 1);
-  putc ('\n', outf);
+/* 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().  */
 
-  if (cfg_hooks->dump_bb)
-    cfg_hooks->dump_bb (bb, outf, indent);
+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);
+  /* TODO: Add pretty printer for counter.  */
+  if (bb->count.initialized_p ())
+    pp_printf (pp, "COUNT:" "%" PRId64, bb->count.to_gcov_type ());
+  pp_write_text_to_stream (pp);
+  if (!(dump_flags & TDF_SLIM))
+    cfg_hooks->dump_bb_for_graph (pp, bb);
+}
+
+/* Dump the complete CFG to FILE.  FLAGS are the TDF_* flags in dumpfile.h.  */
+void
+dump_flow_info (FILE *file, dump_flags_t flags)
+{
+  basic_block bb;
+
+  fprintf (file, "\n%d basic blocks, %d edges.\n", n_basic_blocks_for_fn (cfun),
+          n_edges_for_fn (cfun));
+  FOR_ALL_BB_FN (bb, cfun)
+    dump_bb (file, bb, 0, flags);
+
+  putc ('\n', file);
+}
+
+/* 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
@@ -322,7 +380,7 @@ redirect_edge_and_branch (edge e, basic_block dest)
    to the destination of the other edge going from its source.  */
 
 bool
-can_remove_branch_p (edge e)
+can_remove_branch_p (const_edge e)
 {
   if (!cfg_hooks->can_remove_branch_p)
     internal_error ("%s does not support can_remove_branch_p",
@@ -363,11 +421,52 @@ void
 remove_edge (edge e)
 {
   if (current_loops != NULL)
-    rescan_loop_exit (e, false, true);
+    {
+      rescan_loop_exit (e, false, true);
+
+      /* Removal of an edge inside an irreducible region or which leads
+        to an irreducible region can turn the region into a natural loop.
+        In that case, ask for the loop structure fixups.
+
+        FIXME: Note that LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS is not always
+        set, so always ask for fixups when removing an edge in that case.  */
+      if (!loops_state_satisfies_p (LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS)
+         || (e->flags & EDGE_IRREDUCIBLE_LOOP)
+         || (e->dest->flags & BB_IRREDUCIBLE_LOOP))
+       loops_state_set (LOOPS_NEED_FIXUP);
+    }
+
+  /* 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;
+      /* 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.  */
@@ -376,7 +475,6 @@ basic_block
 redirect_edge_and_branch_force (edge e, basic_block dest)
 {
   basic_block ret, src = e->src;
-  struct loop *loop;
 
   if (!cfg_hooks->redirect_edge_and_branch_force)
     internal_error ("%s does not support redirect_edge_and_branch_force",
@@ -386,16 +484,17 @@ redirect_edge_and_branch_force (edge e, basic_block dest)
     rescan_loop_exit (e, false, true);
 
   ret = cfg_hooks->redirect_edge_and_branch_force (e, dest);
-  if (ret != NULL
-      && dom_info_available_p (CDI_DOMINATORS))
+
+  if (ret != NULL && dom_info_available_p (CDI_DOMINATORS))
     set_immediate_dominator (CDI_DOMINATORS, ret, src);
 
   if (current_loops != NULL)
     {
       if (ret != NULL)
        {
-         loop = find_common_loop (single_pred (ret)->loop_father,
-                                  single_succ (ret)->loop_father);
+         struct loop *loop
+           = find_common_loop (single_pred (ret)->loop_father,
+                               single_succ (ret)->loop_father);
          add_bb_to_loop (ret, loop);
        }
       else if (find_edge (src, dest) == e)
@@ -409,10 +508,11 @@ redirect_edge_and_branch_force (edge e, basic_block dest)
    the labels).  If I is NULL, splits just after labels.  The newly created edge
    is returned.  The new basic block is created just after the old one.  */
 
-edge
-split_block (basic_block bb, void *i)
+static edge
+split_block_1 (basic_block bb, void *i)
 {
   basic_block new_bb;
+  edge res;
 
   if (!cfg_hooks->split_block)
     internal_error ("%s does not support split_block", cfg_hooks->name);
@@ -422,8 +522,7 @@ split_block (basic_block bb, void *i)
     return NULL;
 
   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))
     {
@@ -432,9 +531,37 @@ split_block (basic_block bb, void *i)
     }
 
   if (current_loops != NULL)
-    add_bb_to_loop (new_bb, bb->loop_father);
+    {
+      edge_iterator ei;
+      edge e;
+      add_bb_to_loop (new_bb, bb->loop_father);
+      /* Identify all loops bb may have been the latch of and adjust them.  */
+      FOR_EACH_EDGE (e, ei, new_bb->succs)
+       if (e->dest->loop_father->latch == bb)
+         e->dest->loop_father->latch = new_bb;
+    }
+
+  res = make_single_succ_edge (bb, new_bb, EDGE_FALLTHRU);
+
+  if (bb->flags & BB_IRREDUCIBLE_LOOP)
+    {
+      new_bb->flags |= BB_IRREDUCIBLE_LOOP;
+      res->flags |= EDGE_IRREDUCIBLE_LOOP;
+    }
+
+  return res;
+}
 
-  return make_single_succ_edge (bb, new_bb, EDGE_FALLTHRU);
+edge
+split_block (basic_block bb, gimple *i)
+{
+  return split_block_1 (bb, i);
+}
+
+edge
+split_block (basic_block bb, rtx i)
+{
+  return split_block_1 (bb, i);
 }
 
 /* Splits block BB just after labels.  The newly created edge is returned.  */
@@ -442,7 +569,7 @@ split_block (basic_block bb, void *i)
 edge
 split_block_after_labels (basic_block bb)
 {
-  return split_block (bb, NULL);
+  return split_block_1 (bb, NULL);
 }
 
 /* Moves block BB immediately after block AFTER.  Returns false if the
@@ -476,13 +603,10 @@ delete_basic_block (basic_block bb)
       struct loop *loop = bb->loop_father;
 
       /* If we remove the header or the latch of a loop, mark the loop for
-        removal by setting its header and latch to NULL.  */
+        removal.  */
       if (loop->latch == bb
          || loop->header == bb)
-       {
-         loop->header = NULL;
-         loop->latch = NULL;
-       }
+       mark_loop_for_removal (loop);
 
       remove_bb_from_loops (bb);
     }
@@ -509,8 +633,7 @@ basic_block
 split_edge (edge e)
 {
   basic_block ret;
-  gcov_type count = e->count;
-  int freq = EDGE_FREQUENCY (e);
+  profile_count count = e->count ();
   edge f;
   bool irr = (e->flags & EDGE_IRREDUCIBLE_LOOP) != 0;
   struct loop *loop;
@@ -524,9 +647,7 @@ split_edge (edge e)
 
   ret = cfg_hooks->split_edge (e);
   ret->count = count;
-  ret->frequency = freq;
-  single_succ_edge (ret)->probability = REG_BR_PROB_BASE;
-  single_succ_edge (ret)->count = count;
+  single_succ_edge (ret)->probability = profile_probability::always ();
 
   if (irr)
     {
@@ -573,7 +694,9 @@ split_edge (edge e)
       loop = find_common_loop (src->loop_father, dest->loop_father);
       add_bb_to_loop (ret, loop);
 
-      if (loop->latch == src)
+      /* If we split the latch edge of loop adjust the latch block.  */
+      if (loop->latch == src
+         && loop->header == dest)
        loop->latch = ret;
     }
 
@@ -584,8 +707,8 @@ split_edge (edge e)
    HEAD and END are the first and the last statement belonging
    to the block.  If both are NULL, an empty block is created.  */
 
-basic_block
-create_basic_block (void *head, void *end, basic_block after)
+static basic_block
+create_basic_block_1 (void *head, void *end, basic_block after)
 {
   basic_block ret;
 
@@ -602,12 +725,25 @@ create_basic_block (void *head, void *end, basic_block after)
   return ret;
 }
 
+basic_block
+create_basic_block (gimple_seq seq, basic_block after)
+{
+  return create_basic_block_1 (seq, NULL, after);
+}
+
+basic_block
+create_basic_block (rtx head, rtx end, basic_block after)
+{
+  return create_basic_block_1 (head, end, after);
+}
+
+
 /* Creates an empty basic block just after basic block AFTER.  */
 
 basic_block
 create_empty_bb (basic_block after)
 {
-  return create_basic_block (NULL, NULL, after);
+  return create_basic_block_1 (NULL, NULL, after);
 }
 
 /* Checks whether we may merge blocks BB1 and BB2.  */
@@ -635,7 +771,7 @@ predict_edge (edge e, enum br_predictor predictor, int probability)
 }
 
 bool
-predicted_by_p (basic_block bb, enum br_predictor predictor)
+predicted_by_p (const_basic_block bb, enum br_predictor predictor)
 {
   if (!cfg_hooks->predict_edge)
     internal_error ("%s does not support predicted_by_p", cfg_hooks->name);
@@ -657,7 +793,30 @@ 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)
+           mark_loop_for_removal (b->loop_father);
+       }
+      /* 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;
+       }
+      /* If we merge a loop latch into its predecessor, update the loop
+         structure.  */
+      if (b->loop_father->latch
+         && b->loop_father->latch == b)
+       b->loop_father->latch = 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
@@ -672,7 +831,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;
@@ -710,40 +874,46 @@ make_forwarder_block (basic_block bb, bool (*redirect_edge_p) (edge),
 
   fallthru = split_block_after_labels (bb);
   dummy = fallthru->src;
+  dummy->count = profile_count::zero ();
   bb = fallthru->dest;
 
   /* Redirect back edges we want to keep.  */
   for (ei = ei_start (dummy->preds); (e = ei_safe_edge (ei)); )
     {
+      basic_block e_src;
+
       if (redirect_edge_p (e))
        {
+         dummy->count += e->count ();
          ei_next (&ei);
          continue;
        }
 
-      dummy->frequency -= EDGE_FREQUENCY (e);
-      dummy->count -= e->count;
-      if (dummy->frequency < 0)
-       dummy->frequency = 0;
-      if (dummy->count < 0)
-       dummy->count = 0;
-      fallthru->count -= e->count;
-      if (fallthru->count < 0)
-       fallthru->count = 0;
-
+      e_src = e->src;
       jump = redirect_edge_and_branch_force (e, bb);
-      if (jump != NULL
-         && new_bb_cbk != NULL)
-       new_bb_cbk (jump);
+      if (jump != NULL)
+        {
+          /* If we redirected the loop latch edge, the JUMP block now acts like
+             the new latch of the loop.  */
+          if (current_loops != NULL
+              && dummy->loop_father != NULL
+              && dummy->loop_father->header == dummy
+              && dummy->loop_father->latch == e_src)
+            dummy->loop_father->latch = jump;
+
+          if (new_bb_cbk != NULL)
+            new_bb_cbk (jump);
+        }
     }
 
   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)
@@ -781,6 +951,8 @@ make_forwarder_block (basic_block bb, bool (*redirect_edge_p) (edge),
   return fallthru;
 }
 
+/* Try to make the edge fallthru.  */
+
 void
 tidy_fallthru_edge (edge e)
 {
@@ -791,7 +963,9 @@ tidy_fallthru_edge (edge e)
 /* Fix up edges that now fall through, or rather should now fall through
    but previously required a jump around now deleted blocks.  Simplify
    the search by only examining blocks numerically adjacent, since this
-   is how find_basic_blocks created them.  */
+   is how they were created.
+
+   ??? This routine is currently RTL specific.  */
 
 void
 tidy_fallthru_edges (void)
@@ -801,10 +975,11 @@ tidy_fallthru_edges (void)
   if (!cfg_hooks->tidy_fallthru_edge)
     return;
 
-  if (ENTRY_BLOCK_PTR->next_bb == EXIT_BLOCK_PTR)
+  if (ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
     return;
 
-  FOR_BB_BETWEEN (b, ENTRY_BLOCK_PTR->next_bb, EXIT_BLOCK_PTR->prev_bb, next_bb)
+  FOR_BB_BETWEEN (b, ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb,
+                 EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb, next_bb)
     {
       edge s;
 
@@ -814,9 +989,9 @@ tidy_fallthru_edges (void)
         a single successor.
 
         If we had a conditional branch to the next instruction when
-        find_basic_blocks was called, then there will only be one
-        out edge for the block which ended with the conditional
-        branch (since we do not create duplicate edges).
+        CFG was built, then there will only be one out edge for the
+        block which ended with the conditional branch (since we do
+        not create duplicate edges).
 
         Furthermore, the edge will be marked as a fallthru because we
         merge the flags for the duplicate edges.  So we do not want to
@@ -827,22 +1002,60 @@ tidy_fallthru_edges (void)
          s = single_succ_edge (b);
          if (! (s->flags & EDGE_COMPLEX)
              && s->dest == c
-             && !find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX))
+             && !(JUMP_P (BB_END (b)) && CROSSING_JUMP_P (BB_END (b))))
            tidy_fallthru_edge (s);
        }
     }
 }
 
+/* Edge E is assumed to be fallthru edge.  Emit needed jump instruction
+   (and possibly create new basic block) to make edge non-fallthru.
+   Return newly created BB or NULL if none.  */
+
+basic_block
+force_nonfallthru (edge e)
+{
+  basic_block ret, src = e->src;
+
+  if (!cfg_hooks->force_nonfallthru)
+    internal_error ("%s does not support force_nonfallthru",
+                   cfg_hooks->name);
+
+  ret = cfg_hooks->force_nonfallthru (e);
+  if (ret != NULL)
+    {
+      if (dom_info_available_p (CDI_DOMINATORS))
+       set_immediate_dominator (CDI_DOMINATORS, ret, src);
+
+      if (current_loops != NULL)
+       {
+         basic_block pred = single_pred (ret);
+         basic_block succ = single_succ (ret);
+         struct loop *loop
+           = find_common_loop (pred->loop_father, succ->loop_father);
+         rescan_loop_exit (e, false, true);
+         add_bb_to_loop (ret, loop);
+
+         /* If we split the latch edge of loop adjust the latch block.  */
+         if (loop->latch == pred
+             && loop->header == succ)
+           loop->latch = ret;
+       }
+    }
+
+  return ret;
+}
+
 /* Returns true if we can duplicate basic block BB.  */
 
 bool
-can_duplicate_block_p (basic_block bb)
+can_duplicate_block_p (const_basic_block bb)
 {
   if (!cfg_hooks->can_duplicate_block_p)
     internal_error ("%s does not support can_duplicate_block_p",
                    cfg_hooks->name);
 
-  if (bb == EXIT_BLOCK_PTR || bb == ENTRY_BLOCK_PTR)
+  if (bb == EXIT_BLOCK_PTR_FOR_FN (cfun) || bb == ENTRY_BLOCK_PTR_FOR_FN (cfun))
     return false;
 
   return cfg_hooks->can_duplicate_block_p (bb);
@@ -853,11 +1066,11 @@ can_duplicate_block_p (basic_block bb)
    AFTER.  */
 
 basic_block
-duplicate_block (basic_block bb, edge e, basic_block after)
+duplicate_block (basic_block bb, edge e, basic_block after, copy_bb_data *id)
 {
   edge s, n;
   basic_block new_bb;
-  gcov_type new_count = e ? e->count : 0;
+  profile_count new_count = e ? e->count (): profile_count::uninitialized ();
   edge_iterator ei;
 
   if (!cfg_hooks->duplicate_block)
@@ -867,16 +1080,13 @@ duplicate_block (basic_block bb, edge e, basic_block after)
   if (bb->count < new_count)
     new_count = bb->count;
 
-#ifdef ENABLE_CHECKING
-  gcc_assert (can_duplicate_block_p (bb));
-#endif
+  gcc_checking_assert (can_duplicate_block_p (bb));
 
-  new_bb = cfg_hooks->duplicate_block (bb);
+  new_bb = cfg_hooks->duplicate_block (bb, id);
   if (after)
     move_block_after (new_bb, after);
 
-  new_bb->loop_depth = bb->loop_depth;
-  new_bb->flags = bb->flags;
+  new_bb->flags = (bb->flags & ~BB_DUPLICATED);
   FOR_EACH_EDGE (s, ei, bb->succs)
     {
       /* Since we are creating edges from a new block to successors
@@ -884,14 +1094,6 @@ duplicate_block (basic_block bb, edge e, basic_block after)
         is no need to actually check for duplicated edges.  */
       n = unchecked_make_edge (new_bb, s->dest, s->flags);
       n->probability = s->probability;
-      if (e && bb->count)
-       {
-         /* Take care for overflows!  */
-         n->count = s->count * (new_count * 10000 / bb->count) / 10000;
-         s->count -= n->count;
-       }
-      else
-       n->count = s->count;
       n->aux = s->aux;
     }
 
@@ -900,21 +1102,10 @@ duplicate_block (basic_block bb, edge e, basic_block after)
       new_bb->count = new_count;
       bb->count -= new_count;
 
-      new_bb->frequency = EDGE_FREQUENCY (e);
-      bb->frequency -= EDGE_FREQUENCY (e);
-
       redirect_edge_and_branch_force (e, new_bb);
-
-      if (bb->count < 0)
-       bb->count = 0;
-      if (bb->frequency < 0)
-       bb->frequency = 0;
     }
   else
-    {
-      new_bb->count = bb->count;
-      new_bb->frequency = bb->frequency;
-    }
+    new_bb->count = bb->count;
 
   set_bb_original (new_bb, bb);
   set_bb_copy (bb, new_bb);
@@ -925,7 +1116,27 @@ 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));
+         mark_loop_for_removal (cloop);
+       }
+      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;
@@ -946,7 +1157,7 @@ block_ends_with_call_p (basic_block bb)
 /* Return 1 if BB ends with a conditional branch, 0 otherwise.  */
 
 bool
-block_ends_with_condjump_p (basic_block bb)
+block_ends_with_condjump_p (const_basic_block bb)
 {
   if (!cfg_hooks->block_ends_with_condjump_p)
     internal_error ("%s does not support block_ends_with_condjump_p",
@@ -979,7 +1190,8 @@ flow_call_edges_add (sbitmap blocks)
 void
 execute_on_growing_pred (edge e)
 {
-  if (cfg_hooks->execute_on_growing_pred)
+  if (! (e->dest->flags & BB_DUPLICATED)
+      && cfg_hooks->execute_on_growing_pred)
     cfg_hooks->execute_on_growing_pred (e);
 }
 
@@ -989,7 +1201,8 @@ execute_on_growing_pred (edge e)
 void
 execute_on_shrinking_pred (edge e)
 {
-  if (cfg_hooks->execute_on_shrinking_pred)
+  if (! (e->dest->flags & BB_DUPLICATED)
+      && cfg_hooks->execute_on_shrinking_pred)
     cfg_hooks->execute_on_shrinking_pred (e);
 }
 
@@ -1014,7 +1227,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);
@@ -1026,7 +1239,7 @@ cfg_hook_duplicate_loop_to_header_edge (struct loop *loop, edge e,
 
 /* Conditional jumps are represented differently in trees and RTL,
    this hook takes a basic block that is known to have a cond jump
-   at its end and extracts the taken and not taken eges out of it
+   at its end and extracts the taken and not taken edges out of it
    and store it in E1 and E2 respectively.  */
 void
 extract_cond_bb_edges (basic_block b, edge *e1, edge *e2)
@@ -1055,3 +1268,226 @@ 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 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)
+
+   If UPDATE_DOMINANCE is true then this function updates dominators locally
+   (LOOPS structure that contains the information about dominators is passed
+   to enable this), otherwise it does not update the dominator information
+   and it assumed that the caller will do this, perhaps by destroying and
+   recreating it instead of trying to do an incremental update like this
+   function does when update_dominance is true.
+
+   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, bool update_dominance)
+{
+  unsigned i, j;
+  basic_block bb, new_bb, dom_bb;
+  edge e;
+  copy_bb_data id;
+
+  /* Mark the blocks to be copied.  This is used by edge creation hooks
+     to decide whether to reallocate PHI nodes capacity to avoid reallocating
+     PHIs in the set of source BBs.  */
+  for (i = 0; i < n; i++)
+    bbs[i]->flags |= BB_DUPLICATED;
+
+  /* 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, &id);
+      after = new_bb;
+      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.  */
+  if (update_dominance)
+    {
+      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.
+   Store the counting in RECORD.  */
+
+void
+profile_record_check_consistency (profile_record *record)
+{
+  basic_block bb;
+  edge_iterator ei;
+  edge e;
+
+  FOR_ALL_BB_FN (bb, cfun)
+   {
+      if (bb != EXIT_BLOCK_PTR_FOR_FN (cfun)
+         && profile_status_for_fn (cfun) != PROFILE_ABSENT)
+       {
+         profile_probability sum = profile_probability::never ();
+         FOR_EACH_EDGE (e, ei, bb->succs)
+           sum += e->probability;
+         if (EDGE_COUNT (bb->succs)
+             && sum.differs_from_p (profile_probability::always ()))
+           record->num_mismatched_freq_out++;
+         profile_count lsum = profile_count::zero ();
+         FOR_EACH_EDGE (e, ei, bb->succs)
+           lsum += e->count ();
+         if (EDGE_COUNT (bb->succs) && (lsum.differs_from_p (bb->count)))
+           record->num_mismatched_count_out++;
+       }
+      if (bb != ENTRY_BLOCK_PTR_FOR_FN (cfun)
+         && profile_status_for_fn (cfun) != PROFILE_ABSENT)
+       {
+         profile_probability sum = profile_probability::never ();
+         profile_count lsum = profile_count::zero ();
+         FOR_EACH_EDGE (e, ei, bb->preds)
+           {
+             sum += e->probability;
+             lsum += e->count ();
+           }
+         if (EDGE_COUNT (bb->preds)
+             && sum.differs_from_p (profile_probability::always ()))
+           record->num_mismatched_freq_in++;
+         if (lsum.differs_from_p (bb->count))
+           record->num_mismatched_count_in++;
+       }
+      if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)
+         || bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
+       continue;
+      gcc_assert (cfg_hooks->account_profile_record);
+      cfg_hooks->account_profile_record (bb, record);
+   }
+}
+
+/* Work-horse for passes.c:acount_profile.
+   Do book-keeping of the CFG for the profile accounting.
+   Store the counting in RECORD.  */
+
+void
+profile_record_account_profile (profile_record *record)
+{
+  basic_block bb;
+
+  FOR_ALL_BB_FN (bb, cfun)
+   {
+      gcc_assert (cfg_hooks->account_profile_record);
+      cfg_hooks->account_profile_record (bb, record);
+   }
+}