re PR debug/66691 (ICE on valid code at -O3 with -g enabled in simplify_subreg, at...
[gcc.git] / gcc / sel-sched.c
index 378e561bf59a3a93e639e4a3d31fc451bde2e23f..be5d1d12e899e87e8958568ca03ae3236ee9db9c 100644 (file)
@@ -1,5 +1,5 @@
 /* Instruction scheduling pass.  Selective scheduler and pipeliner.
-   Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2006-2015 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -26,6 +26,11 @@ along with GCC; see the file COPYING3.  If not see
 #include "hard-reg-set.h"
 #include "regs.h"
 #include "function.h"
+#include "predict.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgbuild.h"
+#include "basic-block.h"
 #include "flags.h"
 #include "insn-config.h"
 #include "insn-attr.h"
@@ -34,16 +39,14 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "target.h"
 #include "output.h"
-#include "timevar.h"
-#include "tree-pass.h"
 #include "sched-int.h"
-#include "ggc.h"
+#include "symtab.h"
 #include "tree.h"
-#include "vec.h"
 #include "langhooks.h"
 #include "rtlhooks-def.h"
-#include "output.h"
 #include "emit-rtl.h"
+#include "ira.h"
+#include "rtl-iter.h"
 
 #ifdef INSN_SCHEDULING
 #include "sel-sched-ir.h"
@@ -284,7 +287,7 @@ struct rtx_search_arg
   /* What we are searching for.  */
   rtx x;
 
-  /* The occurence counter.  */
+  /* The occurrence counter.  */
   int n;
 };
 
@@ -502,31 +505,25 @@ static int max_ws;
 static int num_insns_scheduled;
 
 /* A vector of expressions is used to be able to sort them.  */
-DEF_VEC_P(expr_t);
-DEF_VEC_ALLOC_P(expr_t,heap);
-static VEC(expr_t, heap) *vec_av_set = NULL;
+static vec<expr_t> vec_av_set = vNULL;
 
 /* A vector of vinsns is used to hold temporary lists of vinsns.  */
-DEF_VEC_P(vinsn_t);
-DEF_VEC_ALLOC_P(vinsn_t,heap);
-typedef VEC(vinsn_t, heap) *vinsn_vec_t;
+typedef vec<vinsn_t> vinsn_vec_t;
 
 /* This vector has the exprs which may still present in av_sets, but actually
    can't be moved up due to bookkeeping created during code motion to another
    fence.  See comment near the call to update_and_record_unavailable_insns
    for the detailed explanations.  */
-static vinsn_vec_t vec_bookkeeping_blocked_vinsns = NULL;
+static vinsn_vec_t vec_bookkeeping_blocked_vinsns = vinsn_vec_t ();
 
 /* This vector has vinsns which are scheduled with renaming on the first fence
    and then seen on the second.  For expressions with such vinsns, target
    availability information may be wrong.  */
-static vinsn_vec_t vec_target_unavailable_vinsns = NULL;
+static vinsn_vec_t vec_target_unavailable_vinsns = vinsn_vec_t ();
 
 /* Vector to store temporary nops inserted in move_op to prevent removal
    of empty bbs.  */
-DEF_VEC_P(insn_t);
-DEF_VEC_ALLOC_P(insn_t,heap);
-static VEC(insn_t, heap) *vec_temp_moveop_nops = NULL;
+static vec<insn_t> vec_temp_moveop_nops = vNULL;
 
 /* These bitmaps record original instructions scheduled on the current
    iteration and bookkeeping copies created by them.  */
