]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/cfgrtl.c
PR fortran/95090 - ICE: identifier overflow
[thirdparty/gcc.git] / gcc / cfgrtl.c
index 2e33dda2f81581062ad411a7234e54e5e4110dfe..827e84a44ddd957b3d0d37c1313b9e6cef190a1c 100644 (file)
@@ -1,5 +1,5 @@
 /* Control flow graph manipulation code for GNU compiler.
-   Copyright (C) 1987-2015 Free Software Foundation, Inc.
+   Copyright (C) 1987-2020 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -40,43 +40,33 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "alias.h"
-#include "symtab.h"
+#include "backend.h"
+#include "target.h"
+#include "rtl.h"
 #include "tree.h"
-#include "hard-reg-set.h"
-#include "predict.h"
-#include "function.h"
-#include "dominance.h"
-#include "cfg.h"
+#include "cfghooks.h"
+#include "df.h"
+#include "insn-config.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
 #include "cfgrtl.h"
 #include "cfganal.h"
 #include "cfgbuild.h"
 #include "cfgcleanup.h"
-#include "basic-block.h"
 #include "bb-reorder.h"
-#include "regs.h"
-#include "flags.h"
-#include "except.h"
 #include "rtl-error.h"
-#include "tm_p.h"
-#include "obstack.h"
 #include "insn-attr.h"
-#include "insn-config.h"
-#include "rtl.h"
-#include "expmed.h"
 #include "dojump.h"
-#include "explow.h"
-#include "calls.h"
-#include "emit-rtl.h"
-#include "varasm.h"
-#include "stmt.h"
 #include "expr.h"
-#include "target.h"
-#include "common/common-target.h"
 #include "cfgloop.h"
 #include "tree-pass.h"
-#include "df.h"
+#include "print-rtl.h"
+
+/* Disable warnings about missing quoting in GCC diagnostics.  */
+#if __GNUC__ >= 10
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wformat-diag"
+#endif
 
 /* Holds the interesting leading and trailing notes for the function.
    Only applicable if the CFG is in cfglayout mode.  */
@@ -102,7 +92,7 @@ static void rtl_delete_block (basic_block);
 static basic_block rtl_redirect_edge_and_branch_force (edge, basic_block);
 static edge rtl_redirect_edge_and_branch (edge, basic_block);
 static basic_block rtl_split_block (basic_block, void *);
-static void rtl_dump_bb (FILE *, basic_block, int, int);
+static void rtl_dump_bb (FILE *, basic_block, int, dump_flags_t);
 static int rtl_verify_flow_info_1 (void);
 static void rtl_make_forwarder_block (edge);
 \f
@@ -132,15 +122,15 @@ can_delete_label_p (const rtx_code_label *label)
   return (!LABEL_PRESERVE_P (label)
          /* User declared labels must be preserved.  */
          && LABEL_NAME (label) == 0
-         && !in_insn_list_p (forced_labels, label));
+         && !vec_safe_contains<rtx_insn *> (forced_labels,
+                                            const_cast<rtx_code_label *> (label)));
 }
 
 /* Delete INSN by patching it out.  */
 
 void
-delete_insn (rtx uncast_insn)
+delete_insn (rtx_insn *insn)
 {
-  rtx_insn *insn = as_a <rtx_insn *> (uncast_insn);
   rtx note;
   bool really_delete = true;
 
@@ -232,20 +222,32 @@ delete_insn (rtx uncast_insn)
     }
 }
 
-/* Like delete_insn but also purge dead edges from BB.  */
+/* Like delete_insn but also purge dead edges from BB.
+   Return true if any edges are eliminated.  */
 
-void
+bool
 delete_insn_and_edges (rtx_insn *insn)
 {
   bool purge = false;
 
-  if (INSN_P (insn)
-      && BLOCK_FOR_INSN (insn)
-      && BB_END (BLOCK_FOR_INSN (insn)) == insn)
-    purge = true;
+  if (INSN_P (insn) && BLOCK_FOR_INSN (insn))
+    {
+      basic_block bb = BLOCK_FOR_INSN (insn);
+      if (BB_END (bb) == insn)
+       purge = true;
+      else if (DEBUG_INSN_P (BB_END (bb)))
+       for (rtx_insn *dinsn = NEXT_INSN (insn);
+            DEBUG_INSN_P (dinsn); dinsn = NEXT_INSN (dinsn))
+         if (BB_END (bb) == dinsn)
+           {
+             purge = true;
+             break;
+           }
+    }
   delete_insn (insn);
   if (purge)
-    purge_dead_edges (BLOCK_FOR_INSN (insn));
+    return purge_dead_edges (BLOCK_FOR_INSN (insn));
+  return false;
 }
 
 /* Unlink a chain of insns between START and FINISH, leaving notes
@@ -253,17 +255,15 @@ delete_insn_and_edges (rtx_insn *insn)
    insns that cannot be removed to NULL.  */
 
 void
-delete_insn_chain (rtx start, rtx finish, bool clear_bb)
+delete_insn_chain (rtx start, rtx_insn *finish, bool clear_bb)
 {
-  rtx_insn *prev, *current;
-
   /* Unchain the insns one by one.  It would be quicker to delete all of these
      with a single unchaining, rather than one at a time, but we need to keep
      the NOTE's.  */
-  current = safe_as_a <rtx_insn *> (finish);
+  rtx_insn *current = finish;
   while (1)
     {
-      prev = PREV_INSN (current);
+      rtx_insn *prev = PREV_INSN (current);
       if (NOTE_P (current) && !can_delete_note_p (as_a <rtx_note *> (current)))
        ;
       else
@@ -489,15 +489,13 @@ public:
 unsigned int
 pass_free_cfg::execute (function *)
 {
-#ifdef DELAY_SLOTS
   /* The resource.c machinery uses DF but the CFG isn't guaranteed to be
      valid at that point so it would be too late to call df_analyze.  */
-  if (optimize > 0 && flag_delayed_branch)
+  if (DELAY_SLOTS && optimize > 0 && flag_delayed_branch)
     {
       df_note_add_problem ();
       df_analyze ();
     }
-#endif
 
   if (crtl->has_bb_partition)
     insert_section_boundary_note ();
@@ -561,7 +559,7 @@ update_bb_for_insn (basic_block bb)
 }
 
 \f
-/* Like active_insn_p, except keep the return value clobber around
+/* Like active_insn_p, except keep the return value use or clobber around
    even after reload.  */
 
 static bool
@@ -574,8 +572,12 @@ flow_active_insn_p (const rtx_insn *insn)
      programs that fail to return a value.  Its effect is to
      keep the return value from being live across the entire
      function.  If we allow it to be skipped, we introduce the
-     possibility for register lifetime confusion.  */
-  if (GET_CODE (PATTERN (insn)) == CLOBBER
+     possibility for register lifetime confusion.
+     Similarly, keep a USE of the function return value, otherwise
+     the USE is dropped and we could fail to thread jump if USE
+     appears on some paths and not on others, see PR90257.  */
+  if ((GET_CODE (PATTERN (insn)) == CLOBBER
+       || GET_CODE (PATTERN (insn)) == USE)
       && REG_P (XEXP (PATTERN (insn), 0))
       && REG_FUNCTION_VALUE_P (XEXP (PATTERN (insn), 0)))
     return true;
@@ -591,8 +593,10 @@ contains_no_active_insn_p (const_basic_block bb)
 {
   rtx_insn *insn;
 
-  if (bb == EXIT_BLOCK_PTR_FOR_FN (cfun) || bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)
-      || !single_succ_p (bb))
+  if (bb == EXIT_BLOCK_PTR_FOR_FN (cfun)
+      || bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)
+      || !single_succ_p (bb)
+      || (single_succ_edge (bb)->flags & EDGE_FAKE) != 0)
     return false;
 
   for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = NEXT_INSN (insn))
@@ -829,10 +833,14 @@ emit_nop_for_unique_locus_between (basic_block a, basic_block b)
 static void
 rtl_merge_blocks (basic_block a, basic_block b)
 {
+  /* If B is a forwarder block whose outgoing edge has no location, we'll
+     propagate the locus of the edge between A and B onto it.  */
+  const bool forward_edge_locus
+    = (b->flags & BB_FORWARDER_BLOCK) != 0
+      && LOCATION_LOCUS (EDGE_SUCC (b, 0)->goto_locus) == UNKNOWN_LOCATION;
   rtx_insn *b_head = BB_HEAD (b), *b_end = BB_END (b), *a_end = BB_END (a);
   rtx_insn *del_first = NULL, *del_last = NULL;
   rtx_insn *b_debug_start = b_end, *b_debug_end = b_end;
-  bool forwarder_p = (b->flags & BB_FORWARDER_BLOCK) != 0;
   int b_empty = 0;
 
   if (dump_file)
@@ -903,9 +911,11 @@ rtl_merge_blocks (basic_block a, basic_block b)
   BB_HEAD (b) = b_empty ? NULL : b_head;
   delete_insn_chain (del_first, del_last, true);
 
-  /* When not optimizing and the edge is the only place in RTL which holds
-     some unique locus, emit a nop with that locus in between.  */
-  if (!optimize)
+  /* If not optimizing, preserve the locus of the single edge between
+     blocks A and B if necessary by emitting a nop.  */
+  if (!optimize
+      && !forward_edge_locus
+      && !DECL_IGNORED_P (current_function_decl))
     {
       emit_nop_for_unique_locus_between (a, b);
       a_end = BB_END (a);
@@ -934,9 +944,7 @@ rtl_merge_blocks (basic_block a, basic_block b)
 
   df_bb_delete (b->index);
 
-  /* If B was a forwarder block, propagate the locus on the edge.  */
-  if (forwarder_p
-      && LOCATION_LOCUS (EDGE_SUCC (b, 0)->goto_locus) == UNKNOWN_LOCATION)
+  if (forward_edge_locus)
     EDGE_SUCC (b, 0)->goto_locus = EDGE_SUCC (a, 0)->goto_locus;
 
   if (dump_file)
@@ -1000,6 +1008,31 @@ block_label (basic_block block)
   return as_a <rtx_code_label *> (BB_HEAD (block));
 }
 
+/* Remove all barriers from BB_FOOTER of a BB.  */
+
+static void
+remove_barriers_from_footer (basic_block bb)
+{
+  rtx_insn *insn = BB_FOOTER (bb);
+
+  /* Remove barriers but keep jumptables.  */
+  while (insn)
+    {
+      if (BARRIER_P (insn))
+       {
+         if (PREV_INSN (insn))
+           SET_NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
+         else
+           BB_FOOTER (bb) = NEXT_INSN (insn);
+         if (NEXT_INSN (insn))
+           SET_PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
+       }
+      if (LABEL_P (insn))
+       return;
+      insn = NEXT_INSN (insn);
+    }
+}
+
 /* Attempt to perform edge redirection by replacing possibly complex jump
    instruction by unconditional jump or removing jump completely.  This can
    apply only if all edges now point to the same block.  The parameters and
@@ -1063,26 +1096,8 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
       /* Selectively unlink whole insn chain.  */
       if (in_cfglayout)
        {
-         rtx_insn *insn = BB_FOOTER (src);
-
          delete_insn_chain (kill_from, BB_END (src), false);
-
-         /* Remove barriers but keep jumptables.  */
-         while (insn)
-           {
-             if (BARRIER_P (insn))
-               {
-                 if (PREV_INSN (insn))
-                   SET_NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
-                 else
-                   BB_FOOTER (src) = NEXT_INSN (insn);
-                 if (NEXT_INSN (insn))
-                   SET_PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
-               }
-             if (LABEL_P (insn))
-               break;
-             insn = NEXT_INSN (insn);
-           }
+         remove_barriers_from_footer (src);
        }
       else
        delete_insn_chain (kill_from, PREV_INSN (BB_HEAD (target)),
@@ -1114,10 +1129,10 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
     {
       rtx_code_label *target_label = block_label (target);
       rtx_insn *barrier;
-      rtx label;
+      rtx_insn *label;
       rtx_jump_table_data *table;
 
-      emit_jump_insn_after_noloc (gen_jump (target_label), insn);
+      emit_jump_insn_after_noloc (targetm.gen_jump (target_label), insn);
       JUMP_LABEL (BB_END (src)) = target_label;
       LABEL_NUSES (target_label)++;
       if (dump_file)
@@ -1133,7 +1148,7 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
       if (tablejump_p (insn, &label, &table))
        delete_insn_chain (label, table, false);
 
-      barrier = next_nonnote_insn (BB_END (src));
+      barrier = next_nonnote_nondebug_insn (BB_END (src));
       if (!barrier || !BARRIER_P (barrier))
        emit_barrier_after (BB_END (src));
       else
@@ -1171,8 +1186,7 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
   else
     e->flags = 0;
 
-  e->probability = REG_BR_PROB_BASE;
-  e->count = src->count;
+  e->probability = profile_probability::always ();
 
   if (e->dest != target)
     redirect_edge_succ (e, target);
@@ -1210,11 +1224,8 @@ patch_jump_insn (rtx_insn *insn, rtx_insn *old_label, basic_block new_bb)
          }
 
       /* Handle casesi dispatch insns.  */
-      if ((tmp = single_set (insn)) != NULL
-         && SET_DEST (tmp) == pc_rtx
-         && GET_CODE (SET_SRC (tmp)) == IF_THEN_ELSE
-         && GET_CODE (XEXP (SET_SRC (tmp), 2)) == LABEL_REF
-         && LABEL_REF_LABEL (XEXP (SET_SRC (tmp), 2)) == old_label)
+      if ((tmp = tablejump_casesi_pattern (insn)) != NULL_RTX
+         && label_ref_label (XEXP (SET_SRC (tmp), 2)) == old_label)
        {
          XEXP (SET_SRC (tmp), 2) = gen_rtx_LABEL_REF (Pmode,
                                                       new_label);
@@ -1281,11 +1292,13 @@ patch_jump_insn (rtx_insn *insn, rtx_insn *old_label, basic_block new_bb)
 
          /* If the substitution doesn't succeed, die.  This can happen
             if the back end emitted unrecognizable instructions or if
-            target is exit block on some arches.  */
+            target is exit block on some arches.  Or for crossing
+            jumps.  */
          if (!redirect_jump (as_a <rtx_jump_insn *> (insn),
                              block_label (new_bb), 0))
            {
-             gcc_assert (new_bb == EXIT_BLOCK_PTR_FOR_FN (cfun));
+             gcc_assert (new_bb == EXIT_BLOCK_PTR_FOR_FN (cfun)
+                         || CROSSING_JUMP_P (insn));
              return false;
            }
        }
@@ -1350,8 +1363,7 @@ fixup_partition_crossing (edge e)
   if (BB_PARTITION (e->src) != BB_PARTITION (e->dest))
     {
       e->flags |= EDGE_CROSSING;
-      if (JUMP_P (BB_END (e->src))
-         && !CROSSING_JUMP_P (BB_END (e->src)))
+      if (JUMP_P (BB_END (e->src)))
        CROSSING_JUMP_P (BB_END (e->src)) = 1;
     }
   else if (BB_PARTITION (e->src) == BB_PARTITION (e->dest))
@@ -1520,15 +1532,8 @@ force_nonfallthru_and_redirect (edge e, basic_block target, rtx jump_label)
        {
          int prob = XINT (note, 0);
 
-         b->probability = prob;
-          /* Update this to use GCOV_COMPUTE_SCALE.  */
-         b->count = e->count * prob / REG_BR_PROB_BASE;
+         b->probability = profile_probability::from_reg_br_prob_note (prob);
          e->probability -= e->probability;
-         e->count -= b->count;
-         if (e->probability < 0)
-           e->probability = 0;
-         if (e->count < 0)
-           e->count = 0;
        }
     }
 
@@ -1557,6 +1562,10 @@ force_nonfallthru_and_redirect (edge e, basic_block target, rtx jump_label)
 
          basic_block bb = create_basic_block (BB_HEAD (e->dest), NULL,
                                               ENTRY_BLOCK_PTR_FOR_FN (cfun));
+         bb->count = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count;
+
+         /* Make sure new block ends up in correct hot/cold section.  */
+         BB_COPY_PARTITION (bb, e->dest);
 
          /* Change the existing edge's source to be the new block, and add
             a new edge from the entry block to the new block.  */
@@ -1636,8 +1645,8 @@ force_nonfallthru_and_redirect (edge e, basic_block target, rtx jump_label)
   if (EDGE_COUNT (e->src->succs) >= 2 || abnormal_edge_flags || asm_goto_edge)
     {
       rtx_insn *new_head;
-      gcov_type count = e->count;
-      int probability = e->probability;
+      profile_count count = e->count ();
+      profile_probability probability = e->probability;
       /* Create the new structures.  */
 
       /* If the old block ended with a tablejump, skip its table
@@ -1652,7 +1661,6 @@ force_nonfallthru_and_redirect (edge e, basic_block target, rtx jump_label)
 
       jump_block = create_basic_block (new_head, NULL, e->src);
       jump_block->count = count;
-      jump_block->frequency = EDGE_FREQUENCY (e);
 
       /* Make sure new block ends up in correct hot/cold section.  */
 
@@ -1661,11 +1669,10 @@ force_nonfallthru_and_redirect (edge e, basic_block target, rtx jump_label)
       /* Wire edge in.  */
       new_edge = make_edge (e->src, jump_block, EDGE_FALLTHRU);
       new_edge->probability = probability;
-      new_edge->count = count;
 
       /* Redirect old edge.  */
       redirect_edge_pred (e, jump_block);
-      e->probability = REG_BR_PROB_BASE;
+      e->probability = profile_probability::always ();
 
       /* If e->src was previously region crossing, it no longer is
          and the reg crossing note should be removed.  */
@@ -1675,14 +1682,11 @@ force_nonfallthru_and_redirect (edge e, basic_block target, rtx jump_label)
         add also edge from asm goto bb to target.  */
       if (asm_goto_edge)
        {
-         new_edge->probability /= 2;
-         new_edge->count /= 2;
-         jump_block->count /= 2;
-         jump_block->frequency /= 2;
-         new_edge = make_edge (new_edge->src, target,
-                               e->flags & ~EDGE_FALLTHRU);
-         new_edge->probability = probability - probability / 2;
-         new_edge->count = count - count / 2;
+         new_edge->probability = new_edge->probability.apply_scale (1, 2);
+         jump_block->count = jump_block->count.apply_scale (1, 2);
+         edge new_edge2 = make_edge (new_edge->src, target,
+                                     e->flags & ~EDGE_FALLTHRU);
+         new_edge2->probability = probability - new_edge->probability;
        }
 
       new_bb = jump_block;
@@ -1708,7 +1712,8 @@ force_nonfallthru_and_redirect (edge e, basic_block target, rtx jump_label)
   else
     {
       rtx_code_label *label = block_label (target);
-      emit_jump_insn_after_setloc (gen_jump (label), BB_END (jump_block), loc);
+      emit_jump_insn_after_setloc (targetm.gen_jump (label),
+                                  BB_END (jump_block), loc);
       JUMP_LABEL (BB_END (jump_block)) = label;
       LABEL_NUSES (label)++;
     }
@@ -1773,7 +1778,7 @@ rtl_tidy_fallthru_edge (edge e)
      the head of block C and assert that we really do fall through.  */
 
   for (q = NEXT_INSN (BB_END (b)); q != BB_HEAD (c); q = NEXT_INSN (q))
-    if (INSN_P (q))
+    if (NONDEBUG_INSN_P (q))
       return;
 
   /* Remove what will soon cease being the jump insn from the source block.
@@ -1785,7 +1790,7 @@ rtl_tidy_fallthru_edge (edge e)
       && (any_uncondjump_p (q)
          || single_succ_p (b)))
     {
-      rtx label;
+      rtx_insn *label;
       rtx_jump_table_data *table;
 
       if (tablejump_p (q, &label, &table))
@@ -1798,8 +1803,7 @@ rtl_tidy_fallthru_edge (edge e)
          PUT_CODE (label, NOTE);
          NOTE_KIND (label) = NOTE_INSN_DELETED_LABEL;
          NOTE_DELETED_LABEL_NAME (label) = name;
-         rtx_insn *lab = safe_as_a <rtx_insn *> (label);
-         reorder_insns (lab, lab, PREV_INSN (q));
+         reorder_insns (label, label, PREV_INSN (q));
          delete_insn (table);
        }
 
@@ -1810,6 +1814,10 @@ rtl_tidy_fallthru_edge (edge e)
 
       q = PREV_INSN (q);
     }
+  /* Unconditional jumps with side-effects (i.e. which we can't just delete
+     together with the barrier) should never have a fallthru edge.  */
+  else if (JUMP_P (q) && any_uncondjump_p (q))
+    return;
 
   /* Selectively unlink the sequence.  */
   if (q != PREV_INSN (BB_HEAD (c)))
@@ -1947,7 +1955,8 @@ rtl_split_edge (edge edge_in)
          if (last
              && JUMP_P (last)
              && edge_in->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)
-             && extract_asm_operands (PATTERN (last)) != NULL_RTX
+             && (extract_asm_operands (PATTERN (last))
+                 || JUMP_LABEL (last) == before)
              && patch_jump_insn (last, before, bb))
            df_set_bb_dirty (edge_in->src);
        }
@@ -2103,9 +2112,8 @@ commit_edge_insertions (void)
      which will be done by fixup_partitions.  */
   fixup_partitions ();
 
-#ifdef ENABLE_CHECKING
-  verify_flow_info ();
-#endif
+  if (!currently_expanding_to_rtl)
+    checking_verify_flow_info ();
 
   FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun),
                  EXIT_BLOCK_PTR_FOR_FN (cfun), next_bb)