@@ -580,7 +577,7 @@ advance_one_cycle (fence_t fence)
 {
   unsigned i;
   int cycle;
-  rtx insn;
+  rtx_insn *insn;
 
   advance_state (FENCE_STATE (fence));
   cycle = ++FENCE_CYCLE (fence);
@@ -589,12 +586,12 @@ advance_one_cycle (fence_t fence)
   can_issue_more = issue_rate;
   FENCE_ISSUE_MORE (fence) = can_issue_more;
 
-  for (i = 0; VEC_iterate (rtx, FENCE_EXECUTING_INSNS (fence), i, insn); )
+  for (i = 0; vec_safe_iterate (FENCE_EXECUTING_INSNS (fence), i, &insn); )
     {
       if (INSN_READY_CYCLE (insn) < cycle)
         {
           remove_from_deps (FENCE_DC (fence), insn);
-          VEC_unordered_remove (rtx, FENCE_EXECUTING_INSNS (fence), i);
+          FENCE_EXECUTING_INSNS (fence)->unordered_remove (i);
           continue;
         }
       i++;
@@ -609,7 +606,7 @@ advance_one_cycle (fence_t fence)
 /* Returns true when SUCC in a fallthru bb of INSN, possibly
    skipping empty basic blocks.  */
 static bool
-in_fallthru_bb_p (rtx insn, rtx succ)
+in_fallthru_bb_p (rtx_insn *insn, rtx succ)
 {
   basic_block bb = BLOCK_FOR_INSN (insn);
   edge e;
@@ -638,7 +635,7 @@ extract_new_fences_from (flist_t old_fences, flist_tail_t new_fences,
                         int orig_max_seqno)
 {
   bool was_here_p = false;
-  insn_t insn = NULL_RTX;
+  insn_t insn = NULL;
   insn_t succ;
   succ_iterator si;
   ilist_iterator ii;
@@ -732,7 +729,7 @@ can_substitute_through_p (insn_t insn, ds_t ds)
   return false;
 }
 
-/* Substitute all occurences of INSN's destination in EXPR' vinsn with INSN's
+/* Substitute all occurrences of INSN's destination in EXPR' vinsn with INSN's
    source (if INSN is eligible for substitution).  Returns TRUE if
    substitution was actually performed, FALSE otherwise.  Substitution might
    be not performed because it's either EXPR' vinsn doesn't contain INSN's
@@ -761,7 +758,7 @@ substitute_reg_in_expr (expr_t expr, insn_t insn, bool undo)
   /* Substitute if INSN has a form of x:=y and LHS(INSN) occurs in *VI.  */
   if (rtx_ok_for_substitution_p (old, *where))
     {
-      rtx new_insn;
+      rtx_insn *new_insn;
       rtx *where_replace;
 
       /* We should copy these rtxes before substitution.  */
@@ -793,8 +790,8 @@ substitute_reg_in_expr (expr_t expr, insn_t insn, bool undo)
          /* Do not allow clobbering the address register of speculative
              insns.  */
          if ((EXPR_SPEC_DONE_DS (expr) & SPECULATIVE)
-              && bitmap_bit_p (VINSN_REG_USES (EXPR_VINSN (expr)),
-                              expr_dest_regno (expr)))
+              && register_unavailable_p (VINSN_REG_USES (EXPR_VINSN (expr)),
+                                        expr_dest_reg (expr)))
            EXPR_TARGET_AVAILABLE (expr) = false;
 
          return true;
@@ -806,64 +803,33 @@ substitute_reg_in_expr (expr_t expr, insn_t insn, bool undo)
     return false;
 }
 
-/* Helper function for count_occurences_equiv.  */
-static int
-count_occurrences_1 (rtx *cur_rtx, void *arg)
-{
-  rtx_search_arg_p p = (rtx_search_arg_p) arg;
-
-  /* The last param FOR_GCSE is true, because otherwise it performs excessive
-    substitutions like
-       r8 = r33
-       r16 = r33
-    for the last insn it presumes r33 equivalent to r8, so it changes it to
-    r33.  Actually, there's no change, but it spoils debugging.  */
-  if (exp_equiv_p (*cur_rtx, p->x, 0, true))
-    {
-      /* Bail out if we occupy more than one register.  */
-      if (REG_P (*cur_rtx)
-          && HARD_REGISTER_P (*cur_rtx)
-          && hard_regno_nregs[REGNO(*cur_rtx)][GET_MODE (*cur_rtx)] > 1)
-        {
-          p->n = 0;
-          return 1;
-        }
-
-      p->n++;
-
-      /* Do not traverse subexprs.  */
-      return -1;
-    }
-
-  if (GET_CODE (*cur_rtx) == SUBREG
-      && REG_P (p->x)
-      && (!REG_P (SUBREG_REG (*cur_rtx))
-         || REGNO (SUBREG_REG (*cur_rtx)) == REGNO (p->x)))
-    {
-      /* ??? Do not support substituting regs inside subregs.  In that case,
-         simplify_subreg will be called by validate_replace_rtx, and
-         unsubstitution will fail later.  */
-      p->n = 0;
-      return 1;
-    }
-
-  /* Continue search.  */
-  return 0;
-}
-
 /* Return the number of places WHAT appears within WHERE.
    Bail out when we found a reference occupying several hard registers.  */
 static int
-count_occurrences_equiv (rtx what, rtx where)
+count_occurrences_equiv (const_rtx what, const_rtx where)
 {
-  struct rtx_search_arg arg;
-
-  arg.x = what;
-  arg.n = 0;
-
-  for_each_rtx (&where, &count_occurrences_1, (void *) &arg);
-
-  return arg.n;
+  int count = 0;
+  subrtx_iterator::array_type array;
+  FOR_EACH_SUBRTX (iter, array, where, NONCONST)
+    {
+      const_rtx x = *iter;
+      if (REG_P (x) && REGNO (x) == REGNO (what))
+       {
+         /* Bail out if mode is different or more than one register is
+            used.  */
+         if (GET_MODE (x) != GET_MODE (what) || REG_NREGS (x) > 1)
+           return 0;
+         count += 1;
+       }
+      else if (GET_CODE (x) == SUBREG
+              && (!REG_P (SUBREG_REG (x))
+                  || REGNO (SUBREG_REG (x)) == REGNO (what)))
+       /* ??? Do not support substituting regs inside subregs.  In that case,
+          simplify_subreg will be called by validate_replace_rtx, and
+          unsubstitution will fail later.  */
+       return 0;
+    }
+  return count;
 }
 
 /* Returns TRUE if WHAT is found in WHERE rtx tree.  */
@@ -878,16 +844,16 @@ rtx_ok_for_substitution_p (rtx what, rtx where)
 
 /* Substitute VI's set source with REGNO.  Returns newly created pattern
    that has REGNO as its source.  */
-static rtx
+static rtx_insn *
 create_insn_rtx_with_rhs (vinsn_t vi, rtx rhs_rtx)
 {
   rtx lhs_rtx;
   rtx pattern;
-  rtx insn_rtx;
+  rtx_insn *insn_rtx;
 
   lhs_rtx = copy_rtx (VINSN_LHS (vi));
 
-  pattern = gen_rtx_SET (VOIDmode, lhs_rtx, rhs_rtx);
+  pattern = gen_rtx_SET (lhs_rtx, rhs_rtx);
   insn_rtx = create_insn_rtx_from_pattern (pattern, NULL_RTX);
 
   return insn_rtx;
@@ -918,7 +884,7 @@ static bool
 replace_src_with_reg_ok_p (insn_t insn, rtx new_src_reg)
 {
   vinsn_t vi = INSN_VINSN (insn);
-  enum machine_mode mode;
+  machine_mode mode;
   rtx dst_loc;
   bool res;
 
@@ -959,16 +925,16 @@ replace_dest_with_reg_ok_p (insn_t insn, rtx new_reg)
 }
 
 /* Create a pattern with rhs of VI and lhs of LHS_RTX.  */
-static rtx
+static rtx_insn *
 create_insn_rtx_with_lhs (vinsn_t vi, rtx lhs_rtx)
 {
   rtx rhs_rtx;
   rtx pattern;
-  rtx insn_rtx;
+  rtx_insn *insn_rtx;
 
   rhs_rtx = copy_rtx (VINSN_RHS (vi));
 
-  pattern = gen_rtx_SET (VOIDmode, lhs_rtx, rhs_rtx);
+  pattern = gen_rtx_SET (lhs_rtx, rhs_rtx);
   insn_rtx = create_insn_rtx_from_pattern (pattern, NULL_RTX);
 
   return insn_rtx;
@@ -979,7 +945,7 @@ create_insn_rtx_with_lhs (vinsn_t vi, rtx lhs_rtx)
 static void
 replace_dest_with_reg_in_expr (expr_t expr, rtx new_reg)
 {
-  rtx insn_rtx;
+  rtx_insn *insn_rtx;
   vinsn_t vinsn;
 
   insn_rtx = create_insn_rtx_with_lhs (EXPR_VINSN (expr), new_reg);
@@ -1026,24 +992,15 @@ vinsn_writes_one_of_regs_p (vinsn_t vi, regset used_regs,
 
    Code adopted from regrename.c::build_def_use.  */
 static enum reg_class
-get_reg_class (rtx insn)
+get_reg_class (rtx_insn *insn)
 {
-  int alt, i, n_ops;
+  int i, n_ops;
 
-  extract_insn (insn);
-  if (! constrain_operands (1))
-    fatal_insn_not_found (insn);
-  preprocess_constraints ();
-  alt = which_alternative;
+  extract_constrain_insn (insn);
+  preprocess_constraints (insn);
   n_ops = recog_data.n_operands;
 
-  for (i = 0; i < n_ops; ++i)
-    {
-      int matches = recog_op_alt[i][alt].matches;
-      if (matches >= 0)
-       recog_op_alt[i][alt].cl = recog_op_alt[matches][alt].cl;
-    }
-
+  const operand_alternative *op_alt = which_op_alt ();
   if (asm_noperands (PATTERN (insn)) > 0)
     {
       for (i = 0; i < n_ops; i++)
@@ -1051,7 +1008,7 @@ get_reg_class (rtx insn)
          {
            rtx *loc = recog_data.operand_loc[i];
            rtx op = *loc;
-           enum reg_class cl = recog_op_alt[i][alt].cl;
+           enum reg_class cl = alternative_class (op_alt, i);
 
            if (REG_P (op)
                && REGNO (op) == ORIGINAL_REGNO (op))
@@ -1065,7 +1022,7 @@ get_reg_class (rtx insn)
       for (i = 0; i < n_ops + recog_data.n_dups; i++)
        {
         int opn = i < n_ops ? i : recog_data.dup_num[i - n_ops];
-        enum reg_class cl = recog_op_alt[opn][alt].cl;
+        enum reg_class cl = alternative_class (op_alt, opn);
 
         if (recog_data.operand_type[opn] == OP_OUT ||
             recog_data.operand_type[opn] == OP_INOUT)
@@ -1080,7 +1037,6 @@ get_reg_class (rtx insn)
   return NO_REGS;
 }
 
-#ifdef HARD_REGNO_RENAME_OK
 /* Calculate HARD_REGNO_RENAME_OK data for REGNO.  */
 static void
 init_hard_regno_rename (int regno)
@@ -1099,14 +1055,12 @@ init_hard_regno_rename (int regno)
         SET_HARD_REG_BIT (sel_hrd.regs_for_rename[regno], cur_reg);
     }
 }
-#endif
 
 /* A wrapper around HARD_REGNO_RENAME_OK that will look into the hard regs
    data first.  */
 static inline bool
 sel_hard_regno_rename_ok (int from ATTRIBUTE_UNUSED, int to ATTRIBUTE_UNUSED)
 {
-#ifdef HARD_REGNO_RENAME_OK
   /* Check whether this is all calculated.  */
   if (TEST_HARD_REG_BIT (sel_hrd.regs_for_rename[from], from))
     return TEST_HARD_REG_BIT (sel_hrd.regs_for_rename[from], to);
@@ -1114,14 +1068,11 @@ sel_hard_regno_rename_ok (int from ATTRIBUTE_UNUSED, int to ATTRIBUTE_UNUSED)
   init_hard_regno_rename (from);
 
   return TEST_HARD_REG_BIT (sel_hrd.regs_for_rename[from], to);
-#else
-  return true;
-#endif
 }
 
 /* Calculate set of registers that are capable of holding MODE.  */
 static void
-init_regs_for_mode (enum machine_mode mode)
+init_regs_for_mode (machine_mode mode)
 {
   int cur_reg;
 
@@ -1130,19 +1081,29 @@ init_regs_for_mode (enum machine_mode mode)
 
   for (cur_reg = 0; cur_reg < FIRST_PSEUDO_REGISTER; cur_reg++)
     {
-      int nregs = hard_regno_nregs[cur_reg][mode];
+      int nregs;
       int i;
 
+      /* See whether it accepts all modes that occur in
+         original insns.  */
+      if (! HARD_REGNO_MODE_OK (cur_reg, mode))
+        continue;
+
+      nregs = hard_regno_nregs[cur_reg][mode];
+
       for (i = nregs - 1; i >= 0; --i)
         if (fixed_regs[cur_reg + i]
                 || global_regs[cur_reg + i]
             /* Can't use regs which aren't saved by
                the prologue.  */
             || !TEST_HARD_REG_BIT (sel_hrd.regs_ever_used, cur_reg + i)
+           /* Can't use regs with non-null REG_BASE_VALUE, because adjusting
+              it affects aliasing globally and invalidates all AV sets.  */
+           || get_reg_base_value (cur_reg + i)
 #ifdef LEAF_REGISTERS
             /* We can't use a non-leaf register if we're in a
                leaf function.  */
-            || (current_function_is_leaf
+            || (crtl->is_leaf
                 && !LEAF_REGISTERS[cur_reg + i])
 #endif
             )
@@ -1151,11 +1112,6 @@ init_regs_for_mode (enum machine_mode mode)
       if (i >= 0)
         continue;
 
-      /* See whether it accepts all modes that occur in
-         original insns.  */
-      if (! HARD_REGNO_MODE_OK (cur_reg, mode))
-        continue;
-
       if (HARD_REGNO_CALL_PART_CLOBBERED (cur_reg, mode))
         SET_HARD_REG_BIT (sel_hrd.regs_for_call_clobbered[mode],
                           cur_reg);
@@ -1209,7 +1165,7 @@ static void
 mark_unavailable_hard_regs (def_t def, struct reg_rename *reg_rename_p,
                             regset used_regs ATTRIBUTE_UNUSED)
 {
-  enum machine_mode mode;
+  machine_mode mode;
   enum reg_class cl = NO_REGS;
   rtx orig_dest;
   unsigned cur_reg, regno;
@@ -1259,17 +1215,12 @@ mark_unavailable_hard_regs (def_t def, struct reg_rename *reg_rename_p,
      FIXME: it is enough to do this once per all original defs.  */
   if (frame_pointer_needed)
     {
-      int i;
+      add_to_hard_reg_set (&reg_rename_p->unavailable_hard_regs,
+                          Pmode, FRAME_POINTER_REGNUM);
 
-      for (i = hard_regno_nregs[FRAME_POINTER_REGNUM][Pmode]; i--;)
-       SET_HARD_REG_BIT (reg_rename_p->unavailable_hard_regs,
-                          FRAME_POINTER_REGNUM + i);
-
-#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
-      for (i = hard_regno_nregs[HARD_FRAME_POINTER_REGNUM][Pmode]; i--;)
-       SET_HARD_REG_BIT (reg_rename_p->unavailable_hard_regs,
-                          HARD_FRAME_POINTER_REGNUM + i);
-#endif
+      if (!HARD_FRAME_POINTER_IS_FRAME_POINTER)
+        add_to_hard_reg_set (&reg_rename_p->unavailable_hard_regs, 
+                            Pmode, HARD_FRAME_POINTER_REGNUM);
     }
 
 #ifdef STACK_REGS
@@ -1384,7 +1335,7 @@ choose_best_reg_1 (HARD_REG_SET hard_regs_used,
 {
   int best_new_reg;
   unsigned cur_reg;
-  enum machine_mode mode = VOIDmode;
+  machine_mode mode = VOIDmode;
   unsigned regno, i, n;
   hard_reg_set_iterator hrsi;
   def_list_iterator di;
@@ -1495,7 +1446,7 @@ choose_best_pseudo_reg (regset used_regs,
 {
   def_list_iterator i;
   def_t def;
-  enum machine_mode mode = VOIDmode;
+  machine_mode mode = VOIDmode;
   bool bad_hard_regs = false;
 
   /* We should not use this after reload.  */
@@ -1573,7 +1524,7 @@ verify_target_availability (expr_t expr, regset used_regs,
                            struct reg_rename *reg_rename_p)
 {
   unsigned n, i, regno;
-  enum machine_mode mode;
+  machine_mode mode;
   bool target_available, live_available, hard_available;
 
   if (!REG_P (EXPR_LHS (expr)) || EXPR_TARGET_AVAILABLE (expr) < 0)
@@ -1582,7 +1533,7 @@ verify_target_availability (expr_t expr, regset used_regs,
   regno = expr_dest_regno (expr);
   mode = GET_MODE (EXPR_LHS (expr));
   target_available = EXPR_TARGET_AVAILABLE (expr) == 1;
-  n = reload_completed ? hard_regno_nregs[regno][mode] : 1;
+  n = HARD_REGISTER_NUM_P (regno) ? hard_regno_nregs[regno][mode] : 1;
 
   live_available = hard_available = true;
   for (i = 0; i < n; i++)
@@ -1823,10 +1774,10 @@ static insn_t
 create_speculation_check (expr_t c_expr, ds_t check_ds, insn_t orig_insn)
 {
   rtx check_pattern;
-  rtx insn_rtx;
+  rtx_insn *insn_rtx;
   insn_t insn;
   basic_block recovery_block;
-  rtx label;
+  rtx_insn *label;
 
   /* Create a recovery block if target is going to emit branchy check, or if
      ORIG_INSN was speculative already.  */
@@ -1839,7 +1790,7 @@ create_speculation_check (expr_t c_expr, ds_t check_ds, insn_t orig_insn)
   else
     {
       recovery_block = NULL;
-      label = NULL_RTX;
+      label = NULL;
     }
 
   /* Get pattern of the check.  */
@@ -1892,7 +1843,7 @@ create_speculation_check (expr_t c_expr, ds_t check_ds, insn_t orig_insn)
 
 /* True when INSN is a "regN = regN" copy.  */
 static bool
-identical_copy_p (rtx insn)
+identical_copy_p (rtx_insn *insn)
 {
   rtx lhs, rhs, pat;
 
@@ -1915,7 +1866,7 @@ identical_copy_p (rtx insn)
 /* Undo all transformations on *AV_PTR that were done when
    moving through INSN.  */
 static void
-undo_transformations (av_set_t *av_ptr, rtx insn)
+undo_transformations (av_set_t *av_ptr, rtx_insn *insn)
 {
   av_set_iterator av_iter;
   expr_t expr;
@@ -1948,9 +1899,7 @@ undo_transformations (av_set_t *av_ptr, rtx insn)
         {
           expr_history_def *phist;
 
-          phist = VEC_index (expr_history_def,
-                             EXPR_HISTORY_OF_CHANGES (expr),
-                             index);
+          phist = &EXPR_HISTORY_OF_CHANGES (expr)[index];
 
           switch (phist->type)
             {
@@ -2120,6 +2069,62 @@ moving_insn_creates_bookkeeping_block_p (insn_t insn,
   return TRUE;
 }
 
+/* Return true when the conflict with newly created implicit clobbers
+   between EXPR and THROUGH_INSN is found because of renaming.  */
+static bool
+implicit_clobber_conflict_p (insn_t through_insn, expr_t expr)
+{
+  HARD_REG_SET temp;
+  rtx_insn *insn;
+  rtx reg, rhs, pat;
+  hard_reg_set_iterator hrsi;
+  unsigned regno;
+  bool valid;
+
+  /* Make a new pseudo register.  */
+  reg = gen_reg_rtx (GET_MODE (EXPR_LHS (expr)));
+  max_regno = max_reg_num ();
+  maybe_extend_reg_info_p ();
+
+  /* Validate a change and bail out early.  */
+  insn = EXPR_INSN_RTX (expr);
+  validate_change (insn, &SET_DEST (PATTERN (insn)), reg, true);
+  valid = verify_changes (0);
+  cancel_changes (0);
+  if (!valid)
+    {
+      if (sched_verbose >= 6)
+       sel_print ("implicit clobbers failed validation, ");
+      return true;
+    }
+
+  /* Make a new insn with it.  */
+  rhs = copy_rtx (VINSN_RHS (EXPR_VINSN (expr)));
+  pat = gen_rtx_SET (reg, rhs);
+  start_sequence ();
+  insn = emit_insn (pat);
+  end_sequence ();
+
+  /* Calculate implicit clobbers.  */
+  extract_insn (insn);
+  preprocess_constraints (insn);
+  ira_implicitly_set_insn_hard_regs (&temp);
+  AND_COMPL_HARD_REG_SET (temp, ira_no_alloc_regs);
+
+  /* If any implicit clobber registers intersect with regular ones in
+     through_insn, we have a dependency and thus bail out.  */
+  EXECUTE_IF_SET_IN_HARD_REG_SET (temp, 0, regno, hrsi)
+    {
+      vinsn_t vi = INSN_VINSN (through_insn);
+      if (bitmap_bit_p (VINSN_REG_SETS (vi), regno)
+         || bitmap_bit_p (VINSN_REG_CLOBBERS (vi), regno)
+         || bitmap_bit_p (VINSN_REG_USES (vi), regno))
+       return true;
+    }
+
+  return false;
+}
+
 /* Modifies EXPR so it can be moved through the THROUGH_INSN,
    performing necessary transformations.  Record the type of transformation
    made in PTRANS_TYPE, when it is not NULL.  When INSIDE_INSN_GROUP,
@@ -2138,6 +2143,15 @@ moveup_expr (expr_t expr, insn_t through_insn, bool inside_insn_group,
   ds_t *has_dep_p;
   ds_t full_ds;
 
+  /* ??? We use dependencies of non-debug insns on debug insns to
+     indicate that the debug insns need to be reset if the non-debug
+     insn is pulled ahead of it.  It's hard to figure out how to
+     introduce such a notion in sel-sched, but it already fails to
+     support debug insns in other ways, so we just go ahead and
+     let the deug insns go corrupt for now.  */
+  if (DEBUG_INSN_P (through_insn) && !DEBUG_INSN_P (insn))
+    return MOVEUP_EXPR_SAME;
+
   /* When inside_insn_group, delegate to the helper.  */
   if (inside_insn_group)
     return moveup_expr_inside_insn_group (expr, through_insn);
@@ -2168,10 +2182,8 @@ moveup_expr (expr_t expr, insn_t through_insn, bool inside_insn_group,
               || ! in_current_region_p (fallthru_bb))
             return MOVEUP_EXPR_NULL;
 
-          /* And it should be mutually exclusive with through_insn, or
-             be an unconditional jump.  */
-          if (! any_uncondjump_p (insn)
-              && ! sched_insns_conditions_mutex_p (insn, through_insn)
+          /* And it should be mutually exclusive with through_insn.  */
+          if (! sched_insns_conditions_mutex_p (insn, through_insn)
              && ! DEBUG_INSN_P (through_insn))
             return MOVEUP_EXPR_NULL;
         }
@@ -2245,6 +2257,17 @@ moveup_expr (expr_t expr, insn_t through_insn, bool inside_insn_group,
       if (!enable_schedule_as_rhs_p || !EXPR_SEPARABLE_P (expr))
         return MOVEUP_EXPR_NULL;
 
+      /* When renaming a hard register to a pseudo before reload, extra
+        dependencies can occur from the implicit clobbers of the insn.
+        Filter out such cases here.  */
+      if (!reload_completed && REG_P (EXPR_LHS (expr))
+         && HARD_REGISTER_P (EXPR_LHS (expr))
+         && implicit_clobber_conflict_p (through_insn, expr))
+       {
+         if (sched_verbose >= 6)
+           sel_print ("implicit clobbers conflict detected, ");
+         return MOVEUP_EXPR_NULL;
+       }
       EXPR_TARGET_AVAILABLE (expr) = false;
       was_target_conflict = true;
       as_rhs = true;
@@ -2735,10 +2758,10 @@ compute_av_set_at_bb_end (insn_t insn, ilist_t p, int ws)
         sel_print ("real successors num: %d\n", sinfo->all_succs_n);
     }
 
-  /* Add insn to to the tail of current path.  */
+  /* Add insn to the tail of current path.  */
   ilist_add (&p, insn);
 
-  FOR_EACH_VEC_ELT (rtx, sinfo->succs_ok, is, succ)
+  FOR_EACH_VEC_ELT (sinfo->succs_ok, is, succ)
     {
       av_set_t succ_set;
 
@@ -2746,7 +2769,7 @@ compute_av_set_at_bb_end (insn_t insn, ilist_t p, int ws)
       succ_set = compute_av_set_inside_bb (succ, p, ws, true);
 
       av_set_split_usefulness (succ_set,
-                               VEC_index (int, sinfo->probs_ok, is),
+                               sinfo->probs_ok[is],
                                sinfo->all_prob);
 
       if (sinfo->all_succs_n > 1)
@@ -2792,7 +2815,7 @@ compute_av_set_at_bb_end (insn_t insn, ilist_t p, int ws)
   /* Check liveness restrictions via hard way when there are more than
      two successors.  */
   if (sinfo->succs_ok_n > 2)
-    FOR_EACH_VEC_ELT (rtx, sinfo->succs_ok, is, succ)
+    FOR_EACH_VEC_ELT (sinfo->succs_ok, is, succ)
       {
         basic_block succ_bb = BLOCK_FOR_INSN (succ);
 
@@ -2803,7 +2826,7 @@ compute_av_set_at_bb_end (insn_t insn, ilist_t p, int ws)
 
   /* Finally, check liveness restrictions on paths leaving the region.  */
   if (sinfo->all_succs_n > sinfo->succs_ok_n)
-    FOR_EACH_VEC_ELT (rtx, sinfo->succs_other, is, succ)
+    FOR_EACH_VEC_ELT (sinfo->succs_other, is, succ)
       mark_unavailable_targets
         (av1, NULL, BB_LV_SET (BLOCK_FOR_INSN (succ)));
 
@@ -3138,7 +3161,7 @@ compute_live (insn_t insn)
 
 /* Update liveness sets for INSN.  */
 static inline void
-update_liveness_on_insn (rtx insn)
+update_liveness_on_insn (rtx_insn *insn)
 {
   ignore_first = true;
   compute_live (insn);
@@ -3146,9 +3169,9 @@ update_liveness_on_insn (rtx insn)
 
 /* Compute liveness below INSN and write it into REGS.  */
 static inline void
-compute_live_below_insn (rtx insn, regset regs)
+compute_live_below_insn (rtx_insn *insn, regset regs)
 {
-  rtx succ;
+  rtx_insn *succ;
   succ_iterator si;
 
   FOR_EACH_SUCC_1 (succ, si, insn, SUCCS_ALL)
@@ -3157,7 +3180,7 @@ compute_live_below_insn (rtx insn, regset regs)
 
 /* Update the data gathered in av and lv sets starting from INSN.  */
 static void
-update_data_sets (rtx insn)
+update_data_sets (rtx_insn *insn)
 {
   update_liveness_on_insn (insn);
   if (sel_bb_head_p (insn))
@@ -3445,8 +3468,6 @@ process_pipelined_exprs (av_set_t *av_ptr)
 static void
 process_spec_exprs (av_set_t *av_ptr)
 {
-  bool try_data_p = true;
-  bool try_control_p = true;
   expr_t expr;
   av_set_iterator si;
 
@@ -3472,34 +3493,6 @@ process_spec_exprs (av_set_t *av_ptr)
           av_set_iter_remove (&si);
           continue;
         }
-
-      if ((spec_info->flags & PREFER_NON_DATA_SPEC)
-          && !(ds & BEGIN_DATA))
-        try_data_p = false;
-
-      if ((spec_info->flags & PREFER_NON_CONTROL_SPEC)
-          && !(ds & BEGIN_CONTROL))
-        try_control_p = false;
-    }
-
-  FOR_EACH_EXPR_1 (expr, si, av_ptr)
-    {
-      ds_t ds;
-
-      ds = EXPR_SPEC_DONE_DS (expr);
-
-      if (ds & SPECULATIVE)
-        {
-          if ((ds & BEGIN_DATA) && !try_data_p)
-            /* We don't want any data speculative instructions right
-               now.  */
-            av_set_iter_remove (&si);
-
-          if ((ds & BEGIN_CONTROL) && !try_control_p)
-            /* We don't want any control speculative instructions right
-               now.  */
-            av_set_iter_remove (&si);
-        }
     }
 }
 
@@ -3567,29 +3560,38 @@ process_use_exprs (av_set_t *av_ptr)
   return NULL;
 }
 
-/* Lookup EXPR in VINSN_VEC and return TRUE if found.  */
+/* Lookup EXPR in VINSN_VEC and return TRUE if found.  Also check patterns from
+   EXPR's history of changes.  */
 static bool
 vinsn_vec_has_expr_p (vinsn_vec_t vinsn_vec, expr_t expr)
 {
-  vinsn_t vinsn;
+  vinsn_t vinsn, expr_vinsn;
   int n;
+  unsigned i;
 
-  FOR_EACH_VEC_ELT (vinsn_t, vinsn_vec, n, vinsn)
-    if (VINSN_SEPARABLE_P (vinsn))
-      {
-        if (vinsn_equal_p (vinsn, EXPR_VINSN (expr)))
-          return true;
-      }
-    else
-      {
-        /* For non-separable instructions, the blocking insn can have
-           another pattern due to substitution, and we can't choose
-           different register as in the above case.  Check all registers
-           being written instead.  */
-        if (bitmap_intersect_p (VINSN_REG_SETS (vinsn),
-                                VINSN_REG_SETS (EXPR_VINSN (expr))))
-          return true;
-      }
+  /* Start with checking expr itself and then proceed with all the old forms
+     of expr taken from its history vector.  */
+  for (i = 0, expr_vinsn = EXPR_VINSN (expr);
+       expr_vinsn;
+       expr_vinsn = (i < EXPR_HISTORY_OF_CHANGES (expr).length ()
+                    ? EXPR_HISTORY_OF_CHANGES (expr)[i++].old_expr_vinsn
+                    : NULL))
+    FOR_EACH_VEC_ELT (vinsn_vec, n, vinsn)
+      if (VINSN_SEPARABLE_P (vinsn))
+       {
+         if (vinsn_equal_p (vinsn, expr_vinsn))
+           return true;
+       }
+      else
+       {
+         /* For non-separable instructions, the blocking insn can have
+            another pattern due to substitution, and we can't choose
+            different register as in the above case.  Check all registers
+            being written instead.  */
+         if (bitmap_intersect_p (VINSN_REG_SETS (vinsn),
+                                 VINSN_REG_SETS (expr_vinsn)))
+           return true;
+       }
 
   return false;
 }
@@ -3625,12 +3627,12 @@ av_set_could_be_blocked_by_bookkeeping_p (av_set_t orig_ops, void *static_params
      renaming.  Check with the right register instead.  */
   if (sparams->dest && REG_P (sparams->dest))
     {
-      unsigned regno = REGNO (sparams->dest);
+      rtx reg = sparams->dest;
       vinsn_t failed_vinsn = INSN_VINSN (sparams->failed_insn);
 
-      if (bitmap_bit_p (VINSN_REG_SETS (failed_vinsn), regno)
-         || bitmap_bit_p (VINSN_REG_USES (failed_vinsn), regno)
-         || bitmap_bit_p (VINSN_REG_CLOBBERS (failed_vinsn), regno))
+      if (register_unavailable_p (VINSN_REG_SETS (failed_vinsn), reg)
+         || register_unavailable_p (VINSN_REG_USES (failed_vinsn), reg)
+         || register_unavailable_p (VINSN_REG_CLOBBERS (failed_vinsn), reg))
        return true;
     }
 
@@ -3642,15 +3644,15 @@ av_set_could_be_blocked_by_bookkeeping_p (av_set_t orig_ops, void *static_params
 static void
 vinsn_vec_clear (vinsn_vec_t *vinsn_vec)
 {
-  unsigned len = VEC_length (vinsn_t, *vinsn_vec);
+  unsigned len = vinsn_vec->length ();
   if (len > 0)
     {
       vinsn_t vinsn;
       int n;
 
-      FOR_EACH_VEC_ELT (vinsn_t, *vinsn_vec, n, vinsn)
+      FOR_EACH_VEC_ELT (*vinsn_vec, n, vinsn)
         vinsn_detach (vinsn);
-      VEC_block_remove (vinsn_t, *vinsn_vec, 0, len);
+      vinsn_vec->block_remove (0, len);
     }
 }
 
@@ -3659,15 +3661,14 @@ static void
 vinsn_vec_add (vinsn_vec_t *vinsn_vec, expr_t expr)
 {
   vinsn_attach (EXPR_VINSN (expr));
-  VEC_safe_push (vinsn_t, heap, *vinsn_vec, EXPR_VINSN (expr));
+  vinsn_vec->safe_push (EXPR_VINSN (expr));
 }
 
 /* Free the vector representing blocked expressions.  */
 static void
-vinsn_vec_free (vinsn_vec_t *vinsn_vec)
+vinsn_vec_free (vinsn_vec_t &vinsn_vec)
 {
-  if (*vinsn_vec)
-    VEC_free (vinsn_t, heap, *vinsn_vec);
+  vinsn_vec.release ();
 }
 
 /* Increase EXPR_PRIORITY_ADJ for INSN by AMOUNT.  */
@@ -3704,15 +3705,15 @@ fill_vec_av_set (av_set_t av, blist_t bnds, fence_t fence,
     return false;
 
   /* Empty vector from the previous stuff.  */
-  if (VEC_length (expr_t, vec_av_set) > 0)
-    VEC_block_remove (expr_t, vec_av_set, 0, VEC_length (expr_t, vec_av_set));
+  if (vec_av_set.length () > 0)
+    vec_av_set.block_remove (0, vec_av_set.length ());
 
   /* Turn the set into a vector for sorting and call sel_target_adjust_priority
      for each insn.  */
-  gcc_assert (VEC_empty (expr_t, vec_av_set));
+  gcc_assert (vec_av_set.is_empty ());
   FOR_EACH_EXPR (expr, si, av)
     {
-      VEC_safe_push (expr_t, heap, vec_av_set, expr);
+      vec_av_set.safe_push (expr);
 
       gcc_assert (EXPR_PRIORITY_ADJ (expr) == 0 || *pneed_stall);
 
@@ -3721,7 +3722,7 @@ fill_vec_av_set (av_set_t av, blist_t bnds, fence_t fence,
     }
 
   /* Sort the vector.  */
-  VEC_qsort (expr_t, vec_av_set, sel_rank_for_schedule);
+  vec_av_set.qsort (sel_rank_for_schedule);
 
   /* We record maximal priority of insns in av set for current instruction
      group.  */
@@ -3729,20 +3730,21 @@ fill_vec_av_set (av_set_t av, blist_t bnds, fence_t fence,
     av_max_prio = est_ticks_till_branch = INT_MIN;
 
   /* Filter out inappropriate expressions.  Loop's direction is reversed to
-     visit "best" instructions first.  We assume that VEC_unordered_remove
+     visit "best" instructions first.  We assume that vec::unordered_remove
      moves last element in place of one being deleted.  */
-  for (n = VEC_length (expr_t, vec_av_set) - 1, stalled = 0; n >= 0; n--)
+  for (n = vec_av_set.length () - 1, stalled = 0; n >= 0; n--)
     {
-      expr_t expr = VEC_index (expr_t, vec_av_set, n);
+      expr_t expr = vec_av_set[n];
       insn_t insn = EXPR_INSN_RTX (expr);
-      char target_available;
+      signed char target_available;
       bool is_orig_reg_p = true;
       int need_cycles, new_prio;
+      bool fence_insn_p = INSN_UID (insn) == INSN_UID (FENCE_INSN (fence));
 
       /* Don't allow any insns other than from SCHED_GROUP if we have one.  */
       if (FENCE_SCHED_NEXT (fence) && insn != FENCE_SCHED_NEXT (fence))
         {
-          VEC_unordered_remove (expr_t, vec_av_set, n);
+          vec_av_set.unordered_remove (n);
           continue;
         }
 
@@ -3757,7 +3759,8 @@ fill_vec_av_set (av_set_t av, blist_t bnds, fence_t fence,
 
       /* If insn was already scheduled on the current fence,
         set TARGET_AVAILABLE to -1 no matter what expr's attribute says.  */
-      if (vinsn_vec_has_expr_p (vec_target_unavailable_vinsns, expr))
+      if (vinsn_vec_has_expr_p (vec_target_unavailable_vinsns, expr)
+         && !fence_insn_p)
        target_available = -1;
 
       /* If the availability of the EXPR is invalidated by the insertion of
@@ -3766,7 +3769,7 @@ fill_vec_av_set (av_set_t av, blist_t bnds, fence_t fence,
         we have to recompute the set of available registers for it.  */
       if (vinsn_vec_has_expr_p (vec_bookkeeping_blocked_vinsns, expr))
        {
-          VEC_unordered_remove (expr_t, vec_av_set, n);
+          vec_av_set.unordered_remove (n);
           if (sched_verbose >= 4)
             sel_print ("Expr %d is blocked by bookkeeping inserted earlier\n",
                        INSN_UID (insn));
@@ -3783,18 +3786,25 @@ fill_vec_av_set (av_set_t av, blist_t bnds, fence_t fence,
                (target_available == false
                 && !EXPR_SEPARABLE_P (expr))
                /* Don't try to find a register for low-priority expression.  */
-               || (int) VEC_length (expr_t, vec_av_set) - 1 - n >= max_insns_to_rename
+               || (int) vec_av_set.length () - 1 - n >= max_insns_to_rename
                /* ??? FIXME: Don't try to rename data speculation.  */
                || (EXPR_SPEC_DONE_DS (expr) & BEGIN_DATA)
                || ! find_best_reg_for_expr (expr, bnds, &is_orig_reg_p))
         {
-          VEC_unordered_remove (expr_t, vec_av_set, n);
+          vec_av_set.unordered_remove (n);
           if (sched_verbose >= 4)
             sel_print ("Expr %d has no suitable target register\n",
                        INSN_UID (insn));
-          continue;
+
+         /* A fence insn should not get here.  */
+         gcc_assert (!fence_insn_p);
+         continue;
         }
 
+      /* At this point a fence insn should always be available.  */
+      gcc_assert (!fence_insn_p
+                 || INSN_UID (FENCE_INSN (fence)) == INSN_UID (EXPR_INSN_RTX (expr)));
+
       /* Filter expressions that need to be renamed or speculated when
         pipelining, because compensating register copies or speculation
         checks are likely to be placed near the beginning of the loop,
@@ -3808,7 +3818,7 @@ fill_vec_av_set (av_set_t av, blist_t bnds, fence_t fence,
 
          if ((int) current_loop_nest->ninsns < 9)
            {
-             VEC_unordered_remove (expr_t, vec_av_set, n);
+             vec_av_set.unordered_remove (n);
              if (sched_verbose >= 4)
                sel_print ("Pipelining expr %d will likely cause stall\n",
                           INSN_UID (insn));
@@ -3819,7 +3829,7 @@ fill_vec_av_set (av_set_t av, blist_t bnds, fence_t fence,
              < need_n_ticks_till_branch * issue_rate / 2
              && est_ticks_till_branch < need_n_ticks_till_branch)
             {
-              VEC_unordered_remove (expr_t, vec_av_set, n);
+              vec_av_set.unordered_remove (n);
               if (sched_verbose >= 4)
                 sel_print ("Pipelining expr %d will likely cause stall\n",
                            INSN_UID (insn));
@@ -3834,7 +3844,7 @@ fill_vec_av_set (av_set_t av, blist_t bnds, fence_t fence,
        {
           stalled++;
           min_need_stall = min_need_stall < 0 ? 1 : MIN (min_need_stall, 1);
-          VEC_unordered_remove (expr_t, vec_av_set, n);
+          vec_av_set.unordered_remove (n);
          if (sched_verbose >= 4)
            sel_print ("Delaying speculation check %d until its first use\n",
                       INSN_UID (insn));
@@ -3861,7 +3871,7 @@ fill_vec_av_set (av_set_t av, blist_t bnds, fence_t fence,
              min_need_stall = (min_need_stall < 0
                                ? need_cycles
                                : MIN (min_need_stall, need_cycles));
-             VEC_unordered_remove (expr_t, vec_av_set, n);
+             vec_av_set.unordered_remove (n);
 
              if (sched_verbose >= 4)
                sel_print ("Expr %d is not ready until cycle %d (cached)\n",
@@ -3899,7 +3909,7 @@ fill_vec_av_set (av_set_t av, blist_t bnds, fence_t fence,
                             ? need_cycles
                             : MIN (min_need_stall, need_cycles));
 
-          VEC_unordered_remove (expr_t, vec_av_set, n);
+          vec_av_set.unordered_remove (n);
 
           if (sched_verbose >= 4)
             sel_print ("Expr %d is not ready yet until cycle %d\n",
@@ -3917,14 +3927,14 @@ fill_vec_av_set (av_set_t av, blist_t bnds, fence_t fence,
   if (FENCE_SCHED_NEXT (fence))
     {
       gcc_assert (sched_next_worked == 1);
-      FENCE_SCHED_NEXT (fence) = NULL_RTX;
+      FENCE_SCHED_NEXT (fence) = NULL;
     }
 
   /* No need to stall if this variable was not initialized.  */
   if (min_need_stall < 0)
     min_need_stall = 0;
 
-  if (VEC_empty (expr_t, vec_av_set))
+  if (vec_av_set.is_empty ())
     {
       /* We need to set *pneed_stall here, because later we skip this code
          when ready list is empty.  */
@@ -3935,14 +3945,14 @@ fill_vec_av_set (av_set_t av, blist_t bnds, fence_t fence,
     gcc_assert (min_need_stall == 0);
 
   /* Sort the vector.  */
-  VEC_qsort (expr_t, vec_av_set, sel_rank_for_schedule);
+  vec_av_set.qsort (sel_rank_for_schedule);
 
   if (sched_verbose >= 4)
     {
       sel_print ("Total ready exprs: %d, stalled: %d\n",
-                 VEC_length (expr_t, vec_av_set), stalled);
-      sel_print ("Sorted av set (%d): ", VEC_length (expr_t, vec_av_set));
-      FOR_EACH_VEC_ELT (expr_t, vec_av_set, n, expr)
+                 vec_av_set.length (), stalled);
+      sel_print ("Sorted av set (%d): ", vec_av_set.length ());
+      FOR_EACH_VEC_ELT (vec_av_set, n, expr)
         dump_expr (expr);
       sel_print ("\n");
     }
@@ -3960,7 +3970,7 @@ convert_vec_av_set_to_ready (void)
   expr_t expr;
 
   /* Allocate and fill the ready list from the sorted vector.  */
-  ready.n_ready = VEC_length (expr_t, vec_av_set);
+  ready.n_ready = vec_av_set.length ();
   ready.first = ready.n_ready - 1;
 
   gcc_assert (ready.n_ready > 0);
@@ -3971,7 +3981,7 @@ convert_vec_av_set_to_ready (void)
       sched_extend_ready_list (ready.n_ready);
     }
 
-  FOR_EACH_VEC_ELT (expr_t, vec_av_set, n, expr)
+  FOR_EACH_VEC_ELT (vec_av_set, n, expr)
     {
       vinsn_t vi = EXPR_VINSN (expr);
       insn_t insn = VINSN_INSN_RTX (vi);
@@ -4116,29 +4126,25 @@ invoke_reorder_hooks (fence_t fence)
   if (issue_more && ran_hook)
     {
       int i, j, n;
-      rtx *arr = ready.vec;
-      expr_t *vec = VEC_address (expr_t, vec_av_set);
+      rtx_insn **arr = ready.vec;
+      expr_t *vec = vec_av_set.address ();
 
       for (i = 0, n = ready.n_ready; i < n; i++)
         if (EXPR_INSN_RTX (vec[i]) != arr[i])
           {
-            expr_t tmp;
-
             for (j = i; j < n; j++)
               if (EXPR_INSN_RTX (vec[j]) == arr[i])
                 break;
             gcc_assert (j < n);
 
-            tmp = vec[i];
-            vec[i] = vec[j];
-            vec[j] = tmp;
+           std::swap (vec[i], vec[j]);
           }
     }
 
   return issue_more;
 }
 
-/* Return an EXPR correponding to INDEX element of ready list, if
+/* Return an EXPR corresponding to INDEX element of ready list, if
    FOLLOW_READY_ELEMENT is true (i.e., an expr of
    ready_element (&ready, INDEX) will be returned), and to INDEX element of
    ready.vec otherwise.  */
@@ -4150,7 +4156,7 @@ find_expr_for_ready (int index, bool follow_ready_element)
 
   real_index = follow_ready_element ? ready.first - index : index;
 
-  expr = VEC_index (expr_t, vec_av_set, real_index);
+  expr = vec_av_set[real_index];
   gcc_assert (ready.vec[real_index] == EXPR_INSN_RTX (expr));
 
   return expr;
@@ -4181,7 +4187,7 @@ invoke_dfa_lookahead_guard (void)
       if (! have_hook || i == 0)
         r = 0;
       else
-        r = !targetm.sched.first_cycle_multipass_dfa_lookahead_guard (insn);
+        r = targetm.sched.first_cycle_multipass_dfa_lookahead_guard (insn, i);
 
       gcc_assert (INSN_CODE (insn) >= 0);
 
@@ -4243,7 +4249,7 @@ calculate_privileged_insns (void)
    number is ISSUE_MORE.  FENCE and BEST_INSN are the current fence
    and the insn chosen for scheduling, respectively.  */
 static int
-invoke_aftermath_hooks (fence_t fence, rtx best_insn, int issue_more)
+invoke_aftermath_hooks (fence_t fence, rtx_insn *best_insn, int issue_more)
 {
   gcc_assert (INSN_P (best_insn));
 
@@ -4267,7 +4273,7 @@ invoke_aftermath_hooks (fence_t fence, rtx best_insn, int issue_more)
 
 /* Estimate the cost of issuing INSN on DFA state STATE.  */
 static int
-estimate_insn_cost (rtx insn, state_t state)
+estimate_insn_cost (rtx_insn *insn, state_t state)
 {
   static state_t temp = NULL;
   int cost;
@@ -4290,7 +4296,7 @@ estimate_insn_cost (rtx insn, state_t state)
 static int
 get_expr_cost (expr_t expr, fence_t fence)
 {
-  rtx insn = EXPR_INSN_RTX (expr);
+  rtx_insn *insn = EXPR_INSN_RTX (expr);
 
   if (recog_memoized (insn) < 0)
     {
@@ -4320,8 +4326,9 @@ choose_best_insn (fence_t fence, int privileged_n, int *index)
   if (dfa_lookahead > 0)
     {
       cycle_issued_insns = FENCE_ISSUED_INSNS (fence);
+      /* TODO: pass equivalent of first_cycle_insn_p to max_issue ().  */
       can_issue = max_issue (&ready, privileged_n,
-                             FENCE_STATE (fence), index);
+                             FENCE_STATE (fence), true, index);
       if (sched_verbose >= 2)
         sel_print ("max_issue: we can issue %d insns, already did %d insns\n",
                    can_issue, FENCE_ISSUED_INSNS (fence));
@@ -4402,7 +4409,8 @@ find_best_expr (av_set_t *av_vliw_ptr, blist_t bnds, fence_t fence,
     {
       can_issue_more = invoke_aftermath_hooks (fence, EXPR_INSN_RTX (best),
                                                can_issue_more);
-      if (can_issue_more == 0)
+      if (targetm.sched.variable_issue
+         && can_issue_more == 0)
         *pneed_stall = 1;
     }
 
@@ -4486,7 +4494,8 @@ find_block_for_bookkeeping (edge e1, edge e2, bool lax)
   edge e;
 
   /* Loop over edges from E1 to E2, inclusive.  */
-  for (e = e1; !lax || e->dest != EXIT_BLOCK_PTR; e = EDGE_SUCC (e->dest, 0))
+  for (e = e1; !lax || e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun); e =
+       EDGE_SUCC (e->dest, 0))
     {
       if (EDGE_COUNT (e->dest->preds) == 2)
        {
@@ -4546,7 +4555,7 @@ create_block_for_bookkeeping (edge e1, edge e2)
   /* Move note_list from the upper bb.  */
   gcc_assert (BB_NOTE_LIST (new_bb) == NULL_RTX);
   BB_NOTE_LIST (new_bb) = BB_NOTE_LIST (bb);
-  BB_NOTE_LIST (bb) = NULL_RTX;
+  BB_NOTE_LIST (bb) = NULL;
 
   gcc_assert (e2->dest == bb);
 
@@ -4577,7 +4586,7 @@ create_block_for_bookkeeping (edge e1, edge e2)
       if (DEBUG_INSN_P (insn)
          && single_succ_p (new_bb)
          && (succ = single_succ (new_bb))
-         && succ != EXIT_BLOCK_PTR
+         && succ != EXIT_BLOCK_PTR_FOR_FN (cfun)
          && DEBUG_INSN_P ((last = sel_bb_end (new_bb))))
        {
          while (insn != last && (DEBUG_INSN_P (insn) || NOTE_P (insn)))
@@ -4587,18 +4596,15 @@ create_block_for_bookkeeping (edge e1, edge e2)
            {
              sel_global_bb_info_def gbi;
              sel_region_bb_info_def rbi;
-             int i;
 
              if (sched_verbose >= 2)
                sel_print ("Swapping block ids %i and %i\n",
                           new_bb->index, succ->index);
 
-             i = new_bb->index;
-             new_bb->index = succ->index;
-             succ->index = i;
+             std::swap (new_bb->index, succ->index);
 
-             SET_BASIC_BLOCK (new_bb->index, new_bb);
-             SET_BASIC_BLOCK (succ->index, succ);
+             SET_BASIC_BLOCK_FOR_FN (cfun, new_bb->index, new_bb);
+             SET_BASIC_BLOCK_FOR_FN (cfun, succ->index, succ);
 
              memcpy (&gbi, SEL_GLOBAL_BB_INFO (new_bb), sizeof (gbi));
              memcpy (SEL_GLOBAL_BB_INFO (new_bb), SEL_GLOBAL_BB_INFO (succ),
@@ -4610,15 +4616,13 @@ create_block_for_bookkeeping (edge e1, edge e2)
                      sizeof (rbi));
              memcpy (SEL_REGION_BB_INFO (succ), &rbi, sizeof (rbi));
 
-             i = BLOCK_TO_BB (new_bb->index);
-             BLOCK_TO_BB (new_bb->index) = BLOCK_TO_BB (succ->index);
-             BLOCK_TO_BB (succ->index) = i;
+             std::swap (BLOCK_TO_BB (new_bb->index),
+                        BLOCK_TO_BB (succ->index));
 
-             i = CONTAINING_RGN (new_bb->index);
-             CONTAINING_RGN (new_bb->index) = CONTAINING_RGN (succ->index);
-             CONTAINING_RGN (succ->index) = i;
+             std::swap (CONTAINING_RGN (new_bb->index),
+                        CONTAINING_RGN (succ->index));
 
-             for (i = 0; i < current_nr_blocks; i++)
+             for (int i = 0; i < current_nr_blocks; i++)
                if (BB_TO_BLOCK (i) == succ->index)
                  BB_TO_BLOCK (i) = new_bb->index;
                else if (BB_TO_BLOCK (i) == new_bb->index)
@@ -4643,10 +4647,8 @@ create_block_for_bookkeeping (edge e1, edge e2)
                           CODE_LABEL_NUMBER (BB_HEAD (new_bb)),
                           CODE_LABEL_NUMBER (BB_HEAD (succ)));
 
-             i = CODE_LABEL_NUMBER (BB_HEAD (new_bb));
-             CODE_LABEL_NUMBER (BB_HEAD (new_bb))
-               = CODE_LABEL_NUMBER (BB_HEAD (succ));
-             CODE_LABEL_NUMBER (BB_HEAD (succ)) = i;
+             std::swap (CODE_LABEL_NUMBER (BB_HEAD (new_bb)),
+                        CODE_LABEL_NUMBER (BB_HEAD (succ)));
            }
        }
     }
@@ -4655,9 +4657,10 @@ create_block_for_bookkeeping (edge e1, edge e2)
 }
 
 /* Return insn after which we must insert bookkeeping code for path(s) incoming
-   into E2->dest, except from E1->src.  */
+   into E2->dest, except from E1->src.  If the returned insn immediately
+   precedes a fence, assign that fence to *FENCE_TO_REWIND.  */
 static insn_t
-find_place_for_bookkeeping (edge e1, edge e2)
+find_place_for_bookkeeping (edge e1, edge e2, fence_t *fence_to_rewind)
 {
   insn_t place_to_insert;
   /* Find a basic block that can hold bookkeeping.  If it can be found, do not
@@ -4674,7 +4677,7 @@ find_place_for_bookkeeping (edge e1, edge e2)
         removed already.  */
       if (DEBUG_INSN_P (place_to_insert))
        {
-         rtx insn = sel_bb_head (book_block);
+         rtx_insn *insn = sel_bb_head (book_block);
 
          while (insn != place_to_insert &&
                 (DEBUG_INSN_P (insn) || NOTE_P (insn)))
@@ -4699,9 +4702,14 @@ find_place_for_bookkeeping (edge e1, edge e2)
        sel_print ("Pre-existing bookkeeping block is %i\n", book_block->index);
     }
 
-  /* If basic block ends with a jump, insert bookkeeping code right before it.  */
+  *fence_to_rewind = NULL;
+  /* If basic block ends with a jump, insert bookkeeping code right before it.
+     Notice if we are crossing a fence when taking PREV_INSN.  */
   if (INSN_P (place_to_insert) && control_flow_insn_p (place_to_insert))
-    place_to_insert = PREV_INSN (place_to_insert);
+    {
+      *fence_to_rewind = flist_lookup (fences, place_to_insert);
+      place_to_insert = PREV_INSN (place_to_insert);
+    }
 
   return place_to_insert;
 }
@@ -4712,11 +4720,10 @@ static int
 find_seqno_for_bookkeeping (insn_t place_to_insert, insn_t join_point)
 {
   int seqno;
-  rtx next;
 
   /* Check if we are about to insert bookkeeping copy before a jump, and use
      jump's seqno for the copy; otherwise, use JOIN_POINT's seqno.  */
-  next = NEXT_INSN (place_to_insert);
+  rtx_insn *next = NEXT_INSN (place_to_insert);
   if (INSN_P (next)
       && JUMP_P (next)
       && BLOCK_FOR_INSN (next) == BLOCK_FOR_INSN (place_to_insert))
@@ -4751,7 +4758,7 @@ find_seqno_for_bookkeeping (insn_t place_to_insert, insn_t join_point)
 static insn_t
 emit_bookkeeping_insn (insn_t place_to_insert, expr_t c_expr, int new_seqno)
 {
-  rtx new_insn_rtx = create_copy_of_insn_rtx (EXPR_INSN_RTX (c_expr));
+  rtx_insn *new_insn_rtx = create_copy_of_insn_rtx (EXPR_INSN_RTX (c_expr));
 
   vinsn_t new_vinsn
     = create_vinsn_from_insn_rtx (new_insn_rtx,
@@ -4776,21 +4783,23 @@ generate_bookkeeping_insn (expr_t c_expr, edge e1, edge e2)
   insn_t join_point, place_to_insert, new_insn;
   int new_seqno;
   bool need_to_exchange_data_sets;
+  fence_t fence_to_rewind;
 
   if (sched_verbose >= 4)
     sel_print ("Generating bookkeeping insn (%d->%d)\n", e1->src->index,
               e2->dest->index);
 
   join_point = sel_bb_head (e2->dest);
-  place_to_insert = find_place_for_bookkeeping (e1, e2);
-  if (!place_to_insert)
-    return NULL;
+  place_to_insert = find_place_for_bookkeeping (e1, e2, &fence_to_rewind);
   new_seqno = find_seqno_for_bookkeeping (place_to_insert, join_point);
   need_to_exchange_data_sets
     = sel_bb_empty_p (BLOCK_FOR_INSN (place_to_insert));
 
   new_insn = emit_bookkeeping_insn (place_to_insert, c_expr, new_seqno);
 
+  if (fence_to_rewind)
+    FENCE_INSN (fence_to_rewind) = new_insn;
+
   /* When inserting bookkeeping insn in new block, av sets should be
      following: old basic block (that now holds bookkeeping) data sets are
      the same as was before generation of bookkeeping, and new basic block
@@ -4829,7 +4838,8 @@ remove_insns_that_need_bookkeeping (fence_t fence, av_set_t *av_ptr)
          && (EXPR_SPEC (expr)
              || !EXPR_ORIG_BB_INDEX (expr)
              || !dominated_by_p (CDI_DOMINATORS,
-                                 BASIC_BLOCK (EXPR_ORIG_BB_INDEX (expr)),
+                                 BASIC_BLOCK_FOR_FN (cfun,
+                                                     EXPR_ORIG_BB_INDEX (expr)),
                                  BLOCK_FOR_INSN (FENCE_INSN (fence)))))
        {
           if (sched_verbose >= 4)
@@ -4872,11 +4882,11 @@ remove_insns_that_need_bookkeeping (fence_t fence, av_set_t *av_ptr)
       ...
 */
 static void
-move_cond_jump (rtx insn, bnd_t bnd)
+move_cond_jump (rtx_insn *insn, bnd_t bnd)
 {
   edge ft_edge;
   basic_block block_from, block_next, block_new, block_bnd, bb;
-  rtx next, prev, link, head;
+  rtx_insn *next, *prev, *link, *head;
 
   block_from = BLOCK_FOR_INSN (insn);
   block_bnd = BLOCK_FOR_INSN (BND_TO (bnd));
@@ -4923,7 +4933,7 @@ move_cond_jump (rtx insn, bnd_t bnd)
   head = BB_HEAD (block_new);
   while (bb != block_from->next_bb)
     {
-      rtx from, to;
+      rtx_insn *from, *to;
       from = bb == block_bnd ? prev : sel_bb_head (bb);
       to = bb == block_from ? next : sel_bb_end (bb);
 
@@ -4975,16 +4985,15 @@ remove_temp_moveop_nops (bool full_tidying)
   int i;
   insn_t insn;
 
-  FOR_EACH_VEC_ELT (insn_t, vec_temp_moveop_nops, i, insn)
+  FOR_EACH_VEC_ELT (vec_temp_moveop_nops, i, insn)
     {
       gcc_assert (INSN_NOP_P (insn));
       return_nop_to_pool (insn, full_tidying);
     }
 
   /* Empty the vector.  */
-  if (VEC_length (insn_t, vec_temp_moveop_nops) > 0)
-    VEC_block_remove (insn_t, vec_temp_moveop_nops, 0,
-                     VEC_length (insn_t, vec_temp_moveop_nops));
+  if (vec_temp_moveop_nops.length () > 0)
+    vec_temp_moveop_nops.block_remove (0, vec_temp_moveop_nops.length ());
 }
 
 /* Records the maximal UID before moving up an instruction.  Used for
@@ -5135,24 +5144,24 @@ find_sequential_best_exprs (bnd_t bnd, expr_t expr_vliw, bool for_moveop)
 static void ATTRIBUTE_UNUSED
 move_nop_to_previous_block (insn_t nop, basic_block prev_bb)
 {
-  insn_t prev_insn, next_insn, note;
+  insn_t prev_insn, next_insn;
 
   gcc_assert (sel_bb_head_p (nop)
               && prev_bb == BLOCK_FOR_INSN (nop)->prev_bb);
-  note = bb_note (BLOCK_FOR_INSN (nop));
+  rtx_note *note = bb_note (BLOCK_FOR_INSN (nop));
   prev_insn = sel_bb_end (prev_bb);
   next_insn = NEXT_INSN (nop);
   gcc_assert (prev_insn != NULL_RTX
               && PREV_INSN (note) == prev_insn);
 
-  NEXT_INSN (prev_insn) = nop;
-  PREV_INSN (nop) = prev_insn;
+  SET_NEXT_INSN (prev_insn) = nop;
+  SET_PREV_INSN (nop) = prev_insn;
 
-  PREV_INSN (note) = nop;
-  NEXT_INSN (note) = next_insn;
+  SET_PREV_INSN (note) = nop;
+  SET_NEXT_INSN (note) = next_insn;
 
-  NEXT_INSN (nop) = note;
-  PREV_INSN (next_insn) = note;
+  SET_NEXT_INSN (nop) = note;
+  SET_PREV_INSN (next_insn) = note;
 
   BB_END (prev_bb) = nop;
   BLOCK_FOR_INSN (nop) = prev_bb;
@@ -5317,14 +5326,14 @@ update_fence_and_insn (fence_t fence, insn_t insn, int need_stall)
   /* First, reflect that something is scheduled on this fence.  */
   asm_p = advance_state_on_fence (fence, insn);
   FENCE_LAST_SCHEDULED_INSN (fence) = insn;
-  VEC_safe_push (rtx, gc, FENCE_EXECUTING_INSNS (fence), insn);
+  vec_safe_push (FENCE_EXECUTING_INSNS (fence), insn);
   if (SCHED_GROUP_P (insn))
     {
       FENCE_SCHED_NEXT (fence) = INSN_SCHED_NEXT (insn);
       SCHED_GROUP_P (insn) = 0;
     }
   else
-    FENCE_SCHED_NEXT (fence) = NULL_RTX;
+    FENCE_SCHED_NEXT (fence) = NULL;
   if (INSN_UID (insn) < FENCE_READY_TICKS_SIZE (fence))
     FENCE_READY_TICKS (fence) [INSN_UID (insn)] = 0;
 
@@ -5509,8 +5518,8 @@ fill_insns (fence_t fence, int seqno, ilist_t **scheduled_insns_tailpp)
     {
       blist_t *bnds_tailp1, *bndsp;
       expr_t expr_vliw;
-      int need_stall;
-      int was_stall = 0, scheduled_insns = 0, stall_iterations = 0;
+      int need_stall = false;
+      int was_stall = 0, scheduled_insns = 0;
       int max_insns = pipelining_p ? issue_rate : 2 * issue_rate;
       int max_stall = pipelining_p ? 1 : 3;
       bool last_insn_was_debug = false;
@@ -5529,16 +5538,15 @@ fill_insns (fence_t fence, int seqno, ilist_t **scheduled_insns_tailpp)
       do
         {
           expr_vliw = find_best_expr (&av_vliw, bnds, fence, &need_stall);
-          if (!expr_vliw && need_stall)
+          if (! expr_vliw && need_stall)
             {
               /* All expressions required a stall.  Do not recompute av sets
                  as we'll get the same answer (modulo the insns between
                  the fence and its boundary, which will not be available for
-                 pipelining).  */
-              gcc_assert (! expr_vliw && stall_iterations < 2);
-              was_stall++;
-             /* If we are going to stall for too long, break to recompute av
+                 pipelining).
+                If we are going to stall for too long, break to recompute av
                 sets and bring more insns for pipelining.  */
+              was_stall++;
              if (need_stall <= 3)
                stall_for_cycles (fence, need_stall);
              else
@@ -5659,7 +5667,7 @@ update_and_record_unavailable_insns (basic_block book_block)
   av_set_iterator i;
   av_set_t old_av_set = NULL;
   expr_t cur_expr;
-  rtx bb_end = sel_bb_end (book_block);
+  rtx_insn *bb_end = sel_bb_end (book_block);
 
   /* First, get correct liveness in the bookkeeping block.  The problem is
      the range between the bookeeping insn and the end of block.  */
@@ -5688,8 +5696,8 @@ update_and_record_unavailable_insns (basic_block book_block)
               || EXPR_TARGET_AVAILABLE (new_expr)
                 != EXPR_TARGET_AVAILABLE (cur_expr))
            /* Unfortunately, the below code could be also fired up on
-              separable insns.
-              FIXME: add an example of how this could happen.  */
+              separable insns, e.g. when moving insns through the new
+              speculation check as in PR 53701.  */
             vinsn_vec_add (&vec_bookkeeping_blocked_vinsns, cur_expr);
         }
 
@@ -5800,7 +5808,7 @@ move_op_after_merge_succs (cmpd_local_params_p lp, void *sparams)
 /* Track bookkeeping copies created, insns scheduled, and blocks for
    rescheduling when INSN is found by move_op.  */
 static void
-track_scheduled_insns_and_blocks (rtx insn)
+track_scheduled_insns_and_blocks (rtx_insn *insn)
 {
   /* Even if this insn can be a copy that will be removed during current move_op,
      we still need to count it as an originator.  */
@@ -5827,7 +5835,7 @@ track_scheduled_insns_and_blocks (rtx insn)
 /* Emit a register-register copy for INSN if needed.  Return true if
    emitted one.  PARAMS is the move_op static parameters.  */
 static bool
-maybe_emit_renaming_copy (rtx insn,
+maybe_emit_renaming_copy (rtx_insn *insn,
                           moveop_static_params_p params)
 {
   bool insn_emitted  = false;
@@ -5867,7 +5875,7 @@ maybe_emit_renaming_copy (rtx insn,
    Return true if we've  emitted one.  PARAMS is the move_op static
    parameters.  */
 static bool
-maybe_emit_speculative_check (rtx insn, expr_t expr,
+maybe_emit_speculative_check (rtx_insn *insn, expr_t expr,
                               moveop_static_params_p params)
 {
   bool insn_emitted = false;
@@ -5896,7 +5904,7 @@ maybe_emit_speculative_check (rtx insn, expr_t expr,
    insn such as renaming/speculation.  Return true if one of such
    transformations actually happened, and we have emitted this insn.  */
 static bool
-handle_emitting_transformations (rtx insn, expr_t expr,
+handle_emitting_transformations (rtx_insn *insn, expr_t expr,
                                  moveop_static_params_p params)
 {
   bool insn_emitted = false;
@@ -5912,7 +5920,7 @@ handle_emitting_transformations (rtx insn, expr_t expr,
    leave a NOP there till the return to fill_insns.  */
 
 static bool
-need_nop_to_preserve_insn_bb (rtx insn)
+need_nop_to_preserve_insn_bb (rtx_insn *insn)
 {
   insn_t bb_head, bb_end, bb_next, in_next;
   basic_block bb = BLOCK_FOR_INSN (insn);
@@ -5955,7 +5963,7 @@ need_nop_to_preserve_insn_bb (rtx insn)
 /* Remove INSN from stream.  When ONLY_DISCONNECT is true, its data
    is not removed but reused when INSN is re-emitted.  */
 static void
-remove_insn_from_stream (rtx insn, bool only_disconnect)
+remove_insn_from_stream (rtx_insn *insn, bool only_disconnect)
 {
   /* If there's only one insn in the BB, make sure that a nop is
      inserted into it, so the basic block won't disappear when we'll
@@ -5965,7 +5973,7 @@ remove_insn_from_stream (rtx insn, bool only_disconnect)
     {
       insn_t nop = get_nop_from_pool (insn);
       gcc_assert (INSN_NOP_P (nop));
-      VEC_safe_push (insn_t, heap, vec_temp_moveop_nops, nop);
+      vec_temp_moveop_nops.safe_push (nop);
     }
 
   sel_remove_insn (insn, only_disconnect, false);
@@ -5980,14 +5988,13 @@ move_op_orig_expr_found (insn_t insn, expr_t expr,
                          cmpd_local_params_p lparams ATTRIBUTE_UNUSED,
                          void *static_params)
 {
-  bool only_disconnect, insn_emitted;
+  bool only_disconnect;
   moveop_static_params_p params = (moveop_static_params_p) static_params;
 
   copy_expr_onside (params->c_expr, INSN_EXPR (insn));
   track_scheduled_insns_and_blocks (insn);
-  insn_emitted = handle_emitting_transformations (insn, expr, params);
-  only_disconnect = (params->uid == INSN_UID (insn)
-                     && ! insn_emitted  && ! EXPR_WAS_CHANGED (expr));
+  handle_emitting_transformations (insn, expr, params);
+  only_disconnect = params->uid == INSN_UID (insn);
 
   /* Mark that we've disconnected an insn.  */
   if (only_disconnect)
@@ -6304,7 +6311,7 @@ code_motion_process_successors (insn_t insn, av_set_t orig_ops,
 {
   int res = 0;
   succ_iterator succ_i;
-  rtx succ;
+  insn_t succ;
   basic_block bb;
   int old_index;
   unsigned old_succs;
@@ -6354,12 +6361,29 @@ code_motion_process_successors (insn_t insn, av_set_t orig_ops,
         res = b;
 
       /* We have simplified the control flow below this point.  In this case,
-         the iterator becomes invalid.  We need to try again.  */
+         the iterator becomes invalid.  We need to try again.
+        If we have removed the insn itself, it could be only an
+        unconditional jump.  Thus, do not rescan but break immediately --
+        we have already visited the only successor block.  */
+      if (!BLOCK_FOR_INSN (insn))
+       {
+         if (sched_verbose >= 6)
+           sel_print ("Not doing rescan: already visited the only successor"
+                      " of block %d\n", old_index);
+         break;
+       }
       if (BLOCK_FOR_INSN (insn)->index != old_index
           || EDGE_COUNT (bb->succs) != old_succs)
-        goto rescan;
+        {
+         if (sched_verbose >= 6)
+           sel_print ("Rescan: CFG was simplified below insn %d, block %d\n",
+                      INSN_UID (insn), BLOCK_FOR_INSN (insn)->index);
+          insn = sel_bb_end (BLOCK_FOR_INSN (insn));
+          goto rescan;
+        }
     }
 
+#ifdef ENABLE_CHECKING
   /* Here, RES==1 if original expr was found at least for one of the
      successors.  After the loop, RES may happen to have zero value
      only if at some point the expr searched is present in av_set, but is
@@ -6367,11 +6391,12 @@ code_motion_process_successors (insn_t insn, av_set_t orig_ops,
      The exception is when the original operation is blocked by
      bookkeeping generated for another fence or for another path in current
      move_op.  */
-  gcc_checking_assert (res == 1
-                      || (res == 0
-                          && av_set_could_be_blocked_by_bookkeeping_p (orig_ops,
-                                                                       static_params))
-                      || res == -1);
+  gcc_assert (res == 1
+             || (res == 0
+                 && av_set_could_be_blocked_by_bookkeeping_p (orig_ops,
+                                                              static_params))
+             || res == -1);
+#endif
 
   /* Merge data, clean up, etc.  */
   if (res != -1 && code_motion_path_driver_info->after_merge_succs)
@@ -6467,7 +6492,7 @@ code_motion_path_driver (insn_t insn, av_set_t orig_ops, ilist_t path,
 
   /* Filter the orig_ops set.  */
   if (AV_SET_VALID_P (insn))
-    av_set_intersect (&orig_ops, AV_SET (insn));
+    av_set_code_motion_filter (&orig_ops, AV_SET (insn));
 
   /* If no more original ops, return immediately.  */
   if (!orig_ops)
@@ -6573,21 +6598,37 @@ code_motion_path_driver (insn_t insn, av_set_t orig_ops, ilist_t path,
   if (!expr)
     {
       int res;
+      rtx_insn *last_insn = PREV_INSN (insn);
+      bool added_to_path;
 
       gcc_assert (insn == sel_bb_end (bb));
 
       /* Add bb tail to PATH (but it doesn't make any sense if it's a bb_head -
         it's already in PATH then).  */
       if (insn != first_insn)
-       ilist_add (&path, insn);
+       {
+         ilist_add (&path, insn);
+         added_to_path = true;
+       }
+      else
+        added_to_path = false;
 
       /* Process_successors should be able to find at least one
         successor for which code_motion_path_driver returns TRUE.  */
       res = code_motion_process_successors (insn, orig_ops,
                                             path, static_params);
 
+      /* Jump in the end of basic block could have been removed or replaced
+         during code_motion_process_successors, so recompute insn as the
+         last insn in bb.  */
+      if (NEXT_INSN (last_insn) != insn)
+        {
+          insn = sel_bb_end (bb);
+          first_insn = sel_bb_head (bb);
+        }
+
       /* Remove bb tail from path.  */
-      if (insn != first_insn)
+      if (added_to_path)
        ilist_remove (&path);
 
       if (res != 1)
@@ -6627,7 +6668,11 @@ code_motion_path_driver (insn_t insn, av_set_t orig_ops, ilist_t path,
      the numbering by creating bookkeeping blocks.  */
   if (removed_last_insn)
     insn = PREV_INSN (insn);
-  bitmap_set_bit (code_motion_visited_blocks, BLOCK_FOR_INSN (insn)->index);
+
+  /* If we have simplified the control flow and removed the first jump insn,
+     there's no point in marking this block in the visited blocks bitmap.  */
+  if (BLOCK_FOR_INSN (insn))
+    bitmap_set_bit (code_motion_visited_blocks, BLOCK_FOR_INSN (insn)->index);
   return true;
 }
 
@@ -6647,7 +6692,7 @@ move_op (insn_t insn, av_set_t orig_ops, expr_t expr_vliw,
 {
   struct moveop_static_params sparams;
   struct cmpd_local_params lparams;
-  bool res;
+  int res;
 
   /* Init params for code_motion_path_driver.  */
   sparams.dest = dest;
@@ -6666,6 +6711,8 @@ move_op (insn_t insn, av_set_t orig_ops, expr_t expr_vliw,
   code_motion_path_driver_info = &move_op_hooks;
   res = code_motion_path_driver (insn, orig_ops, NULL, &lparams, &sparams);
 
+  gcc_assert (res != -1);
+
   if (sparams.was_renamed)
     EXPR_WAS_RENAMED (expr_vliw) = true;
 
@@ -6687,11 +6734,12 @@ static void
 init_seqno_1 (basic_block bb, sbitmap visited_bbs, bitmap blocks_to_reschedule)
 {
   int bbi = BLOCK_TO_BB (bb->index);
-  insn_t insn, note = bb_note (bb);
+  insn_t insn;
   insn_t succ_insn;
   succ_iterator si;
 
-  SET_BIT (visited_bbs, bbi);
+  rtx_note *note = bb_note (bb);
+  bitmap_set_bit (visited_bbs, bbi);
   if (blocks_to_reschedule)
     bitmap_clear_bit (blocks_to_reschedule, bb->index);
 
@@ -6703,27 +6751,28 @@ init_seqno_1 (basic_block bb, sbitmap visited_bbs, bitmap blocks_to_reschedule)
 
       gcc_assert (in_current_region_p (succ));
 
-      if (!TEST_BIT (visited_bbs, succ_bbi))
+      if (!bitmap_bit_p (visited_bbs, succ_bbi))
        {
          gcc_assert (succ_bbi > bbi);
 
          init_seqno_1 (succ, visited_bbs, blocks_to_reschedule);
        }
+      else if (blocks_to_reschedule)
+        bitmap_set_bit (forced_ebb_heads, succ->index);
     }
 
   for (insn = BB_END (bb); insn != note; insn = PREV_INSN (insn))
     INSN_SEQNO (insn) = cur_seqno--;
 }
 
-/* Initialize seqnos for the current region.  NUMBER_OF_INSNS is the number
-   of instructions in the region, BLOCKS_TO_RESCHEDULE contains blocks on
-   which we're rescheduling when pipelining, FROM is the block where
+/* Initialize seqnos for the current region.  BLOCKS_TO_RESCHEDULE contains
+   blocks on which we're rescheduling when pipelining, FROM is the block where
    traversing region begins (it may not be the head of the region when
    pipelining, but the head of the loop instead).
 
    Returns the maximal seqno found.  */
 static int
-init_seqno (int number_of_insns, bitmap blocks_to_reschedule, basic_block from)
+init_seqno (bitmap blocks_to_reschedule, basic_block from)
 {
   sbitmap visited_bbs;
   bitmap_iterator bi;
@@ -6733,22 +6782,26 @@ init_seqno (int number_of_insns, bitmap blocks_to_reschedule, basic_block from)
 
   if (blocks_to_reschedule)
     {
-      sbitmap_ones (visited_bbs);
+      bitmap_ones (visited_bbs);
       EXECUTE_IF_SET_IN_BITMAP (blocks_to_reschedule, 0, bbi, bi)
         {
          gcc_assert (BLOCK_TO_BB (bbi) < current_nr_blocks);
-          RESET_BIT (visited_bbs, BLOCK_TO_BB (bbi));
+          bitmap_clear_bit (visited_bbs, BLOCK_TO_BB (bbi));
        }
     }
   else
     {
-      sbitmap_zero (visited_bbs);
+      bitmap_clear (visited_bbs);
       from = EBB_FIRST_BB (0);
     }
 
-  cur_seqno = number_of_insns > 0 ? number_of_insns : sched_max_luid - 1;
+  cur_seqno = sched_max_luid - 1;
   init_seqno_1 (from, visited_bbs, blocks_to_reschedule);
-  gcc_assert (cur_seqno == 0 || number_of_insns == 0);
+
+  /* cur_seqno may be positive if the number of instructions is less than
+     sched_max_luid - 1 (when rescheduling or if some instructions have been
+     removed by the call to purge_empty_blocks in sel_sched_region_1).  */
+  gcc_assert (cur_seqno >= 0);
 
   sbitmap_free (visited_bbs);
   return sched_max_luid - 1;
@@ -6762,7 +6815,8 @@ sel_setup_region_sched_flags (void)
   bookkeeping_p = 1;
   pipelining_p = (bookkeeping_p
                   && (flag_sel_sched_pipelining != 0)
-                 && current_loop_nest != NULL);
+                 && current_loop_nest != NULL
+                 && loop_has_exit_edges (current_loop_nest));
   max_insns_to_rename = PARAM_VALUE (PARAM_SELSCHED_INSNS_TO_RENAME);
   max_ws = MAX_WS;
 }
@@ -6773,7 +6827,7 @@ current_region_empty_p (void)
 {
   int i;
   for (i = 0; i < current_nr_blocks; i++)
-    if (! sel_bb_empty_p (BASIC_BLOCK (BB_TO_BLOCK (i))))
+    if (! sel_bb_empty_p (BASIC_BLOCK_FOR_FN (cfun, BB_TO_BLOCK (i))))
       return false;
 
   return true;
@@ -6781,7 +6835,7 @@ current_region_empty_p (void)
 
 /* Prepare and verify loop nest for pipelining.  */
 static void
-setup_current_loop_nest (int rgn)
+setup_current_loop_nest (int rgn, bb_vec_t *bbs)
 {
   current_loop_nest = get_loop_nest_for_rgn (rgn);
 
@@ -6790,7 +6844,7 @@ setup_current_loop_nest (int rgn)
 
   /* If this loop has any saved loop preheaders from nested loops,
      add these basic blocks to the current region.  */
-  sel_add_loop_preheaders ();
+  sel_add_loop_preheaders (bbs);
 
   /* Check that we're starting with a valid information.  */
   gcc_assert (loop_latch_edge (current_loop_nest));
@@ -6829,27 +6883,27 @@ sel_region_init (int rgn)
   if (current_region_empty_p ())
     return true;
 
-  if (flag_sel_sched_pipelining)
-    setup_current_loop_nest (rgn);
+  bbs.create (current_nr_blocks);
 
-  sel_setup_region_sched_flags ();
+  for (i = 0; i < current_nr_blocks; i++)
+    bbs.quick_push (BASIC_BLOCK_FOR_FN (cfun, BB_TO_BLOCK (i)));
 
-  bbs = VEC_alloc (basic_block, heap, current_nr_blocks);
+  sel_init_bbs (bbs);
 
-  for (i = 0; i < current_nr_blocks; i++)
-    VEC_quick_push (basic_block, bbs, BASIC_BLOCK (BB_TO_BLOCK (i)));
+  if (flag_sel_sched_pipelining)
+    setup_current_loop_nest (rgn, &bbs);
 
-  sel_init_bbs (bbs, NULL);
+  sel_setup_region_sched_flags ();
 
   /* Initialize luids and dependence analysis which both sel-sched and haifa
      need.  */
-  sched_init_luids (bbs, NULL, NULL, NULL);
+  sched_init_luids (bbs);
   sched_deps_init (false);
 
   /* Initialize haifa data.  */
   rgn_setup_sched_infos ();
   sel_set_sched_flags ();
-  haifa_init_h_i_d (bbs, NULL, NULL, NULL);
+  haifa_init_h_i_d (bbs);
 
   sel_compute_priorities (rgn);
   init_deps_global ();
@@ -6858,7 +6912,7 @@ sel_region_init (int rgn)
   sel_setup_sched_infos ();
   sel_init_global_and_expr (bbs);
 
-  VEC_free (basic_block, heap, bbs);
+  bbs.release ();
 
   blocks_to_reschedule = BITMAP_ALLOC (NULL);
 
@@ -6867,13 +6921,14 @@ sel_region_init (int rgn)
      compute_live for the first insn of the loop.  */
   if (current_loop_nest)
     {
-      int header = (sel_is_loop_preheader_p (BASIC_BLOCK (BB_TO_BLOCK (0)))
-                    ? 1
-                    : 0);
+      int header =
+       (sel_is_loop_preheader_p (BASIC_BLOCK_FOR_FN (cfun, BB_TO_BLOCK (0)))
+        ? 1
+        : 0);
 
       if (current_nr_blocks == header + 1)
         update_liveness_on_insn
-          (sel_bb_head (BASIC_BLOCK (BB_TO_BLOCK (header))));
+          (sel_bb_head (BASIC_BLOCK_FOR_FN (cfun, BB_TO_BLOCK (header))));
     }
 
   /* Set hooks so that no newly generated insn will go out unnoticed.  */
@@ -6911,8 +6966,8 @@ simplify_changed_insns (void)
 
   for (i = 0; i < current_nr_blocks; i++)
     {
-      basic_block bb = BASIC_BLOCK (BB_TO_BLOCK (i));
-      rtx insn;
+      basic_block bb = BASIC_BLOCK_FOR_FN (cfun, BB_TO_BLOCK (i));
+      rtx_insn *insn;
 
       FOR_BB_INSNS (bb, insn)
        if (INSN_P (insn))
@@ -6931,7 +6986,7 @@ simplify_changed_insns (void)
 static void
 find_ebb_boundaries (basic_block bb, bitmap scheduled_blocks)
 {
-  insn_t head, tail;
+  rtx_insn *head, *tail;
   basic_block bb1 = bb;
   if (sched_verbose >= 2)
     sel_print ("Finishing schedule in bbs: ");
@@ -6963,6 +7018,7 @@ reset_sched_cycles_in_current_ebb (void)
   int last_clock = 0;
   int haifa_last_clock = -1;
   int haifa_clock = 0;
+  int issued_insns = 0;
   insn_t insn;
 
   if (targetm.sched.init)
@@ -6981,7 +7037,7 @@ reset_sched_cycles_in_current_ebb (void)
     {
       int cost, haifa_cost;
       int sort_p;
-      bool asm_p, real_insn, after_stall;
+      bool asm_p, real_insn, after_stall, all_issued;
       int clock;
 
       if (!INSN_P (insn))
@@ -7017,7 +7073,9 @@ reset_sched_cycles_in_current_ebb (void)
           haifa_cost = cost;
           after_stall = 1;
         }
-
+      all_issued = issued_insns == issue_rate;
+      if (haifa_cost == 0 && all_issued)
+       haifa_cost = 1;
       if (haifa_cost > 0)
        {
          int i = 0;
@@ -7025,6 +7083,7 @@ reset_sched_cycles_in_current_ebb (void)
          while (haifa_cost--)
            {
              advance_state (curr_state);
+             issued_insns = 0;
               i++;
 
              if (sched_verbose >= 2)
@@ -7041,9 +7100,22 @@ reset_sched_cycles_in_current_ebb (void)
                   && haifa_cost > 0
                   && estimate_insn_cost (insn, curr_state) == 0)
                 break;
-           }
+
+              /* When the data dependency stall is longer than the DFA stall,
+                 and when we have issued exactly issue_rate insns and stalled,
+                 it could be that after this longer stall the insn will again
+                 become unavailable  to the DFA restrictions.  Looks strange
+                 but happens e.g. on x86-64.  So recheck DFA on the last
+                 iteration.  */
+              if ((after_stall || all_issued)
+                  && real_insn
+                  && haifa_cost == 0)
+                haifa_cost = estimate_insn_cost (insn, curr_state);
+            }
 
          haifa_clock += i;
+          if (sched_verbose >= 2)
+            sel_print ("haifa clock: %d\n", haifa_clock);
        }
       else
        gcc_assert (haifa_cost == 0);
@@ -7057,21 +7129,34 @@ reset_sched_cycles_in_current_ebb (void)
                                            &sort_p))
          {
            advance_state (curr_state);
+           issued_insns = 0;
            haifa_clock++;
            if (sched_verbose >= 2)
               {
                 sel_print ("advance_state (dfa_new_cycle)\n");
                 debug_state (curr_state);
+               sel_print ("haifa clock: %d\n", haifa_clock + 1);
               }
           }
 
       if (real_insn)
        {
+         static state_t temp = NULL;
+
+         if (!temp)
+           temp = xmalloc (dfa_state_size);
+         memcpy (temp, curr_state, dfa_state_size);
+
          cost = state_transition (curr_state, insn);
+         if (memcmp (temp, curr_state, dfa_state_size))
+           issued_insns++;
 
           if (sched_verbose >= 2)
-            debug_state (curr_state);
-
+           {
+             sel_print ("scheduled insn %d, clock %d\n", INSN_UID (insn),
+                        haifa_clock + 1);
+              debug_state (curr_state);
+           }
          gcc_assert (cost < 0);
        }
 
@@ -7158,7 +7243,7 @@ sel_region_target_finish (bool reset_sched_cycles_p)
 
          /* Extend luids so that insns generated by the target will
             get zero luid.  */
-         sched_init_luids (NULL, NULL, NULL, NULL);
+         sched_extend_luids ();
        }
     }
 
@@ -7176,13 +7261,12 @@ sel_region_finish (bool reset_sched_cycles_p)
   free_nop_pool ();
 
   /* Free the vectors.  */
-  if (vec_av_set)
-    VEC_free (expr_t, heap, vec_av_set);
+  vec_av_set.release ();
   BITMAP_FREE (current_copies);
   BITMAP_FREE (current_originators);
   BITMAP_FREE (code_motion_visited_blocks);
-  vinsn_vec_free (&vec_bookkeeping_blocked_vinsns);
-  vinsn_vec_free (&vec_target_unavailable_vinsns);
+  vinsn_vec_free (vec_bookkeeping_blocked_vinsns);
+  vinsn_vec_free (vec_target_unavailable_vinsns);
 
   /* If LV_SET of the region head should be updated, do it now because
      there will be no other chance.  */
@@ -7212,6 +7296,7 @@ sel_region_finish (bool reset_sched_cycles_p)
 
   finish_deps_global ();
   sched_finish_luids ();
+  h_d_i_d.release ();
 
   sel_finish_bbs ();
   BITMAP_FREE (blocks_to_reschedule);
@@ -7307,12 +7392,13 @@ find_min_max_seqno (flist_t fences, int *min_seqno, int *max_seqno)
     }
 }
 
-/* Calculate new fences from FENCES.  */
+/* Calculate new fences from FENCES.  Write the current time to PTIME.  */
 static flist_t
-calculate_new_fences (flist_t fences, int orig_max_seqno)
+calculate_new_fences (flist_t fences, int orig_max_seqno, int *ptime)
 {
   flist_t old_fences = fences;
   struct flist_tail_def _new_fences, *new_fences = &_new_fences;
+  int max_time = 0;
 
   flist_tail_init (new_fences);
   for (; fences; fences = FLIST_NEXT (fences))
@@ -7341,9 +7427,11 @@ calculate_new_fences (flist_t fences, int orig_max_seqno)
         }
       else
         extract_new_fences_from (fences, new_fences, orig_max_seqno);
+      max_time = MAX (max_time, FENCE_CYCLE (fence));
     }
 
   flist_clear (&old_fences);
+  *ptime = max_time;
   return FLIST_TAIL_HEAD (new_fences);
 }
 
@@ -7398,6 +7486,7 @@ static void
 sel_sched_region_2 (int orig_max_seqno)
 {
   int highest_seqno_in_use = orig_max_seqno;
+  int max_time = 0;
 
   stat_bookkeeping_copies = 0;
   stat_insns_needed_bookkeeping = 0;
@@ -7413,19 +7502,22 @@ sel_sched_region_2 (int orig_max_seqno)
 
       find_min_max_seqno (fences, &min_seqno, &max_seqno);
       schedule_on_fences (fences, max_seqno, &scheduled_insns_tailp);
-      fences = calculate_new_fences (fences, orig_max_seqno);
+      fences = calculate_new_fences (fences, orig_max_seqno, &max_time);
       highest_seqno_in_use = update_seqnos_and_stage (min_seqno, max_seqno,
                                                       highest_seqno_in_use,
                                                       &scheduled_insns);
     }
 
   if (sched_verbose >= 1)
-    sel_print ("Scheduled %d bookkeeping copies, %d insns needed "
-               "bookkeeping, %d insns renamed, %d insns substituted\n",
-               stat_bookkeeping_copies,
-               stat_insns_needed_bookkeeping,
-               stat_renamed_scheduled,
-               stat_substitutions_total);
+    {
+      sel_print ("Total scheduling time: %d cycles\n", max_time);
+      sel_print ("Scheduled %d bookkeeping copies, %d insns needed "
+                "bookkeeping, %d insns renamed, %d insns substituted\n",
+                stat_bookkeeping_copies,
+                stat_insns_needed_bookkeeping,
+                stat_renamed_scheduled,
+                stat_substitutions_total);
+    }
 }
 
 /* Schedule a region.  When pipelining, search for possibly never scheduled
@@ -7434,17 +7526,12 @@ sel_sched_region_2 (int orig_max_seqno)
 static void
 sel_sched_region_1 (void)
 {
-  int number_of_insns;
   int orig_max_seqno;
 
-  /* Remove empty blocks that might be in the region from the beginning.
-     We need to do save sched_max_luid before that, as it actually shows
-     the number of insns in the region, and purge_empty_blocks can
-     alter it.  */
-  number_of_insns = sched_max_luid - 1;
+  /* Remove empty blocks that might be in the region from the beginning.  */
   purge_empty_blocks ();
 
-  orig_max_seqno = init_seqno (number_of_insns, NULL, NULL);
+  orig_max_seqno = init_seqno (NULL, NULL);
   gcc_assert (orig_max_seqno >= 1);
 
   /* When pipelining outer loops, create fences on the loop header,
@@ -7484,21 +7571,23 @@ sel_sched_region_1 (void)
             {
               basic_block bb = EBB_FIRST_BB (i);
 
-              if (sel_bb_empty_p (bb))
-                {
-                  bitmap_clear_bit (blocks_to_reschedule, bb->index);
-                  continue;
-                }
-
               if (bitmap_bit_p (blocks_to_reschedule, bb->index))
                 {
+                  if (! bb_ends_ebb_p (bb))
+                    bitmap_set_bit (blocks_to_reschedule, bb_next_bb (bb)->index);
+                  if (sel_bb_empty_p (bb))
+                    {
+                      bitmap_clear_bit (blocks_to_reschedule, bb->index);
+                      continue;
+                    }
                   clear_outdated_rtx_info (bb);
                   if (sel_insn_is_speculation_check (BB_END (bb))
                       && JUMP_P (BB_END (bb)))
                     bitmap_set_bit (blocks_to_reschedule,
                                     BRANCH_EDGE (bb)->dest->index);
                 }
-              else if (INSN_SCHED_TIMES (sel_bb_head (bb)) <= 0)
+              else if (! sel_bb_empty_p (bb)
+                       && INSN_SCHED_TIMES (sel_bb_head (bb)) <= 0)
                 bitmap_set_bit (blocks_to_reschedule, bb->index);
             }
 
@@ -7515,11 +7604,11 @@ sel_sched_region_1 (void)
                   continue;
                 }
 
-              if (bitmap_clear_bit (blocks_to_reschedule, bb->index))
+              if (bitmap_bit_p (blocks_to_reschedule, bb->index))
                 {
                   flist_tail_init (new_fences);
 
-                  orig_max_seqno = init_seqno (0, blocks_to_reschedule, bb);
+                  orig_max_seqno = init_seqno (blocks_to_reschedule, bb);
 
                   /* Mark BB as head of the new ebb.  */
                   bitmap_set_bit (forced_ebb_heads, bb->index);
@@ -7625,7 +7714,7 @@ run_selective_scheduling (void)
 {
   int rgn;
 
-  if (n_basic_blocks == NUM_FIXED_BLOCKS)
+  if (n_basic_blocks_for_fn (cfun) == NUM_FIXED_BLOCKS)
     return;
 
   sel_global_init ();