@@ -2115,7 +2123,11 @@ commit_edge_insertions (void)
 
       FOR_EACH_EDGE (e, ei, bb->succs)
        if (e->insns.r)
-         commit_one_edge_insertion (e);
+         {
+           if (currently_expanding_to_rtl)
+             rebuild_jump_labels_chain (e->insns.r);
+           commit_one_edge_insertion (e);
+         }
     }
 }
 \f
@@ -2125,10 +2137,8 @@ commit_edge_insertions (void)
    documented in dumpfile.h.  */
 
 static void
-rtl_dump_bb (FILE *outf, basic_block bb, int indent, int flags)
+rtl_dump_bb (FILE *outf, basic_block bb, int indent, dump_flags_t flags)
 {
-  rtx_insn *insn;
-  rtx_insn *last;
   char *s_indent;
 
   s_indent = (char *) alloca ((size_t) indent + 1);
@@ -2142,18 +2152,22 @@ rtl_dump_bb (FILE *outf, basic_block bb, int indent, int flags)
     }
 
   if (bb->index != ENTRY_BLOCK && bb->index != EXIT_BLOCK)
-    for (insn = BB_HEAD (bb), last = NEXT_INSN (BB_END (bb)); insn != last;
-        insn = NEXT_INSN (insn))
-      {
-       if (flags & TDF_DETAILS)
-         df_dump_insn_top (insn, outf);
-       if (! (flags & TDF_SLIM))
-         print_rtl_single (outf, insn);
-       else
-         dump_insn_slim (outf, insn);
-       if (flags & TDF_DETAILS)
-         df_dump_insn_bottom (insn, outf);
-      }
+    {
+      rtx_insn *last = BB_END (bb);
+      if (last)
+       last = NEXT_INSN (last);
+      for (rtx_insn *insn = BB_HEAD (bb); insn != last; insn = NEXT_INSN (insn))
+       {
+         if (flags & TDF_DETAILS)
+           df_dump_insn_top (insn, outf);
+         if (! (flags & TDF_SLIM))
+           print_rtl_single (outf, insn);
+         else
+           dump_insn_slim (outf, insn);
+         if (flags & TDF_DETAILS)
+           df_dump_insn_bottom (insn, outf);
+       }
+    }
 
   if (df && (flags & TDF_DETAILS))
     {
@@ -2168,7 +2182,7 @@ rtl_dump_bb (FILE *outf, basic_block bb, int indent, int flags)
    in dumpfile.h.  */
 
 void
-print_rtl_with_bb (FILE *outf, const rtx_insn *rtx_first, int flags)
+print_rtl_with_bb (FILE *outf, const rtx_insn *rtx_first, dump_flags_t flags)
 {
   const rtx_insn *tmp_rtx;
   if (rtx_first == 0)
@@ -2191,7 +2205,7 @@ print_rtl_with_bb (FILE *outf, const rtx_insn *rtx_first, int flags)
       if (df)
        df_dump_start (outf);
 
-      if (flags & TDF_BLOCKS)
+      if (cfun->curr_properties & PROP_cfg)
        {
          FOR_EACH_BB_REVERSE_FN (bb, cfun)
            {
@@ -2199,28 +2213,31 @@ print_rtl_with_bb (FILE *outf, const rtx_insn *rtx_first, int flags)
 
              start[INSN_UID (BB_HEAD (bb))] = bb;
              end[INSN_UID (BB_END (bb))] = bb;
-             for (x = BB_HEAD (bb); x != NULL_RTX; x = NEXT_INSN (x))
+             if (flags & TDF_BLOCKS)
                {
-                 enum bb_state state = IN_MULTIPLE_BB;
+                 for (x = BB_HEAD (bb); x != NULL_RTX; x = NEXT_INSN (x))
+                   {
+                     enum bb_state state = IN_MULTIPLE_BB;
 
-                 if (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
-                   state = IN_ONE_BB;
-                 in_bb_p[INSN_UID (x)] = state;
+                     if (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
+                       state = IN_ONE_BB;
+                     in_bb_p[INSN_UID (x)] = state;
 
-                 if (x == BB_END (bb))
-                   break;
+                     if (x == BB_END (bb))
+                       break;
+                   }
                }
            }
        }
 
-      for (tmp_rtx = rtx_first; NULL != tmp_rtx; tmp_rtx = NEXT_INSN (tmp_rtx))
+      for (tmp_rtx = rtx_first; tmp_rtx != NULL; tmp_rtx = NEXT_INSN (tmp_rtx))
        {
          if (flags & TDF_BLOCKS)
            {
              bb = start[INSN_UID (tmp_rtx)];
              if (bb != NULL)
                {
-                 dump_bb_info (outf, bb, 0, dump_flags | TDF_COMMENT, true, false);
+                 dump_bb_info (outf, bb, 0, dump_flags, true, false);
                  if (df && (flags & TDF_DETAILS))
                    df_dump_top (bb, outf);
                }
@@ -2242,16 +2259,36 @@ print_rtl_with_bb (FILE *outf, const rtx_insn *rtx_first, int flags)
          if (flags & TDF_DETAILS)
            df_dump_insn_bottom (tmp_rtx, outf);
 
-         if (flags & TDF_BLOCKS)
+         bb = end[INSN_UID (tmp_rtx)];
+         if (bb != NULL)
            {
-             bb = end[INSN_UID (tmp_rtx)];
-             if (bb != NULL)
+             if (flags & TDF_BLOCKS)
                {
-                 dump_bb_info (outf, bb, 0, dump_flags | TDF_COMMENT, false, true);
+                 dump_bb_info (outf, bb, 0, dump_flags, false, true);
                  if (df && (flags & TDF_DETAILS))
                    df_dump_bottom (bb, outf);
                  putc ('\n', outf);
                }
+             /* Emit a hint if the fallthrough target of current basic block
+                isn't the one placed right next.  */
+             else if (EDGE_COUNT (bb->succs) > 0)
+               {
+                 gcc_assert (BB_END (bb) == tmp_rtx);
+                 const rtx_insn *ninsn = NEXT_INSN (tmp_rtx);
+                 /* Bypass intervening deleted-insn notes and debug insns.  */
+                 while (ninsn
+                        && !NONDEBUG_INSN_P (ninsn)
+                        && !start[INSN_UID (ninsn)])
+                   ninsn = NEXT_INSN (ninsn);
+                 edge e = find_fallthru_edge (bb->succs);
+                 if (e && ninsn)
+                   {
+                     basic_block dest = e->dest;
+                     if (start[INSN_UID (ninsn)] != dest)
+                       fprintf (outf, "%s      ; pc falls through to BB %d\n",
+                                print_rtx_head, dest->index);
+                   }
+               }
            }
        }
 
@@ -2267,12 +2304,27 @@ void
 update_br_prob_note (basic_block bb)
 {
   rtx note;
-  if (!JUMP_P (BB_END (bb)))
-    return;
   note = find_reg_note (BB_END (bb), REG_BR_PROB, NULL_RTX);
-  if (!note || XINT (note, 0) == BRANCH_EDGE (bb)->probability)
+  if (!JUMP_P (BB_END (bb)) || !BRANCH_EDGE (bb)->probability.initialized_p ())
+    {
+      if (note)
+       {
+         rtx *note_link, this_rtx;
+
+         note_link = &REG_NOTES (BB_END (bb));
+         for (this_rtx = *note_link; this_rtx; this_rtx = XEXP (this_rtx, 1))
+           if (this_rtx == note)
+             {
+               *note_link = XEXP (this_rtx, 1);
+               break;
+             }
+       }
+      return;
+    }
+  if (!note
+      || XINT (note, 0) == BRANCH_EDGE (bb)->probability.to_reg_br_prob_note ())
     return;
-  XINT (note, 0) = BRANCH_EDGE (bb)->probability;
+  XINT (note, 0) = BRANCH_EDGE (bb)->probability.to_reg_br_prob_note ();
 }
 
 /* Get the last insn associated with block BB (that includes barriers and
@@ -2289,16 +2341,39 @@ get_last_bb_insn (basic_block bb)
     end = table;
 
   /* Include any barriers that may follow the basic block.  */
-  tmp = next_nonnote_insn_bb (end);
+  tmp = next_nonnote_nondebug_insn_bb (end);
   while (tmp && BARRIER_P (tmp))
     {
       end = tmp;
-      tmp = next_nonnote_insn_bb (end);
+      tmp = next_nonnote_nondebug_insn_bb (end);
     }
 
   return end;
 }
 
+/* Add all BBs reachable from entry via hot paths into the SET.  */
+
+void
+find_bbs_reachable_by_hot_paths (hash_set<basic_block> *set)
+{
+  auto_vec<basic_block, 64> worklist;
+
+  set->add (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+  worklist.safe_push (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+
+  while (worklist.length () > 0)
+    {
+      basic_block bb = worklist.pop ();
+      edge_iterator ei;
+      edge e;
+
+      FOR_EACH_EDGE (e, ei, bb->succs)
+       if (BB_PARTITION (e->dest) != BB_COLD_PARTITION
+           && !set->add (e->dest))
+         worklist.safe_push (e->dest);
+    }
+}
+
 /* Sanity check partition hotness to ensure that basic blocks in
    the cold partition don't dominate basic blocks in the hot partition.
    If FLAG_ONLY is true, report violations as errors. Otherwise
@@ -2310,51 +2385,25 @@ static vec<basic_block>
 find_partition_fixes (bool flag_only)
 {
   basic_block bb;
-  vec<basic_block> bbs_in_cold_partition = vNULL;
   vec<basic_block> bbs_to_fix = vNULL;
+  hash_set<basic_block> set;
 
   /* Callers check this.  */
   gcc_checking_assert (crtl->has_bb_partition);
 
-  FOR_EACH_BB_FN (bb, cfun)
-    if ((BB_PARTITION (bb) == BB_COLD_PARTITION))
-      bbs_in_cold_partition.safe_push (bb);
-
-  if (bbs_in_cold_partition.is_empty ())
-    return vNULL;
-
-  bool dom_calculated_here = !dom_info_available_p (CDI_DOMINATORS);
-
-  if (dom_calculated_here)
-    calculate_dominance_info (CDI_DOMINATORS);
+  find_bbs_reachable_by_hot_paths (&set);
 
-  while (! bbs_in_cold_partition.is_empty  ())
-    {
-      bb = bbs_in_cold_partition.pop ();
-      /* Any blocks dominated by a block in the cold section
-         must also be cold.  */
-      basic_block son;
-      for (son = first_dom_son (CDI_DOMINATORS, bb);
-           son;
-           son = next_dom_son (CDI_DOMINATORS, son))
-        {
-          /* If son is not yet cold, then mark it cold here and
-             enqueue it for further processing.  */
-          if ((BB_PARTITION (son) != BB_COLD_PARTITION))
-            {
-              if (flag_only)
-                error ("non-cold basic block %d dominated "
-                       "by a block in the cold partition (%d)", son->index, bb->index);
-              else
-                BB_SET_PARTITION (son, BB_COLD_PARTITION);
-              bbs_to_fix.safe_push (son);
-              bbs_in_cold_partition.safe_push (son);
-            }
-        }
-    }
-
-  if (dom_calculated_here)
-    free_dominance_info (CDI_DOMINATORS);
+  FOR_EACH_BB_FN (bb, cfun)
+    if (!set.contains (bb)
+       && BB_PARTITION (bb) != BB_COLD_PARTITION)
+      {
+       if (flag_only)
+         error ("non-cold basic block %d reachable only "
+                "by paths crossing the cold partition", bb->index);
+       else
+         BB_SET_PARTITION (bb, BB_COLD_PARTITION);
+       bbs_to_fix.safe_push (bb);
+      }
 
   return bbs_to_fix;
 }
@@ -2463,11 +2512,22 @@ rtl_verify_edges (void)
          && EDGE_COUNT (bb->succs) >= 2
          && any_condjump_p (BB_END (bb)))
        {
-         if (XINT (note, 0) != BRANCH_EDGE (bb)->probability
-             && profile_status_for_fn (cfun) != PROFILE_ABSENT)
+         if (!BRANCH_EDGE (bb)->probability.initialized_p ())
+           {
+             if (profile_status_for_fn (cfun) != PROFILE_ABSENT)
+               {
+                 error ("verify_flow_info: "
+                        "REG_BR_PROB is set but cfg probability is not");
+                 err = 1;
+               }
+           }
+         else if (XINT (note, 0)
+                  != BRANCH_EDGE (bb)->probability.to_reg_br_prob_note ()
+                  && profile_status_for_fn (cfun) != PROFILE_ABSENT)
            {
              error ("verify_flow_info: REG_BR_PROB does not match cfg %i %i",
-                    XINT (note, 0), BRANCH_EDGE (bb)->probability);
+                    XINT (note, 0),
+                    BRANCH_EDGE (bb)->probability.to_reg_br_prob_note ());
              err = 1;
            }
        }
@@ -2536,15 +2596,15 @@ rtl_verify_edges (void)
            n_abnormal++;
        }
 
-        if (!has_crossing_edge
-           && JUMP_P (BB_END (bb))
-           && CROSSING_JUMP_P (BB_END (bb)))
-          {
-            print_rtl_with_bb (stderr, get_insns (), TDF_RTL | TDF_BLOCKS | TDF_DETAILS);
-            error ("Region crossing jump across same section in bb %i",
-                   bb->index);
-            err = 1;
-          }
+      if (!has_crossing_edge
+         && JUMP_P (BB_END (bb))
+         && CROSSING_JUMP_P (BB_END (bb)))
+       {
+         print_rtl_with_bb (stderr, get_insns (), TDF_BLOCKS | TDF_DETAILS);
+         error ("Region crossing jump across same section in bb %i",
+                bb->index);
+         err = 1;
+       }
 
       if (n_eh && !find_reg_note (BB_END (bb), REG_EH_REGION, NULL_RTX))
        {
@@ -2602,11 +2662,25 @@ rtl_verify_edges (void)
          error ("abnormal edges for no purpose in bb %i", bb->index);
          err = 1;
        }
+
+      int has_eh = -1;
+      FOR_EACH_EDGE (e, ei, bb->preds)
+       {
+         if (has_eh == -1)
+           has_eh = (e->flags & EDGE_EH);
+         if ((e->flags & EDGE_EH) == has_eh)
+           continue;
+         error ("EH incoming edge mixed with non-EH incoming edges "
+                "in bb %i", bb->index);
+         err = 1;
+         break;
+       }
     }
 
   /* If there are partitions, do a sanity check on them: A basic block in
      a cold partition cannot dominate a basic block in a hot partition.  */
-  if (crtl->has_bb_partition && !err)
+  if (crtl->has_bb_partition && !err
+      && current_ir_type () == IR_RTL_CFGLAYOUT)
     {
       vec<basic_block> bbs_to_fix = find_partition_fixes (true);
       err = !bbs_to_fix.is_empty ();
@@ -2899,7 +2973,7 @@ rtl_verify_fallthru (void)
          else
            for (insn = NEXT_INSN (BB_END (e->src)); insn != BB_HEAD (e->dest);
                 insn = NEXT_INSN (insn))
-             if (BARRIER_P (insn) || INSN_P (insn))
+             if (BARRIER_P (insn) || NONDEBUG_INSN_P (insn))
                {
                  error ("verify_flow_info: Incorrect fallthru %i->%i",
                         e->src->index, e->dest->index);
@@ -2921,13 +2995,12 @@ rtl_verify_bb_layout (void)
 {
   basic_block bb;
   int err = 0;
-  rtx_insn *x;
+  rtx_insn *x, *y;
   int num_bb_notes;
   rtx_insn * const rtx_first = get_insns ();
   basic_block last_bb_seen = ENTRY_BLOCK_PTR_FOR_FN (cfun), curr_bb = NULL;
 
   num_bb_notes = 0;
-  last_bb_seen = ENTRY_BLOCK_PTR_FOR_FN (cfun);
 
   for (x = rtx_first; x; x = NEXT_INSN (x))
     {
@@ -2966,7 +3039,8 @@ rtl_verify_bb_layout (void)
 
       if (JUMP_P (x)
          && returnjump_p (x) && ! condjump_p (x)
-         && ! (next_nonnote_insn (x) && BARRIER_P (next_nonnote_insn (x))))
+         && ! ((y = next_nonnote_nondebug_insn (x))
+               && BARRIER_P (y)))
            fatal_insn ("return not followed by barrier", x);
 
       if (curr_bb && x == BB_END (curr_bb))
@@ -3026,7 +3100,7 @@ purge_dead_edges (basic_block bb)
   bool found;
   edge_iterator ei;
 
-  if (DEBUG_INSN_P (insn) && insn != BB_HEAD (bb))
+  if ((DEBUG_INSN_P (insn) || NOTE_P (insn)) && insn != BB_HEAD (bb))
     do
       insn = PREV_INSN (insn);
     while ((DEBUG_INSN_P (insn) || NOTE_P (insn)) && insn != BB_HEAD (bb));
@@ -3159,8 +3233,7 @@ purge_dead_edges (basic_block bb)
       /* Redistribute probabilities.  */
       if (single_succ_p (bb))
        {
-         single_succ_edge (bb)->probability = REG_BR_PROB_BASE;
-         single_succ_edge (bb)->count = bb->count;
+         single_succ_edge (bb)->probability = profile_probability::always ();
        }
       else
        {
@@ -3170,11 +3243,9 @@ purge_dead_edges (basic_block bb)
 
          b = BRANCH_EDGE (bb);
          f = FALLTHRU_EDGE (bb);
-         b->probability = XINT (note, 0);
-         f->probability = REG_BR_PROB_BASE - b->probability;
-          /* Update these to use GCOV_COMPUTE_SCALE.  */
-         b->count = bb->count * b->probability / REG_BR_PROB_BASE;
-         f->count = bb->count * f->probability / REG_BR_PROB_BASE;
+         b->probability = profile_probability::from_reg_br_prob_note
+                                        (XINT (note, 0));
+         f->probability = b->probability.invert ();
        }
 
       return purged;
@@ -3225,8 +3296,7 @@ purge_dead_edges (basic_block bb)
 
   gcc_assert (single_succ_p (bb));
 
-  single_succ_edge (bb)->probability = REG_BR_PROB_BASE;
-  single_succ_edge (bb)->count = bb->count;
+  single_succ_edge (bb)->probability = profile_probability::always ();
 
   if (dump_file)
     fprintf (dump_file, "Purged non-fallthru edges from bb %i\n",
@@ -3313,8 +3383,15 @@ fixup_abnormal_edges (void)
                         If it's placed after a trapping call (i.e. that
                         call is the last insn anyway), we have no fallthru
                         edge.  Simply delete this use and don't try to insert
-                        on the non-existent edge.  */
-                     if (GET_CODE (PATTERN (insn)) != USE)
+                        on the non-existent edge.
+                        Similarly, sometimes a call that can throw is
+                        followed in the source with __builtin_unreachable (),
+                        meaning that there is UB if the call returns rather
+                        than throws.  If there weren't any instructions
+                        following such calls before, supposedly even the ones
+                        we've deleted aren't significant and can be
+                        removed.  */
+                     if (e)
                        {
                          /* We're not deleting it, we're moving it.  */
                          insn->set_undeleted ();
@@ -3631,14 +3708,13 @@ relink_block_chain (bool stay_in_cfglayout_mode)
        {
          fprintf (dump_file, " %i ", index);
          if (get_bb_original (bb))
-           fprintf (dump_file, "duplicate of %i ",
+           fprintf (dump_file, "duplicate of %i\n",
                     get_bb_original (bb)->index);
          else if (forwarder_block_p (bb)
                   && !LABEL_P (BB_HEAD (bb)))
-           fprintf (dump_file, "compensation ");
+           fprintf (dump_file, "compensation\n");
          else
-           fprintf (dump_file, "bb %i ", bb->index);
-         fprintf (dump_file, " [%i]\n", bb->frequency);
+           fprintf (dump_file, "bb %i\n", bb->index);
        }
     }
 
@@ -3664,7 +3740,8 @@ relink_block_chain (bool stay_in_cfglayout_mode)
   /* Maybe reset the original copy tables, they are not valid anymore
      when we renumber the basic blocks in compact_blocks.  If we are
      are going out of cfglayout mode, don't re-allocate the tables.  */
-  free_original_copy_tables ();
+  if (original_copy_tables_initialized_p ())
+    free_original_copy_tables ();
   if (stay_in_cfglayout_mode)
     initialize_original_copy_tables ();
 
@@ -3729,9 +3806,8 @@ fixup_reorder_chain (void)
     insn = NEXT_INSN (insn);
 
   set_last_insn (insn);
-#ifdef ENABLE_CHECKING
-  verify_insn_chain ();
-#endif
+  if (flag_checking)
+    verify_insn_chain ();
 
   /* Now add jumps and labels as needed to match the blocks new
      outgoing edges.  */
@@ -3798,7 +3874,8 @@ fixup_reorder_chain (void)
                  rtx note = find_reg_note (bb_end_jump, REG_BR_PROB, 0);
 
                  if (note
-                     && XINT (note, 0) < REG_BR_PROB_BASE / 2
+                     && profile_probability::from_reg_br_prob_note
+                                (XINT (note, 0)) < profile_probability::even ()
                      && invert_jump (bb_end_jump,
                                      (e_fall->dest
                                       == EXIT_BLOCK_PTR_FOR_FN (cfun)
@@ -3835,7 +3912,7 @@ fixup_reorder_chain (void)
                  update_br_prob_note (bb);
                  if (LABEL_NUSES (ret_label) == 0
                      && single_pred_p (e_taken->dest))
-                   delete_insn (ret_label);
+                   delete_insn (as_a<rtx_insn *> (ret_label));
                  continue;
                }
            }
@@ -3901,9 +3978,9 @@ fixup_reorder_chain (void)
        force_nonfallthru (e);
     }
 
-  /* Ensure goto_locus from edges has some instructions with that locus
-     in RTL.  */
-  if (!optimize)
+  /* Ensure goto_locus from edges has some instructions with that locus in RTL
+     when not optimizing.  */
+  if (!optimize && !DECL_IGNORED_P (current_function_decl))
     FOR_EACH_BB_FN (bb, cfun)
       {
         edge e;
@@ -4139,7 +4216,8 @@ duplicate_insn_chain (rtx_insn *from, rtx_insn *to)
        {
        case DEBUG_INSN:
          /* Don't duplicate label debug insns.  */
-         if (TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL)
+         if (DEBUG_BIND_INSN_P (insn)
+             && TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL)
            break;
          /* FALLTHRU */
        case INSN:
@@ -4214,7 +4292,7 @@ duplicate_insn_chain (rtx_insn *from, rtx_insn *to)
 /* Create a duplicate of the basic block BB.  */
 
 static basic_block
-cfg_layout_duplicate_bb (basic_block bb)
+cfg_layout_duplicate_bb (basic_block bb, copy_bb_data *)
 {
   rtx_insn *insn;
   basic_block new_bb;
@@ -4255,7 +4333,7 @@ cfg_layout_duplicate_bb (basic_block bb)
    FLAGS is a set of additional flags to pass to cleanup_cfg().  */
 
 void
-cfg_layout_initialize (unsigned int flags)
+cfg_layout_initialize (int flags)
 {
   rtx_insn_list *x;
   basic_block bb;
@@ -4266,8 +4344,7 @@ cfg_layout_initialize (unsigned int flags)
      layout required moving a block from the hot to the cold
      section. This would create an illegal partitioning unless some
      manual fixup was performed.  */
-  gcc_assert (!(crtl->bb_reorder_complete
-               && flag_reorder_blocks_and_partition));
+  gcc_assert (!crtl->bb_reorder_complete || !crtl->has_bb_partition);
 
   initialize_original_copy_tables ();
 
@@ -4289,11 +4366,10 @@ cfg_layout_initialize (unsigned int flags)
 void
 break_superblocks (void)
 {
-  sbitmap superblocks;
   bool need = false;
   basic_block bb;
 
-  superblocks = sbitmap_alloc (last_basic_block_for_fn (cfun));
+  auto_sbitmap superblocks (last_basic_block_for_fn (cfun));
   bitmap_clear (superblocks);
 
   FOR_EACH_BB_FN (bb, cfun)
@@ -4309,8 +4385,6 @@ break_superblocks (void)
       rebuild_jump_labels (get_insns ());
       find_many_sub_basic_blocks (superblocks);
     }
-
-  free (superblocks);
 }
 
 /* Finalize the changes: reorder insn list according to the sequence specified
@@ -4319,22 +4393,19 @@ break_superblocks (void)
 void
 cfg_layout_finalize (void)
 {
-#ifdef ENABLE_CHECKING
-  verify_flow_info ();
-#endif
+  free_dominance_info (CDI_DOMINATORS);
   force_one_exit_fallthru ();
   rtl_register_cfg_hooks ();
-  if (reload_completed && !HAVE_epilogue)
+  if (reload_completed && !targetm.have_epilogue ())
     fixup_fallthru_exit_predecessor ();
   fixup_reorder_chain ();
 
   rebuild_jump_labels (get_insns ());
   delete_dead_jumptables ();
 
-#ifdef ENABLE_CHECKING
-  verify_insn_chain ();
-  verify_flow_info ();
-#endif
+  if (flag_checking)
+    verify_insn_chain ();
+  checking_verify_flow_info ();
 }
 
 
@@ -4365,6 +4436,19 @@ cfg_layout_redirect_edge_and_branch (edge e, basic_block dest)
   if (e->dest == dest)
     return e;
 
+  if (e->flags & EDGE_CROSSING
+      && BB_PARTITION (e->src) == BB_PARTITION (dest)
+      && simplejump_p (BB_END (src)))
+    {
+      if (dump_file)
+       fprintf (dump_file,
+                "Removing crossing jump while redirecting edge form %i to %i\n",
+                e->src->index, dest->index);
+      delete_insn (BB_END (src));
+      remove_barriers_from_footer (src);
+      e->flags |= EDGE_FALLTHRU;
+    }
+
   if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun)
       && (ret = try_redirect_by_replacing_jump (e, dest, true)))
     {
@@ -4428,8 +4512,12 @@ cfg_layout_redirect_edge_and_branch (edge e, basic_block dest)
   else
     ret = redirect_branch_edge (e, dest);
 
+  if (!ret)
+    return NULL;
+
+  fixup_partition_crossing (ret);
   /* We don't want simplejumps in the insn stream during cfglayout.  */
-  gcc_assert (!simplejump_p (BB_END (src)));
+  gcc_assert (!simplejump_p (BB_END (src)) || CROSSING_JUMP_P (BB_END (src)));
 
   df_set_bb_dirty (src);
   return ret;
@@ -4583,7 +4671,11 @@ cfg_layout_can_merge_blocks_p (basic_block a, basic_block b)
 static void
 cfg_layout_merge_blocks (basic_block a, basic_block b)
 {
-  bool forwarder_p = (b->flags & BB_FORWARDER_BLOCK) != 0;
+  /* If B is a forwarder block whose outgoing edge has no location, we'll
+     propagate the locus of the edge between A and B onto it.  */
+  const bool forward_edge_locus
+    = (b->flags & BB_FORWARDER_BLOCK) != 0
+      && LOCATION_LOCUS (EDGE_SUCC (b, 0)->goto_locus) == UNKNOWN_LOCATION;
   rtx_insn *insn;
 
   gcc_checking_assert (cfg_layout_can_merge_blocks_p (a, b));
@@ -4604,9 +4696,11 @@ cfg_layout_merge_blocks (basic_block a, basic_block b)
     try_redirect_by_replacing_jump (EDGE_SUCC (a, 0), b, true);
   gcc_assert (!JUMP_P (BB_END (a)));
 
-  /* When not optimizing and the edge is the only place in RTL which holds
-     some unique locus, emit a nop with that locus in between.  */
-  if (!optimize)
+  /* If not optimizing, preserve the locus of the single edge between
+     blocks A and B if necessary by emitting a nop.  */
+  if (!optimize
+      && !forward_edge_locus
+      && !DECL_IGNORED_P (current_function_decl))
     emit_nop_for_unique_locus_between (a, b);
 
   /* Move things from b->footer after a->footer.  */
@@ -4673,9 +4767,7 @@ cfg_layout_merge_blocks (basic_block a, basic_block b)
 
   df_bb_delete (b->index);
 
-  /* If B was a forwarder block, propagate the locus on the edge.  */
-  if (forwarder_p
-      && LOCATION_LOCUS (EDGE_SUCC (b, 0)->goto_locus) == UNKNOWN_LOCATION)
+  if (forward_edge_locus)
     EDGE_SUCC (b, 0)->goto_locus = EDGE_SUCC (a, 0)->goto_locus;
 
   if (dump_file)
@@ -4899,13 +4991,11 @@ rtl_flow_call_edges_add (sbitmap blocks)
                 block in CFG already.  Calling make_edge in such case would
                 cause us to mark that edge as fake and remove it later.  */
 
-#ifdef ENABLE_CHECKING
-             if (split_at_insn == BB_END (bb))
+             if (flag_checking && split_at_insn == BB_END (bb))
                {
                  e = find_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun));
                  gcc_assert (e == NULL);
                }
-#endif
 
              /* Note that the following may create a new basic block
                 and renumber the existing basic blocks.  */
@@ -4916,7 +5006,8 @@ rtl_flow_call_edges_add (sbitmap blocks)
                    blocks_split++;
                }
 
-             make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_FAKE);
+             edge ne = make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_FAKE);
+             ne->probability = profile_probability::guessed_never ();
            }
 
          if (insn == BB_HEAD (bb))
@@ -4956,7 +5047,8 @@ rtl_lv_add_condition_to_bb (basic_block first_head ,
   start_sequence ();
   op0 = force_operand (op0, NULL_RTX);
   op1 = force_operand (op1, NULL_RTX);
-  do_compare_rtx_and_jump (op0, op1, comp, 0, mode, NULL_RTX, NULL, label, -1);
+  do_compare_rtx_and_jump (op0, op1, comp, 0, mode, NULL_RTX, NULL, label,
+                          profile_probability::uninitialized ());
   jump = get_last_insn ();
   JUMP_LABEL (jump) = label;
   LABEL_NUSES (label)++;
@@ -5030,32 +5122,29 @@ rtl_can_remove_branch_p (const_edge e)
 }
 
 static basic_block
-rtl_duplicate_bb (basic_block bb)
+rtl_duplicate_bb (basic_block bb, copy_bb_data *id)
 {
-  bb = cfg_layout_duplicate_bb (bb);
+  bb = cfg_layout_duplicate_bb (bb, id);
   bb->aux = NULL;
   return bb;
 }
 
 /* Do book-keeping of basic block BB 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.  */
+   Store the counting in RECORD.  */
 static void
-rtl_account_profile_record (basic_block bb, int after_pass,
-                           struct profile_record *record)
+rtl_account_profile_record (basic_block bb, struct profile_record *record)
 {
   rtx_insn *insn;
   FOR_BB_INSNS (bb, insn)
     if (INSN_P (insn))
       {
-       record->size[after_pass]
-         += insn_rtx_cost (PATTERN (insn), false);
-       if (profile_status_for_fn (cfun) == PROFILE_READ)
-         record->time[after_pass]
-           += insn_rtx_cost (PATTERN (insn), true) * bb->count;
+       record->size += insn_cost (insn, false);
+       if (bb->count.initialized_p ())
+         record->time
+           += insn_cost (insn, true) * bb->count.to_gcov_type ();
        else if (profile_status_for_fn (cfun) == PROFILE_GUESSED)
-         record->time[after_pass]
-           += insn_rtx_cost (PATTERN (insn), true) * bb->frequency;
+         record->time
+           += insn_cost (insn, true) * bb->count.to_frequency (cfun);
       }
 }
 
@@ -5140,3 +5229,7 @@ struct cfg_hooks cfg_layout_rtl_cfg_hooks = {
 };
 
 #include "gt-cfgrtl.h"
+
+#if __GNUC__ >= 10
+#  pragma GCC diagnostic pop
+#endif