OSDN Git Service

Backported from mainline
[pf3gnuchains/gcc-fork.git] / gcc / haifa-sched.c
index 2b5130c..da0dd76 100644 (file)
@@ -1,6 +1,6 @@
 /* Instruction scheduling pass.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
    Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by,
    and currently maintained by, Jim Wilson (wilson@cygnus.com)
@@ -128,25 +128,28 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
+#include "hard-reg-set.h"
 #include "rtl.h"
 #include "tm_p.h"
-#include "hard-reg-set.h"
 #include "regs.h"
 #include "function.h"
 #include "flags.h"
 #include "insn-config.h"
 #include "insn-attr.h"
 #include "except.h"
-#include "toplev.h"
 #include "recog.h"
 #include "sched-int.h"
 #include "target.h"
+#include "common/common-target.h"
 #include "output.h"
 #include "params.h"
 #include "vecprim.h"
 #include "dbgcnt.h"
 #include "cfgloop.h"
+#include "ira.h"
+#include "emit-rtl.h"  /* FIXME: Can go away once crtl is moved to rtl.h.  */
+#include "hashtab.h"
 
 #ifdef INSN_SCHEDULING
 
@@ -156,6 +159,35 @@ along with GCC; see the file COPYING3.  If not see
 
 int issue_rate;
 
+/* This can be set to true by a backend if the scheduler should not
+   enable a DCE pass.  */
+bool sched_no_dce;
+
+/* The current initiation interval used when modulo scheduling.  */
+static int modulo_ii;
+
+/* The maximum number of stages we are prepared to handle.  */
+static int modulo_max_stages;
+
+/* The number of insns that exist in each iteration of the loop.  We use this
+   to detect when we've scheduled all insns from the first iteration.  */
+static int modulo_n_insns;
+
+/* The current count of insns in the first iteration of the loop that have
+   already been scheduled.  */
+static int modulo_insns_scheduled;
+
+/* The maximum uid of insns from the first iteration of the loop.  */
+static int modulo_iter0_max_uid;
+
+/* The number of times we should attempt to backtrack when modulo scheduling.
+   Decreased each time we have to backtrack.  */
+static int modulo_backtracks_left;
+
+/* The stage in which the last insn from the original loop was
+   scheduled.  */
+static int modulo_last_stage;
+
 /* sched-verbose controls the amount of debugging output the
    scheduler prints.  It is controlled by -fsched-verbose=N:
    N>0 and no -DSR : the output is directed to stderr.
@@ -165,31 +197,23 @@ int issue_rate;
    N=3: rtl at abort point, control-flow, regions info.
    N=5: dependences info.  */
 
-static int sched_verbose_param = 0;
 int sched_verbose = 0;
 
 /* Debugging file.  All printouts are sent to dump, which is always set,
    either to stderr, or to the dump listing file (-dRS).  */
 FILE *sched_dump = 0;
 
-/* fix_sched_param() is called from toplev.c upon detection
-   of the -fsched-verbose=N option.  */
-
-void
-fix_sched_param (const char *param, const char *val)
-{
-  if (!strcmp (param, "verbose"))
-    sched_verbose_param = atoi (val);
-  else
-    warning (0, "fix_sched_param: unknown param: %s", param);
-}
-
-/* This is a placeholder for the scheduler parameters common 
+/* This is a placeholder for the scheduler parameters common
    to all schedulers.  */
 struct common_sched_info_def *common_sched_info;
 
 #define INSN_TICK(INSN)        (HID (INSN)->tick)
+#define INSN_EXACT_TICK(INSN) (HID (INSN)->exact_tick)
+#define INSN_TICK_ESTIMATE(INSN) (HID (INSN)->tick_estimate)
 #define INTER_TICK(INSN) (HID (INSN)->inter_tick)
+#define FEEDS_BACKTRACK_INSN(INSN) (HID (INSN)->feeds_backtrack_insn)
+#define SHADOW_P(INSN) (HID (INSN)->shadow_p)
+#define MUST_RECOMPUTE_SPEC_P(INSN) (HID (INSN)->must_recompute_spec)
 
 /* If INSN_TICK of an instruction is equal to INVALID_TICK,
    then it should be recalculated from scratch.  */
@@ -197,10 +221,6 @@ struct common_sched_info_def *common_sched_info;
 /* The minimal value of the INSN_TICK of an instruction.  */
 #define MIN_TICK (-max_insn_queue_index)
 
-/* Issue points are used to distinguish between instructions in max_issue ().
-   For now, all instructions are equally good.  */
-#define ISSUE_POINTS(INSN) 1
-
 /* List of important notes we must keep around.  This is a pointer to the
    last element in the list.  */
 rtx note_list;
@@ -294,7 +314,7 @@ static int q_size = 0;
    queue or ready list.
    QUEUE_READY     - INSN is in ready list.
    N >= 0 - INSN queued for X [where NEXT_Q_AFTER (q_ptr, X) == N] cycles.  */
-   
+
 #define QUEUE_INDEX(INSN) (HID (INSN)->queue_index)
 
 /* The following variable value refers for all current and future
@@ -310,7 +330,7 @@ size_t dfa_state_size;
 char *ready_try = NULL;
 
 /* The ready list.  */
-struct ready_list ready = {NULL, 0, 0, 0};
+struct ready_list ready = {NULL, 0, 0, 0, 0};
 
 /* The pointer to the ready list (to be removed).  */
 static struct ready_list *readyp = &ready;
@@ -318,6 +338,22 @@ static struct ready_list *readyp = &ready;
 /* Scheduling clock.  */
 static int clock_var;
 
+/* Clock at which the previous instruction was issued.  */
+static int last_clock_var;
+
+/* Set to true if, when queuing a shadow insn, we discover that it would be
+   scheduled too late.  */
+static bool must_backtrack;
+
+/* The following variable value is number of essential insns issued on
+   the current cycle.  An insn is essential one if it changes the
+   processors state.  */
+int cycle_issued_insns;
+
+/* This records the actual schedule.  It is built up during the main phase
+   of schedule_block, and afterwards used to reorder the insns in the RTL.  */
+static VEC(rtx, heap) *scheduled_insns;
+
 static int may_trap_exp (const_rtx, int);
 
 /* Nonzero iff the address is comprised from at most 1 register.  */
@@ -335,7 +371,7 @@ static int may_trap_exp (const_rtx, int);
 static int haifa_luid_for_non_insn (rtx x);
 
 /* Haifa version of sched_info hooks common to all headers.  */
-const struct common_sched_info_def haifa_common_sched_info = 
+const struct common_sched_info_def haifa_common_sched_info =
   {
     NULL, /* fix_recovery_cfg */
     NULL, /* add_block */
@@ -344,8 +380,6 @@ const struct common_sched_info_def haifa_common_sched_info =
     SCHED_PASS_UNKNOWN /* sched_pass_id */
   };
 
-const struct sched_scan_info_def *sched_scan_info;
-
 /* Mapping from instruction UID to its Logical UID.  */
 VEC (int, heap) *sched_luids = NULL;
 
@@ -499,16 +533,268 @@ haifa_classify_insn (const_rtx insn)
 {
   return haifa_classify_rtx (PATTERN (insn));
 }
+\f
+/* After the scheduler initialization function has been called, this function
+   can be called to enable modulo scheduling.  II is the initiation interval
+   we should use, it affects the delays for delay_pairs that were recorded as
+   separated by a given number of stages.
+
+   MAX_STAGES provides us with a limit
+   after which we give up scheduling; the caller must have unrolled at least
+   as many copies of the loop body and recorded delay_pairs for them.
+   
+   INSNS is the number of real (non-debug) insns in one iteration of
+   the loop.  MAX_UID can be used to test whether an insn belongs to
+   the first iteration of the loop; all of them have a uid lower than
+   MAX_UID.  */
+void
+set_modulo_params (int ii, int max_stages, int insns, int max_uid)
+{
+  modulo_ii = ii;
+  modulo_max_stages = max_stages;
+  modulo_n_insns = insns;
+  modulo_iter0_max_uid = max_uid;
+  modulo_backtracks_left = PARAM_VALUE (PARAM_MAX_MODULO_BACKTRACK_ATTEMPTS);
+}
+
+/* A structure to record a pair of insns where the first one is a real
+   insn that has delay slots, and the second is its delayed shadow.
+   I1 is scheduled normally and will emit an assembly instruction,
+   while I2 describes the side effect that takes place at the
+   transition between cycles CYCLES and (CYCLES + 1) after I1.  */
+struct delay_pair
+{
+  struct delay_pair *next_same_i1;
+  rtx i1, i2;
+  int cycles;
+  /* When doing modulo scheduling, we a delay_pair can also be used to
+     show that I1 and I2 are the same insn in a different stage.  If that
+     is the case, STAGES will be nonzero.  */
+  int stages;
+};
+
+/* Two hash tables to record delay_pairs, one indexed by I1 and the other
+   indexed by I2.  */
+static htab_t delay_htab;
+static htab_t delay_htab_i2;
+
+/* Called through htab_traverse.  Walk the hashtable using I2 as
+   index, and delete all elements involving an UID higher than
+   that pointed to by *DATA.  */
+static int
+htab_i2_traverse (void **slot, void *data)
+{
+  int maxuid = *(int *)data;
+  struct delay_pair *p = *(struct delay_pair **)slot;
+  if (INSN_UID (p->i2) >= maxuid || INSN_UID (p->i1) >= maxuid)
+    {
+      htab_clear_slot (delay_htab_i2, slot);
+    }
+  return 1;
+}
+
+/* Called through htab_traverse.  Walk the hashtable using I2 as
+   index, and delete all elements involving an UID higher than
+   that pointed to by *DATA.  */
+static int
+htab_i1_traverse (void **slot, void *data)
+{
+  int maxuid = *(int *)data;
+  struct delay_pair **pslot = (struct delay_pair **)slot;
+  struct delay_pair *p, *first, **pprev;
+
+  if (INSN_UID ((*pslot)->i1) >= maxuid)
+    {
+      htab_clear_slot (delay_htab, slot);
+      return 1;
+    }
+  pprev = &first;
+  for (p = *pslot; p; p = p->next_same_i1)
+    {
+      if (INSN_UID (p->i2) < maxuid)
+       {
+         *pprev = p;
+         pprev = &p->next_same_i1;
+       }
+    }
+  *pprev = NULL;
+  if (first == NULL)
+    htab_clear_slot (delay_htab, slot);
+  else
+    *pslot = first;
+  return 1;
+}
+
+/* Discard all delay pairs which involve an insn with an UID higher
+   than MAX_UID.  */
+void
+discard_delay_pairs_above (int max_uid)
+{
+  htab_traverse (delay_htab, htab_i1_traverse, &max_uid);
+  htab_traverse (delay_htab_i2, htab_i2_traverse, &max_uid);
+}
 
+/* Returns a hash value for X (which really is a delay_pair), based on
+   hashing just I1.  */
+static hashval_t
+delay_hash_i1 (const void *x)
+{
+  return htab_hash_pointer (((const struct delay_pair *) x)->i1);
+}
+
+/* Returns a hash value for X (which really is a delay_pair), based on
+   hashing just I2.  */
+static hashval_t
+delay_hash_i2 (const void *x)
+{
+  return htab_hash_pointer (((const struct delay_pair *) x)->i2);
+}
+
+/* Return nonzero if I1 of pair X is the same as that of pair Y.  */
+static int
+delay_i1_eq (const void *x, const void *y)
+{
+  return ((const struct delay_pair *) x)->i1 == y;
+}
+
+/* Return nonzero if I2 of pair X is the same as that of pair Y.  */
+static int
+delay_i2_eq (const void *x, const void *y)
+{
+  return ((const struct delay_pair *) x)->i2 == y;
+}
+
+/* This function can be called by a port just before it starts the final
+   scheduling pass.  It records the fact that an instruction with delay
+   slots has been split into two insns, I1 and I2.  The first one will be
+   scheduled normally and initiates the operation.  The second one is a
+   shadow which must follow a specific number of cycles after I1; its only
+   purpose is to show the side effect that occurs at that cycle in the RTL.
+   If a JUMP_INSN or a CALL_INSN has been split, I1 should be a normal INSN,
+   while I2 retains the original insn type.
+
+   There are two ways in which the number of cycles can be specified,
+   involving the CYCLES and STAGES arguments to this function.  If STAGES
+   is zero, we just use the value of CYCLES.  Otherwise, STAGES is a factor
+   which is multiplied by MODULO_II to give the number of cycles.  This is
+   only useful if the caller also calls set_modulo_params to enable modulo
+   scheduling.  */
+
+void
+record_delay_slot_pair (rtx i1, rtx i2, int cycles, int stages)
+{
+  struct delay_pair *p = XNEW (struct delay_pair);
+  struct delay_pair **slot;
+
+  p->i1 = i1;
+  p->i2 = i2;
+  p->cycles = cycles;
+  p->stages = stages;
+
+  if (!delay_htab)
+    {
+      delay_htab = htab_create (10, delay_hash_i1, delay_i1_eq, NULL);
+      delay_htab_i2 = htab_create (10, delay_hash_i2, delay_i2_eq, free);
+    }
+  slot = ((struct delay_pair **)
+         htab_find_slot_with_hash (delay_htab, i1, htab_hash_pointer (i1),
+                                   INSERT));
+  p->next_same_i1 = *slot;
+  *slot = p;
+  slot = ((struct delay_pair **)
+         htab_find_slot_with_hash (delay_htab_i2, i2, htab_hash_pointer (i2),
+                                   INSERT));
+  *slot = p;
+}
+
+/* Examine the delay pair hashtable to see if INSN is a shadow for another,
+   and return the other insn if so.  Return NULL otherwise.  */
+rtx
+real_insn_for_shadow (rtx insn)
+{
+  struct delay_pair *pair;
+
+  if (delay_htab == NULL)
+    return NULL_RTX;
+
+  pair
+    = (struct delay_pair *)htab_find_with_hash (delay_htab_i2, insn,
+                                               htab_hash_pointer (insn));
+  if (!pair || pair->stages > 0)
+    return NULL_RTX;
+  return pair->i1;
+}
+
+/* For a pair P of insns, return the fixed distance in cycles from the first
+   insn after which the second must be scheduled.  */
+static int
+pair_delay (struct delay_pair *p)
+{
+  if (p->stages == 0)
+    return p->cycles;
+  else
+    return p->stages * modulo_ii;
+}
+
+/* Given an insn INSN, add a dependence on its delayed shadow if it
+   has one.  Also try to find situations where shadows depend on each other
+   and add dependencies to the real insns to limit the amount of backtracking
+   needed.  */
+void
+add_delay_dependencies (rtx insn)
+{
+  struct delay_pair *pair;
+  sd_iterator_def sd_it;
+  dep_t dep;
+
+  if (!delay_htab)
+    return;
+
+  pair
+    = (struct delay_pair *)htab_find_with_hash (delay_htab_i2, insn,
+                                               htab_hash_pointer (insn));
+  if (!pair)
+    return;
+  add_dependence (insn, pair->i1, REG_DEP_ANTI);
+  if (pair->stages)
+    return;
+
+  FOR_EACH_DEP (pair->i2, SD_LIST_BACK, sd_it, dep)
+    {
+      rtx pro = DEP_PRO (dep);
+      struct delay_pair *other_pair
+       = (struct delay_pair *)htab_find_with_hash (delay_htab_i2, pro,
+                                                   htab_hash_pointer (pro));
+      if (!other_pair || other_pair->stages)
+       continue;
+      if (pair_delay (other_pair) >= pair_delay (pair))
+       {
+         if (sched_verbose >= 4)
+           {
+             fprintf (sched_dump, ";;\tadding dependence %d <- %d\n",
+                      INSN_UID (other_pair->i1),
+                      INSN_UID (pair->i1));
+             fprintf (sched_dump, ";;\tpair1 %d <- %d, cost %d\n",
+                      INSN_UID (pair->i1),
+                      INSN_UID (pair->i2),
+                      pair_delay (pair));
+             fprintf (sched_dump, ";;\tpair2 %d <- %d, cost %d\n",
+                      INSN_UID (other_pair->i1),
+                      INSN_UID (other_pair->i2),
+                      pair_delay (other_pair));
+           }
+         add_dependence (pair->i1, other_pair->i1, REG_DEP_ANTI);
+       }
+    }
+}
+\f
 /* Forward declarations.  */
 
 static int priority (rtx);
 static int rank_for_schedule (const void *, const void *);
 static void swap_sort (rtx *, int);
-static void queue_insn (rtx, int);
+static void queue_insn (rtx, int, const char *);
 static int schedule_insn (rtx);
-static int find_set_reg_weight (const_rtx);
-static void find_insn_reg_weight (const_rtx);
 static void adjust_priority (rtx);
 static void advance_one_cycle (void);
 static void extend_h_i_d (void);
@@ -532,6 +818,7 @@ static void extend_h_i_d (void);
 
 static void ready_add (struct ready_list *, rtx, bool);
 static rtx ready_remove_first (struct ready_list *);
+static rtx ready_remove_first_dispatch (struct ready_list *ready);
 
 static void queue_to_ready (struct ready_list *);
 static int early_queue_to_ready (state_t, struct ready_list *);
@@ -543,8 +830,6 @@ static void debug_ready_list (struct ready_list *);
 static rtx ready_remove (struct ready_list *, int);
 static void ready_remove_insn (rtx);
 
-static int choose_ready (struct ready_list *, rtx *);
-
 static void fix_inter_tick (rtx, rtx);
 static int fix_tick_ready (rtx);
 static void change_queue_index (rtx, int);
@@ -554,6 +839,7 @@ static void change_queue_index (rtx, int);
 
 static void extend_h_i_d (void);
 static void init_h_i_d (rtx);
+static int haifa_speculate_insn (rtx, ds_t, rtx *);
 static void generate_recovery_code (rtx);
 static void process_insn_forw_deps_be_in_spec (rtx, rtx, ds_t);
 static void begin_speculative_block (rtx);
@@ -561,7 +847,7 @@ static void add_to_speculative_block (rtx);
 static void init_before_recovery (basic_block *);
 static void create_check_block_twin (rtx, bool);
 static void fix_recovery_deps (basic_block);
-static void haifa_change_pattern (rtx, rtx);
+static bool haifa_change_pattern (rtx, rtx);
 static void dump_new_block_header (int, basic_block, rtx, rtx);
 static void restore_bb_notes (basic_block);
 static void fix_jump_move (rtx);
@@ -571,10 +857,6 @@ static void sched_remove_insn (rtx);
 static void clear_priorities (rtx, rtx_vec_t *);
 static void calc_priorities (rtx_vec_t);
 static void add_jump_dependencies (rtx, rtx);
-#ifdef ENABLE_CHECKING
-static int has_edge_p (VEC(edge,gc) *, int);
-static void check_cfg (rtx, rtx);
-#endif
 
 #endif /* INSN_SCHEDULING */
 \f
@@ -588,137 +870,533 @@ schedule_insns (void)
 }
 #else
 
-/* Pointer to the last instruction scheduled.  Used by rank_for_schedule,
-   so that insns independent of the last scheduled insn will be preferred
-   over dependent instructions.  */
+/* Do register pressure sensitive insn scheduling if the flag is set
+   up.  */
+bool sched_pressure_p;
 
-static rtx last_scheduled_insn;
+/* Map regno -> its pressure class.  The map defined only when
+   SCHED_PRESSURE_P is true.  */
+enum reg_class *sched_regno_pressure_class;
 
-/* Cached cost of the instruction.  Use below function to get cost of the
-   insn.  -1 here means that the field is not initialized.  */
-#define INSN_COST(INSN)        (HID (INSN)->cost)
+/* The current register pressure.  Only elements corresponding pressure
+   classes are defined.  */
+static int curr_reg_pressure[N_REG_CLASSES];
 
-/* Compute cost of executing INSN.
-   This is the number of cycles between instruction issue and
-   instruction results.  */
-HAIFA_INLINE int
-insn_cost (rtx insn)
-{
-  int cost;
+/* Saved value of the previous array.  */
+static int saved_reg_pressure[N_REG_CLASSES];
 
-  if (sel_sched_p ())
-    {
-      if (recog_memoized (insn) < 0)
-       return 0;
+/* Register living at given scheduling point.  */
+static bitmap curr_reg_live;
 
-      cost = insn_default_latency (insn);
-      if (cost < 0)
-       cost = 0;
+/* Saved value of the previous array.  */
+static bitmap saved_reg_live;
 
-      return cost;
-    }
+/* Registers mentioned in the current region.  */
+static bitmap region_ref_regs;
 
-  cost = INSN_COST (insn);
+/* Initiate register pressure relative info for scheduling the current
+   region.  Currently it is only clearing register mentioned in the
+   current region.  */
+void
+sched_init_region_reg_pressure_info (void)
+{
+  bitmap_clear (region_ref_regs);
+}
 
-  if (cost < 0)
+/* Update current register pressure related info after birth (if
+   BIRTH_P) or death of register REGNO.  */
+static void
+mark_regno_birth_or_death (int regno, bool birth_p)
+{
+  enum reg_class pressure_class;
+
+  pressure_class = sched_regno_pressure_class[regno];
+  if (regno >= FIRST_PSEUDO_REGISTER)
     {
-      /* A USE insn, or something else we don't need to
-        understand.  We can't pass these directly to
-        result_ready_cost or insn_default_latency because it will
-        trigger a fatal error for unrecognizable insns.  */
-      if (recog_memoized (insn) < 0)
+      if (pressure_class != NO_REGS)
        {
-         INSN_COST (insn) = 0;
-         return 0;
+         if (birth_p)
+           {
+             bitmap_set_bit (curr_reg_live, regno);
+             curr_reg_pressure[pressure_class]
+               += (ira_reg_class_max_nregs
+                   [pressure_class][PSEUDO_REGNO_MODE (regno)]);
+           }
+         else
+           {
+             bitmap_clear_bit (curr_reg_live, regno);
+             curr_reg_pressure[pressure_class]
+               -= (ira_reg_class_max_nregs
+                   [pressure_class][PSEUDO_REGNO_MODE (regno)]);
+           }
+       }
+    }
+  else if (pressure_class != NO_REGS
+          && ! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno))
+    {
+      if (birth_p)
+       {
+         bitmap_set_bit (curr_reg_live, regno);
+         curr_reg_pressure[pressure_class]++;
        }
       else
        {
-         cost = insn_default_latency (insn);
-         if (cost < 0)
-           cost = 0;
-
-         INSN_COST (insn) = cost;
+         bitmap_clear_bit (curr_reg_live, regno);
+         curr_reg_pressure[pressure_class]--;
        }
     }
+}
 
-  return cost;
+/* Initiate current register pressure related info from living
+   registers given by LIVE.  */
+static void
+initiate_reg_pressure_info (bitmap live)
+{
+  int i;
+  unsigned int j;
+  bitmap_iterator bi;
+
+  for (i = 0; i < ira_pressure_classes_num; i++)
+    curr_reg_pressure[ira_pressure_classes[i]] = 0;
+  bitmap_clear (curr_reg_live);
+  EXECUTE_IF_SET_IN_BITMAP (live, 0, j, bi)
+    if (current_nr_blocks == 1 || bitmap_bit_p (region_ref_regs, j))
+      mark_regno_birth_or_death (j, true);
 }
 
-/* Compute cost of dependence LINK.
-   This is the number of cycles between instruction issue and
-   instruction results.  */
-int
-dep_cost_1 (dep_t link, dw_t dw)
+/* Mark registers in X as mentioned in the current region.  */
+static void
+setup_ref_regs (rtx x)
 {
-  rtx used = DEP_CON (link);
-  int cost;
+  int i, j, regno;
+  const RTX_CODE code = GET_CODE (x);
+  const char *fmt;
 
-  /* A USE insn should never require the value used to be computed.
-     This allows the computation of a function's result and parameter
-     values to overlap the return and call.  */
-  if (recog_memoized (used) < 0)
-    cost = 0;
-  else
+  if (REG_P (x))
     {
-      rtx insn = DEP_PRO (link);
-      enum reg_note dep_type = DEP_TYPE (link);
-
-      cost = insn_cost (insn);
-
-      if (INSN_CODE (insn) >= 0)
-       {
-         if (dep_type == REG_DEP_ANTI)
-           cost = 0;
-         else if (dep_type == REG_DEP_OUTPUT)
-           {
-             cost = (insn_default_latency (insn)
-                     - insn_default_latency (used));
-             if (cost <= 0)
-               cost = 1;
-           }
-         else if (bypass_p (insn))
-           cost = insn_latency (insn, used);
-       }
-       
+      regno = REGNO (x);
+      if (HARD_REGISTER_NUM_P (regno))
+       bitmap_set_range (region_ref_regs, regno,
+                         hard_regno_nregs[regno][GET_MODE (x)]);
+      else
+       bitmap_set_bit (region_ref_regs, REGNO (x));
+      return;
+    }
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    if (fmt[i] == 'e')
+      setup_ref_regs (XEXP (x, i));
+    else if (fmt[i] == 'E')
+      {
+       for (j = 0; j < XVECLEN (x, i); j++)
+         setup_ref_regs (XVECEXP (x, i, j));
+      }
+}
 
-      if (targetm.sched.adjust_cost_2)
-       {
-         cost = targetm.sched.adjust_cost_2 (used, (int) dep_type, insn, cost,
-                                             dw);
-       }
-      else if (targetm.sched.adjust_cost != NULL)
-       {
-         /* This variable is used for backward compatibility with the
-            targets.  */
-         rtx dep_cost_rtx_link = alloc_INSN_LIST (NULL_RTX, NULL_RTX);
+/* Initiate current register pressure related info at the start of
+   basic block BB.  */
+static void
+initiate_bb_reg_pressure_info (basic_block bb)
+{
+  unsigned int i ATTRIBUTE_UNUSED;
+  rtx insn;
 
-         /* Make it self-cycled, so that if some tries to walk over this
-            incomplete list he/she will be caught in an endless loop.  */
-         XEXP (dep_cost_rtx_link, 1) = dep_cost_rtx_link;
+  if (current_nr_blocks > 1)
+    FOR_BB_INSNS (bb, insn)
+      if (NONDEBUG_INSN_P (insn))
+       setup_ref_regs (PATTERN (insn));
+  initiate_reg_pressure_info (df_get_live_in (bb));
+#ifdef EH_RETURN_DATA_REGNO
+  if (bb_has_eh_pred (bb))
+    for (i = 0; ; ++i)
+      {
+       unsigned int regno = EH_RETURN_DATA_REGNO (i);
 
-         /* Targets use only REG_NOTE_KIND of the link.  */
-         PUT_REG_NOTE_KIND (dep_cost_rtx_link, DEP_TYPE (link));
+       if (regno == INVALID_REGNUM)
+         break;
+       if (! bitmap_bit_p (df_get_live_in (bb), regno))
+         mark_regno_birth_or_death (regno, true);
+      }
+#endif
+}
 
-         cost = targetm.sched.adjust_cost (used, dep_cost_rtx_link,
-                                           insn, cost);
+/* Save current register pressure related info.  */
+static void
+save_reg_pressure (void)
+{
+  int i;
 
-         free_INSN_LIST_node (dep_cost_rtx_link);
-       }
+  for (i = 0; i < ira_pressure_classes_num; i++)
+    saved_reg_pressure[ira_pressure_classes[i]]
+      = curr_reg_pressure[ira_pressure_classes[i]];
+  bitmap_copy (saved_reg_live, curr_reg_live);
+}
 
-      if (cost < 0)
-       cost = 0;
-    }
+/* Restore saved register pressure related info.  */
+static void
+restore_reg_pressure (void)
+{
+  int i;
 
-  return cost;
+  for (i = 0; i < ira_pressure_classes_num; i++)
+    curr_reg_pressure[ira_pressure_classes[i]]
+      = saved_reg_pressure[ira_pressure_classes[i]];
+  bitmap_copy (curr_reg_live, saved_reg_live);
 }
 
-/* Compute cost of dependence LINK.
-   This is the number of cycles between instruction issue and
-   instruction results.  */
-int
-dep_cost (dep_t link)
+/* Return TRUE if the register is dying after its USE.  */
+static bool
+dying_use_p (struct reg_use_data *use)
 {
-  return dep_cost_1 (link, 0);
+  struct reg_use_data *next;
+
+  for (next = use->next_regno_use; next != use; next = next->next_regno_use)
+    if (NONDEBUG_INSN_P (next->insn)
+       && QUEUE_INDEX (next->insn) != QUEUE_SCHEDULED)
+      return false;
+  return true;
+}
+
+/* Print info about the current register pressure and its excess for
+   each pressure class.  */
+static void
+print_curr_reg_pressure (void)
+{
+  int i;
+  enum reg_class cl;
+
+  fprintf (sched_dump, ";;\t");
+  for (i = 0; i < ira_pressure_classes_num; i++)
+    {
+      cl = ira_pressure_classes[i];
+      gcc_assert (curr_reg_pressure[cl] >= 0);
+      fprintf (sched_dump, "  %s:%d(%d)", reg_class_names[cl],
+              curr_reg_pressure[cl],
+              curr_reg_pressure[cl] - ira_available_class_regs[cl]);
+    }
+  fprintf (sched_dump, "\n");
+}
+\f
+/* Determine if INSN has a condition that is clobbered if a register
+   in SET_REGS is modified.  */
+static bool
+cond_clobbered_p (rtx insn, HARD_REG_SET set_regs)
+{
+  rtx pat = PATTERN (insn);
+  gcc_assert (GET_CODE (pat) == COND_EXEC);
+  if (TEST_HARD_REG_BIT (set_regs, REGNO (XEXP (COND_EXEC_TEST (pat), 0))))
+    {
+      sd_iterator_def sd_it;
+      dep_t dep;
+      haifa_change_pattern (insn, ORIG_PAT (insn));
+      FOR_EACH_DEP (insn, SD_LIST_BACK, sd_it, dep)
+       DEP_STATUS (dep) &= ~DEP_CANCELLED;
+      TODO_SPEC (insn) = HARD_DEP;
+      if (sched_verbose >= 2)
+       fprintf (sched_dump,
+                ";;\t\tdequeue insn %s because of clobbered condition\n",
+                (*current_sched_info->print_insn) (insn, 0));
+      return true;
+    }
+
+  return false;
+}
+
+/* Look at the remaining dependencies for insn NEXT, and compute and return
+   the TODO_SPEC value we should use for it.  This is called after one of
+   NEXT's dependencies has been resolved.  */
+
+static ds_t
+recompute_todo_spec (rtx next)
+{
+  ds_t new_ds;
+  sd_iterator_def sd_it;
+  dep_t dep, control_dep = NULL;
+  int n_spec = 0;
+  int n_control = 0;
+  bool first_p = true;
+
+  if (sd_lists_empty_p (next, SD_LIST_BACK))
+    /* NEXT has all its dependencies resolved.  */
+    return 0;
+
+  if (!sd_lists_empty_p (next, SD_LIST_HARD_BACK))
+    return HARD_DEP;
+
+  /* Now we've got NEXT with speculative deps only.
+     1. Look at the deps to see what we have to do.
+     2. Check if we can do 'todo'.  */
+  new_ds = 0;
+
+  FOR_EACH_DEP (next, SD_LIST_BACK, sd_it, dep)
+    {
+      ds_t ds = DEP_STATUS (dep) & SPECULATIVE;
+
+      if (DEBUG_INSN_P (DEP_PRO (dep)) && !DEBUG_INSN_P (next))
+       continue;
+
+      if (ds)
+       {
+         n_spec++;
+         if (first_p)
+           {
+             first_p = false;
+
+             new_ds = ds;
+           }
+         else
+           new_ds = ds_merge (new_ds, ds);
+       }
+      if (DEP_TYPE (dep) == REG_DEP_CONTROL)
+       {
+         n_control++;
+         control_dep = dep;
+         DEP_STATUS (dep) &= ~DEP_CANCELLED;
+       }
+    }
+
+  if (n_control == 1 && n_spec == 0)
+    {
+      rtx pro, other, new_pat;
+      rtx cond = NULL_RTX;
+      bool success;
+      rtx prev = NULL_RTX;
+      int i;
+      unsigned regno;
+  
+      if ((current_sched_info->flags & DO_PREDICATION) == 0
+         || (ORIG_PAT (next) != NULL_RTX
+             && PREDICATED_PAT (next) == NULL_RTX))
+       return HARD_DEP;
+
+      pro = DEP_PRO (control_dep);
+      other = real_insn_for_shadow (pro);
+      if (other != NULL_RTX)
+       pro = other;
+
+      cond = sched_get_reverse_condition_uncached (pro);
+      regno = REGNO (XEXP (cond, 0));
+
+      /* Find the last scheduled insn that modifies the condition register.
+        We can stop looking once we find the insn we depend on through the
+        REG_DEP_CONTROL; if the condition register isn't modified after it,
+        we know that it still has the right value.  */
+      if (QUEUE_INDEX (pro) == QUEUE_SCHEDULED)
+       FOR_EACH_VEC_ELT_REVERSE (rtx, scheduled_insns, i, prev)
+         {
+           HARD_REG_SET t;
+
+           find_all_hard_reg_sets (prev, &t);
+           if (TEST_HARD_REG_BIT (t, regno))
+             return HARD_DEP;
+           if (prev == pro)
+             break;
+         }
+      if (ORIG_PAT (next) == NULL_RTX)
+       {
+         ORIG_PAT (next) = PATTERN (next);
+
+         new_pat = gen_rtx_COND_EXEC (VOIDmode, cond, PATTERN (next));
+         success = haifa_change_pattern (next, new_pat);
+         if (!success)
+           return HARD_DEP;
+         PREDICATED_PAT (next) = new_pat;
+       }
+      else if (PATTERN (next) != PREDICATED_PAT (next))
+       {
+         bool success = haifa_change_pattern (next,
+                                              PREDICATED_PAT (next));
+         gcc_assert (success);
+       }
+      DEP_STATUS (control_dep) |= DEP_CANCELLED;
+      return DEP_CONTROL;
+    }
+
+  if (PREDICATED_PAT (next) != NULL_RTX)
+    {
+      int tick = INSN_TICK (next);
+      bool success = haifa_change_pattern (next,
+                                          ORIG_PAT (next));
+      INSN_TICK (next) = tick;
+      gcc_assert (success);
+    }
+
+  /* We can't handle the case where there are both speculative and control
+     dependencies, so we return HARD_DEP in such a case.  Also fail if
+     we have speculative dependencies with not enough points, or more than
+     one control dependency.  */
+  if ((n_spec > 0 && n_control > 0)
+      || (n_spec > 0
+         /* Too few points?  */
+         && ds_weak (new_ds) < spec_info->data_weakness_cutoff)
+      || (n_control > 1))
+    return HARD_DEP;
+
+  return new_ds;
+}
+\f
+/* Pointer to the last instruction scheduled.  */
+static rtx last_scheduled_insn;
+
+/* Pointer to the last nondebug instruction scheduled within the
+   block, or the prev_head of the scheduling block.  Used by
+   rank_for_schedule, so that insns independent of the last scheduled
+   insn will be preferred over dependent instructions.  */
+static rtx last_nondebug_scheduled_insn;
+
+/* Pointer that iterates through the list of unscheduled insns if we
+   have a dbg_cnt enabled.  It always points at an insn prior to the
+   first unscheduled one.  */
+static rtx nonscheduled_insns_begin;
+
+/* Cached cost of the instruction.  Use below function to get cost of the
+   insn.  -1 here means that the field is not initialized.  */
+#define INSN_COST(INSN)        (HID (INSN)->cost)
+
+/* Compute cost of executing INSN.
+   This is the number of cycles between instruction issue and
+   instruction results.  */
+int
+insn_cost (rtx insn)
+{
+  int cost;
+
+  if (sel_sched_p ())
+    {
+      if (recog_memoized (insn) < 0)
+       return 0;
+
+      cost = insn_default_latency (insn);
+      if (cost < 0)
+       cost = 0;
+
+      return cost;
+    }
+
+  cost = INSN_COST (insn);
+
+  if (cost < 0)
+    {
+      /* A USE insn, or something else we don't need to
+        understand.  We can't pass these directly to
+        result_ready_cost or insn_default_latency because it will
+        trigger a fatal error for unrecognizable insns.  */
+      if (recog_memoized (insn) < 0)
+       {
+         INSN_COST (insn) = 0;
+         return 0;
+       }
+      else
+       {
+         cost = insn_default_latency (insn);
+         if (cost < 0)
+           cost = 0;
+
+         INSN_COST (insn) = cost;
+       }
+    }
+
+  return cost;
+}
+
+/* Compute cost of dependence LINK.
+   This is the number of cycles between instruction issue and
+   instruction results.
+   ??? We also use this function to call recog_memoized on all insns.  */
+int
+dep_cost_1 (dep_t link, dw_t dw)
+{
+  rtx insn = DEP_PRO (link);
+  rtx used = DEP_CON (link);
+  int cost;
+
+  if (DEP_COST (link) != UNKNOWN_DEP_COST)
+    return DEP_COST (link);
+
+  if (delay_htab)
+    {
+      struct delay_pair *delay_entry;
+      delay_entry
+       = (struct delay_pair *)htab_find_with_hash (delay_htab_i2, used,
+                                                   htab_hash_pointer (used));
+      if (delay_entry)
+       {
+         if (delay_entry->i1 == insn)
+           {
+             DEP_COST (link) = pair_delay (delay_entry);
+             return DEP_COST (link);
+           }
+       }
+    }
+
+  /* A USE insn should never require the value used to be computed.
+     This allows the computation of a function's result and parameter
+     values to overlap the return and call.  We don't care about the
+     dependence cost when only decreasing register pressure.  */
+  if (recog_memoized (used) < 0)
+    {
+      cost = 0;
+      recog_memoized (insn);
+    }
+  else
+    {
+      enum reg_note dep_type = DEP_TYPE (link);
+
+      cost = insn_cost (insn);
+
+      if (INSN_CODE (insn) >= 0)
+       {
+         if (dep_type == REG_DEP_ANTI)
+           cost = 0;
+         else if (dep_type == REG_DEP_OUTPUT)
+           {
+             cost = (insn_default_latency (insn)
+                     - insn_default_latency (used));
+             if (cost <= 0)
+               cost = 1;
+           }
+         else if (bypass_p (insn))
+           cost = insn_latency (insn, used);
+       }
+
+
+      if (targetm.sched.adjust_cost_2)
+       cost = targetm.sched.adjust_cost_2 (used, (int) dep_type, insn, cost,
+                                           dw);
+      else if (targetm.sched.adjust_cost != NULL)
+       {
+         /* This variable is used for backward compatibility with the
+            targets.  */
+         rtx dep_cost_rtx_link = alloc_INSN_LIST (NULL_RTX, NULL_RTX);
+
+         /* Make it self-cycled, so that if some tries to walk over this
+            incomplete list he/she will be caught in an endless loop.  */
+         XEXP (dep_cost_rtx_link, 1) = dep_cost_rtx_link;
+
+         /* Targets use only REG_NOTE_KIND of the link.  */
+         PUT_REG_NOTE_KIND (dep_cost_rtx_link, DEP_TYPE (link));
+
+         cost = targetm.sched.adjust_cost (used, dep_cost_rtx_link,
+                                           insn, cost);
+
+         free_INSN_LIST_node (dep_cost_rtx_link);
+       }
+
+      if (cost < 0)
+       cost = 0;
+    }
+
+  DEP_COST (link) = cost;
+  return cost;
+}
+
+/* Compute cost of dependence LINK.
+   This is the number of cycles between instruction issue and
+   instruction results.  */
+int
+dep_cost (dep_t link)
+{
+  return dep_cost_1 (link, 0);
 }
 
 /* Use this sel-sched.c friendly function in reorder2 instead of increasing
@@ -734,7 +1412,7 @@ increase_insn_priority (rtx insn, int amount)
     }
   else
     {
-      /* In sel-sched.c INSN_PRIORITY is not kept up to date.  
+      /* In sel-sched.c INSN_PRIORITY is not kept up to date.
         Use EXPR_PRIORITY instead. */
       sel_add_to_insn_priority (insn, amount);
     }
@@ -744,6 +1422,10 @@ increase_insn_priority (rtx insn, int amount)
 static bool
 contributes_to_priority_p (dep_t dep)
 {
+  if (DEBUG_INSN_P (DEP_CON (dep))
+      || DEBUG_INSN_P (DEP_PRO (dep)))
+    return false;
+
   /* Critical path is meaningful in block boundaries only.  */
   if (!current_sched_info->contributes_to_priority (DEP_CON (dep),
                                                    DEP_PRO (dep)))
@@ -763,6 +1445,31 @@ contributes_to_priority_p (dep_t dep)
   return true;
 }
 
+/* Compute the number of nondebug forward deps of an insn.  */
+
+static int
+dep_list_size (rtx insn)
+{
+  sd_iterator_def sd_it;
+  dep_t dep;
+  int dbgcount = 0, nodbgcount = 0;
+
+  if (!MAY_HAVE_DEBUG_INSNS)
+    return sd_lists_size (insn, SD_LIST_FORW);
+
+  FOR_EACH_DEP (insn, SD_LIST_FORW, sd_it, dep)
+    {
+      if (DEBUG_INSN_P (DEP_CON (dep)))
+       dbgcount++;
+      else if (!DEBUG_INSN_P (DEP_PRO (dep)))
+       nodbgcount++;
+    }
+
+  gcc_assert (dbgcount + nodbgcount == sd_lists_size (insn, SD_LIST_FORW));
+
+  return nodbgcount;
+}
+
 /* Compute the priority number for INSN.  */
 static int
 priority (rtx insn)
@@ -777,7 +1484,7 @@ priority (rtx insn)
     {
       int this_priority = -1;
 
-      if (sd_lists_empty_p (insn, SD_LIST_FORW))
+      if (dep_list_size (insn) == 0)
        /* ??? We should set INSN_PRIORITY to insn_cost when and insn has
           some forward deps but all of them are ignored by
           contributes_to_priority hook.  At the moment we set priority of
@@ -792,7 +1499,7 @@ priority (rtx insn)
             different than that of normal instructions.  Instead of walking
             through INSN_FORW_DEPS (check) list, we walk through
             INSN_FORW_DEPS list of each instruction in the corresponding
-            recovery block.  */ 
+            recovery block.  */
 
           /* Selective scheduling does not define RECOVERY_BLOCK macro.  */
          rec = sel_sched_p () ? NULL : RECOVERY_BLOCK (insn);
@@ -843,7 +1550,7 @@ priority (rtx insn)
                        this_priority = next_priority;
                    }
                }
-             
+
              twin = PREV_INSN (twin);
            }
          while (twin != prev_first);
@@ -873,6 +1580,56 @@ do { if ((N_READY) == 2)                                       \
          qsort (READY, N_READY, sizeof (rtx), rank_for_schedule); }  \
 while (0)
 
+/* Setup info about the current register pressure impact of scheduling
+   INSN at the current scheduling point.  */
+static void
+setup_insn_reg_pressure_info (rtx insn)
+{
+  int i, change, before, after, hard_regno;
+  int excess_cost_change;
+  enum machine_mode mode;
+  enum reg_class cl;
+  struct reg_pressure_data *pressure_info;
+  int *max_reg_pressure;
+  struct reg_use_data *use;
+  static int death[N_REG_CLASSES];
+
+  gcc_checking_assert (!DEBUG_INSN_P (insn));
+
+  excess_cost_change = 0;
+  for (i = 0; i < ira_pressure_classes_num; i++)
+    death[ira_pressure_classes[i]] = 0;
+  for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use)
+    if (dying_use_p (use))
+      {
+       cl = sched_regno_pressure_class[use->regno];
+       if (use->regno < FIRST_PSEUDO_REGISTER)
+         death[cl]++;
+       else
+         death[cl]
+           += ira_reg_class_max_nregs[cl][PSEUDO_REGNO_MODE (use->regno)];
+      }
+  pressure_info = INSN_REG_PRESSURE (insn);
+  max_reg_pressure = INSN_MAX_REG_PRESSURE (insn);
+  gcc_assert (pressure_info != NULL && max_reg_pressure != NULL);
+  for (i = 0; i < ira_pressure_classes_num; i++)
+    {
+      cl = ira_pressure_classes[i];
+      gcc_assert (curr_reg_pressure[cl] >= 0);
+      change = (int) pressure_info[i].set_increase - death[cl];
+      before = MAX (0, max_reg_pressure[i] - ira_available_class_regs[cl]);
+      after = MAX (0, max_reg_pressure[i] + change
+                  - ira_available_class_regs[cl]);
+      hard_regno = ira_class_hard_regs[cl][0];
+      gcc_assert (hard_regno >= 0);
+      mode = reg_raw_mode[hard_regno];
+      excess_cost_change += ((after - before)
+                            * (ira_memory_move_cost[mode][cl][0]
+                               + ira_memory_move_cost[mode][cl][1]));
+    }
+  INSN_REG_PRESSURE_EXCESS_COST_CHANGE (insn) = excess_cost_change;
+}
+
 /* Returns a positive value if x is preferred; returns a negative value if
    y is preferred.  Should never return 0, since that will make the sort
    unstable.  */
@@ -883,23 +1640,72 @@ rank_for_schedule (const void *x, const void *y)
   rtx tmp = *(const rtx *) y;
   rtx tmp2 = *(const rtx *) x;
   int tmp_class, tmp2_class;
-  int val, priority_val, weight_val, info_val;
+  int val, priority_val, info_val;
+
+  if (MAY_HAVE_DEBUG_INSNS)
+    {
+      /* Schedule debug insns as early as possible.  */
+      if (DEBUG_INSN_P (tmp) && !DEBUG_INSN_P (tmp2))
+       return -1;
+      else if (!DEBUG_INSN_P (tmp) && DEBUG_INSN_P (tmp2))
+       return 1;
+      else if (DEBUG_INSN_P (tmp) && DEBUG_INSN_P (tmp2))
+       return INSN_LUID (tmp) - INSN_LUID (tmp2);
+    }
 
   /* The insn in a schedule group should be issued the first.  */
-  if (SCHED_GROUP_P (tmp) != SCHED_GROUP_P (tmp2))
+  if (flag_sched_group_heuristic &&
+      SCHED_GROUP_P (tmp) != SCHED_GROUP_P (tmp2))
     return SCHED_GROUP_P (tmp2) ? 1 : -1;
 
   /* Make sure that priority of TMP and TMP2 are initialized.  */
   gcc_assert (INSN_PRIORITY_KNOWN (tmp) && INSN_PRIORITY_KNOWN (tmp2));
 
+  if (sched_pressure_p)
+    {
+      int diff;
+
+      /* Prefer insn whose scheduling results in the smallest register
+        pressure excess.  */
+      if ((diff = (INSN_REG_PRESSURE_EXCESS_COST_CHANGE (tmp)
+                  + (INSN_TICK (tmp) > clock_var
+                     ? INSN_TICK (tmp) - clock_var : 0)
+                  - INSN_REG_PRESSURE_EXCESS_COST_CHANGE (tmp2)
+                  - (INSN_TICK (tmp2) > clock_var
+                     ? INSN_TICK (tmp2) - clock_var : 0))) != 0)
+       return diff;
+    }
+
+
+  if (sched_pressure_p
+      && (INSN_TICK (tmp2) > clock_var || INSN_TICK (tmp) > clock_var))
+    {
+      if (INSN_TICK (tmp) <= clock_var)
+       return -1;
+      else if (INSN_TICK (tmp2) <= clock_var)
+       return 1;
+      else
+       return INSN_TICK (tmp) - INSN_TICK (tmp2);
+    }
+
+  /* If we are doing backtracking in this schedule, prefer insns that
+     have forward dependencies with negative cost against an insn that
+     was already scheduled.  */
+  if (current_sched_info->flags & DO_BACKTRACKING)
+    {
+      priority_val = FEEDS_BACKTRACK_INSN (tmp2) - FEEDS_BACKTRACK_INSN (tmp);
+      if (priority_val)
+       return priority_val;
+    }
+
   /* Prefer insn with higher priority.  */
   priority_val = INSN_PRIORITY (tmp2) - INSN_PRIORITY (tmp);
 
-  if (priority_val)
+  if (flag_sched_critical_path_heuristic && priority_val)
     return priority_val;
 
   /* Prefer speculative insn with greater dependencies weakness.  */
-  if (spec_info)
+  if (flag_sched_spec_insn_heuristic && spec_info)
     {
       ds_t ds1, ds2;
       dw_t dw1, dw2;
@@ -910,7 +1716,7 @@ rank_for_schedule (const void *x, const void *y)
        dw1 = ds_weak (ds1);
       else
        dw1 = NO_DEP_WEAK;
-      
+
       ds2 = TODO_SPEC (tmp2) & SPECULATIVE;
       if (ds2)
        dw2 = ds_weak (ds2);
@@ -922,27 +1728,24 @@ rank_for_schedule (const void *x, const void *y)
        return dw;
     }
 
-  /* Prefer an insn with smaller contribution to registers-pressure.  */
-  if (!reload_completed &&
-      (weight_val = INSN_REG_WEIGHT (tmp) - INSN_REG_WEIGHT (tmp2)))
-    return weight_val;
-
   info_val = (*current_sched_info->rank) (tmp, tmp2);
-  if (info_val)
+  if(flag_sched_rank_heuristic && info_val)
     return info_val;
 
-  /* Compare insns based on their relation to the last-scheduled-insn.  */
-  if (INSN_P (last_scheduled_insn))
+  /* Compare insns based on their relation to the last scheduled
+     non-debug insn.  */
+  if (flag_sched_last_insn_heuristic && last_nondebug_scheduled_insn)
     {
       dep_t dep1;
       dep_t dep2;
+      rtx last = last_nondebug_scheduled_insn;
 
       /* Classify the instructions into three classes:
          1) Data dependent on last schedule insn.
          2) Anti/Output dependent on last scheduled insn.
          3) Independent of last scheduled insn, or has latency of one.
          Choose the insn from the highest numbered class if different.  */
-      dep1 = sd_find_dep_between (last_scheduled_insn, tmp, true);
+      dep1 = sd_find_dep_between (last, tmp, true);
 
       if (dep1 == NULL || dep_cost (dep1) == 1)
        tmp_class = 3;
@@ -952,7 +1755,7 @@ rank_for_schedule (const void *x, const void *y)
       else
        tmp_class = 2;
 
-      dep2 = sd_find_dep_between (last_scheduled_insn, tmp2, true);
+      dep2 = sd_find_dep_between (last, tmp2, true);
 
       if (dep2 == NULL || dep_cost (dep2)  == 1)
        tmp2_class = 3;
@@ -970,10 +1773,9 @@ rank_for_schedule (const void *x, const void *y)
      This gives the scheduler more freedom when scheduling later
      instructions at the expense of added register pressure.  */
 
-  val = (sd_lists_size (tmp2, SD_LIST_FORW)
-        - sd_lists_size (tmp, SD_LIST_FORW));
+  val = (dep_list_size (tmp2) - dep_list_size (tmp));
 
-  if (val != 0)
+  if (flag_sched_dep_count_heuristic && val != 0)
     return val;
 
   /* If insns are equally good, sort by INSN_LUID (original insn order),
@@ -1000,15 +1802,18 @@ swap_sort (rtx *a, int n)
 
 /* Add INSN to the insn queue so that it can be executed at least
    N_CYCLES after the currently executing insn.  Preserve insns
-   chain for debugging purposes.  */
+   chain for debugging purposes.  REASON will be printed in debugging
+   output.  */
 
 HAIFA_INLINE static void
-queue_insn (rtx insn, int n_cycles)
+queue_insn (rtx insn, int n_cycles, const char *reason)
 {
   int next_q = NEXT_Q_AFTER (q_ptr, n_cycles);
   rtx link = alloc_INSN_LIST (insn, insn_queue[next_q]);
+  int new_tick;
 
   gcc_assert (n_cycles <= max_insn_queue_index);
+  gcc_assert (!DEBUG_INSN_P (insn));
 
   insn_queue[next_q] = link;
   q_size += 1;
@@ -1018,10 +1823,25 @@ queue_insn (rtx insn, int n_cycles)
       fprintf (sched_dump, ";;\t\tReady-->Q: insn %s: ",
               (*current_sched_info->print_insn) (insn, 0));
 
-      fprintf (sched_dump, "queued for %d cycles.\n", n_cycles);
+      fprintf (sched_dump, "queued for %d cycles (%s).\n", n_cycles, reason);
     }
 
   QUEUE_INDEX (insn) = next_q;
+
+  if (current_sched_info->flags & DO_BACKTRACKING)
+    {
+      new_tick = clock_var + n_cycles;
+      if (INSN_TICK (insn) == INVALID_TICK || INSN_TICK (insn) < new_tick)
+       INSN_TICK (insn) = new_tick;
+
+      if (INSN_EXACT_TICK (insn) != INVALID_TICK
+         && INSN_EXACT_TICK (insn) < clock_var + n_cycles)
+       {
+         must_backtrack = true;
+         if (sched_verbose >= 2)
+           fprintf (sched_dump, ";;\t\tcausing a backtrack.\n");
+       }
+    }
 }
 
 /* Remove INSN from queue.  */
@@ -1076,9 +1896,17 @@ ready_add (struct ready_list *ready, rtx insn, bool first_p)
     }
 
   ready->n_ready++;
+  if (DEBUG_INSN_P (insn))
+    ready->n_debug++;
 
   gcc_assert (QUEUE_INDEX (insn) != QUEUE_READY);
   QUEUE_INDEX (insn) = QUEUE_READY;
+
+  if (INSN_EXACT_TICK (insn) != INVALID_TICK
+      && INSN_EXACT_TICK (insn) < clock_var)
+    {
+      must_backtrack = true;
+    }
 }
 
 /* Remove the element with the highest priority from the ready list and
@@ -1088,10 +1916,12 @@ HAIFA_INLINE static rtx
 ready_remove_first (struct ready_list *ready)
 {
   rtx t;
-  
+
   gcc_assert (ready->n_ready);
   t = ready->vec[ready->first--];
   ready->n_ready--;
+  if (DEBUG_INSN_P (t))
+    ready->n_debug--;
   /* If the queue becomes empty, reset it.  */
   if (ready->n_ready == 0)
     ready->first = ready->veclen - 1;
@@ -1114,7 +1944,7 @@ rtx
 ready_element (struct ready_list *ready, int index)
 {
   gcc_assert (ready->n_ready && index < ready->n_ready);
-  
+
   return ready->vec[ready->first - index];
 }
 
@@ -1133,6 +1963,8 @@ ready_remove (struct ready_list *ready, int index)
   gcc_assert (ready->n_ready && index < ready->n_ready);
   t = ready->vec[ready->first - index];
   ready->n_ready--;
+  if (DEBUG_INSN_P (t))
+    ready->n_debug--;
   for (i = index; i < ready->n_ready; i++)
     ready->vec[ready->first - i] = ready->vec[ready->first - i - 1];
   QUEUE_INDEX (t) = QUEUE_NOWHERE;
@@ -1160,7 +1992,15 @@ ready_remove_insn (rtx insn)
 void
 ready_sort (struct ready_list *ready)
 {
+  int i;
   rtx *first = ready_lastpos (ready);
+
+  if (sched_pressure_p)
+    {
+      for (i = 0; i < ready->n_ready; i++)
+       if (!DEBUG_INSN_P (first[i]))
+         setup_insn_reg_pressure_info (first[i]);
+    }
   SCHED_SORT (first, ready->n_ready);
 }
 
@@ -1195,7 +2035,7 @@ advance_state (state_t state)
                      targetm.sched.dfa_pre_cycle_insn ());
 
   state_transition (state, NULL);
-  
+
   if (targetm.sched.dfa_post_cycle_insn)
     state_transition (state,
                      targetm.sched.dfa_post_cycle_insn ());
@@ -1210,11 +2050,159 @@ advance_one_cycle (void)
 {
   advance_state (curr_state);
   if (sched_verbose >= 6)
-    fprintf (sched_dump, "\n;;\tAdvanced a state.\n");
+    fprintf (sched_dump, ";;\tAdvanced a state.\n");
 }
 
-/* Clock at which the previous instruction was issued.  */
-static int last_clock_var;
+/* Update register pressure after scheduling INSN.  */
+static void
+update_register_pressure (rtx insn)
+{
+  struct reg_use_data *use;
+  struct reg_set_data *set;
+
+  gcc_checking_assert (!DEBUG_INSN_P (insn));
+
+  for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use)
+    if (dying_use_p (use) && bitmap_bit_p (curr_reg_live, use->regno))
+      mark_regno_birth_or_death (use->regno, false);
+  for (set = INSN_REG_SET_LIST (insn); set != NULL; set = set->next_insn_set)
+    mark_regno_birth_or_death (set->regno, true);
+}
+
+/* Set up or update (if UPDATE_P) max register pressure (see its
+   meaning in sched-int.h::_haifa_insn_data) for all current BB insns
+   after insn AFTER.  */
+static void
+setup_insn_max_reg_pressure (rtx after, bool update_p)
+{
+  int i, p;
+  bool eq_p;
+  rtx insn;
+  static int max_reg_pressure[N_REG_CLASSES];
+
+  save_reg_pressure ();
+  for (i = 0; i < ira_pressure_classes_num; i++)
+    max_reg_pressure[ira_pressure_classes[i]]
+      = curr_reg_pressure[ira_pressure_classes[i]];
+  for (insn = NEXT_INSN (after);
+       insn != NULL_RTX && ! BARRIER_P (insn)
+        && BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (after);
+       insn = NEXT_INSN (insn))
+    if (NONDEBUG_INSN_P (insn))
+      {
+       eq_p = true;
+       for (i = 0; i < ira_pressure_classes_num; i++)
+         {
+           p = max_reg_pressure[ira_pressure_classes[i]];
+           if (INSN_MAX_REG_PRESSURE (insn)[i] != p)
+             {
+               eq_p = false;
+               INSN_MAX_REG_PRESSURE (insn)[i]
+                 = max_reg_pressure[ira_pressure_classes[i]];
+             }
+         }
+       if (update_p && eq_p)
+         break;
+       update_register_pressure (insn);
+       for (i = 0; i < ira_pressure_classes_num; i++)
+         if (max_reg_pressure[ira_pressure_classes[i]]
+             < curr_reg_pressure[ira_pressure_classes[i]])
+           max_reg_pressure[ira_pressure_classes[i]]
+             = curr_reg_pressure[ira_pressure_classes[i]];
+      }
+  restore_reg_pressure ();
+}
+
+/* Update the current register pressure after scheduling INSN.  Update
+   also max register pressure for unscheduled insns of the current
+   BB.  */
+static void
+update_reg_and_insn_max_reg_pressure (rtx insn)
+{
+  int i;
+  int before[N_REG_CLASSES];
+
+  for (i = 0; i < ira_pressure_classes_num; i++)
+    before[i] = curr_reg_pressure[ira_pressure_classes[i]];
+  update_register_pressure (insn);
+  for (i = 0; i < ira_pressure_classes_num; i++)
+    if (curr_reg_pressure[ira_pressure_classes[i]] != before[i])
+      break;
+  if (i < ira_pressure_classes_num)
+    setup_insn_max_reg_pressure (insn, true);
+}
+
+/* Set up register pressure at the beginning of basic block BB whose
+   insns starting after insn AFTER.  Set up also max register pressure
+   for all insns of the basic block.  */
+void
+sched_setup_bb_reg_pressure_info (basic_block bb, rtx after)
+{
+  gcc_assert (sched_pressure_p);
+  initiate_bb_reg_pressure_info (bb);
+  setup_insn_max_reg_pressure (after, false);
+}
+\f
+/* If doing predication while scheduling, verify whether INSN, which
+   has just been scheduled, clobbers the conditions of any
+   instructions that must be predicated in order to break their
+   dependencies.  If so, remove them from the queues so that they will
+   only be scheduled once their control dependency is resolved.  */
+
+static void
+check_clobbered_conditions (rtx insn)
+{
+  HARD_REG_SET t;
+  int i;
+
+  if ((current_sched_info->flags & DO_PREDICATION) == 0)
+    return;
+
+  find_all_hard_reg_sets (insn, &t);
+
+ restart:
+  for (i = 0; i < ready.n_ready; i++)
+    {
+      rtx x = ready_element (&ready, i);
+      if (TODO_SPEC (x) == DEP_CONTROL && cond_clobbered_p (x, t))
+       {
+         ready_remove_insn (x);
+         goto restart;
+       }
+    }
+  for (i = 0; i <= max_insn_queue_index; i++)
+    {
+      rtx link;
+      int q = NEXT_Q_AFTER (q_ptr, i);
+
+    restart_queue:
+      for (link = insn_queue[q]; link; link = XEXP (link, 1))
+       {
+         rtx x = XEXP (link, 0);
+         if (TODO_SPEC (x) == DEP_CONTROL && cond_clobbered_p (x, t))
+           {
+             queue_remove (x);
+             goto restart_queue;
+           }
+       }
+    }
+}
+\f
+/* A structure that holds local state for the loop in schedule_block.  */
+struct sched_block_state
+{
+  /* True if no real insns have been scheduled in the current cycle.  */
+  bool first_cycle_insn_p;
+  /* True if a shadow insn has been scheduled in the current cycle, which
+     means that no more normal insns can be issued.  */
+  bool shadows_only_p;
+  /* True if we're winding down a modulo schedule, which means that we only
+     issue insns with INSN_EXACT_TICK set.  */
+  bool modulo_epilogue;
+  /* Initialized with the machine's issue rate every cycle, and updated
+     by calls to the variable_issue hook.  */
+  int can_issue_more;
+};
 
 /* INSN is the "currently executing insn".  Launch each insn which was
    waiting on INSN.  READY is the ready list which contains the insns
@@ -1227,10 +2215,12 @@ schedule_insn (rtx insn)
 {
   sd_iterator_def sd_it;
   dep_t dep;
+  int i;
   int advance = 0;
 
   if (sched_verbose >= 1)
     {
+      struct reg_pressure_data *pressure_info;
       char buf[2048];
 
       print_insn (buf, insn, 0);
@@ -1241,12 +2231,78 @@ schedule_insn (rtx insn)
        fprintf (sched_dump, "nothing");
       else
        print_reservation (sched_dump, insn);
+      pressure_info = INSN_REG_PRESSURE (insn);
+      if (pressure_info != NULL)
+       {
+         fputc (':', sched_dump);
+         for (i = 0; i < ira_pressure_classes_num; i++)
+           fprintf (sched_dump, "%s%+d(%d)",
+                    reg_class_names[ira_pressure_classes[i]],
+                    pressure_info[i].set_increase, pressure_info[i].change);
+       }
       fputc ('\n', sched_dump);
     }
 
+  if (sched_pressure_p && !DEBUG_INSN_P (insn))
+    update_reg_and_insn_max_reg_pressure (insn);
+
   /* Scheduling instruction should have all its dependencies resolved and
      should have been removed from the ready list.  */
-  gcc_assert (sd_lists_empty_p (insn, SD_LIST_BACK));
+  gcc_assert (sd_lists_empty_p (insn, SD_LIST_HARD_BACK));
+
+  /* Reset debug insns invalidated by moving this insn.  */
+  if (MAY_HAVE_DEBUG_INSNS && !DEBUG_INSN_P (insn))
+    for (sd_it = sd_iterator_start (insn, SD_LIST_BACK);
+        sd_iterator_cond (&sd_it, &dep);)
+      {
+       rtx dbg = DEP_PRO (dep);
+       struct reg_use_data *use, *next;
+
+       if (DEP_STATUS (dep) & DEP_CANCELLED)
+         {
+           sd_iterator_next (&sd_it);
+           continue;
+         }
+
+       gcc_assert (DEBUG_INSN_P (dbg));
+
+       if (sched_verbose >= 6)
+         fprintf (sched_dump, ";;\t\tresetting: debug insn %d\n",
+                  INSN_UID (dbg));
+
+       /* ??? Rather than resetting the debug insn, we might be able
+          to emit a debug temp before the just-scheduled insn, but
+          this would involve checking that the expression at the
+          point of the debug insn is equivalent to the expression
+          before the just-scheduled insn.  They might not be: the
+          expression in the debug insn may depend on other insns not
+          yet scheduled that set MEMs, REGs or even other debug
+          insns.  It's not clear that attempting to preserve debug
+          information in these cases is worth the effort, given how
+          uncommon these resets are and the likelihood that the debug
+          temps introduced won't survive the schedule change.  */
+       INSN_VAR_LOCATION_LOC (dbg) = gen_rtx_UNKNOWN_VAR_LOC ();
+       df_insn_rescan (dbg);
+
+       /* Unknown location doesn't use any registers.  */
+       for (use = INSN_REG_USE_LIST (dbg); use != NULL; use = next)
+         {
+           struct reg_use_data *prev = use;
+
+           /* Remove use from the cyclic next_regno_use chain first.  */
+           while (prev->next_regno_use != use)
+             prev = prev->next_regno_use;
+           prev->next_regno_use = use->next_regno_use;
+           next = use->next_insn_use;
+           free (use);
+         }
+       INSN_REG_USE_LIST (dbg) = NULL;
+
+       /* We delete rather than resolve these deps, otherwise we
+          crash in sched_free_deps(), because forward deps are
+          expected to be released before backward deps.  */
+       sd_delete_dep (sd_it);
+      }
 
   gcc_assert (QUEUE_INDEX (insn) == QUEUE_NOWHERE);
   QUEUE_INDEX (insn) = QUEUE_SCHEDULED;
@@ -1255,29 +2311,54 @@ schedule_insn (rtx insn)
   if (INSN_TICK (insn) > clock_var)
     /* INSN has been prematurely moved from the queue to the ready list.
        This is possible only if following flag is set.  */
-    gcc_assert (flag_sched_stalled_insns);    
+    gcc_assert (flag_sched_stalled_insns);
 
   /* ??? Probably, if INSN is scheduled prematurely, we should leave
      INSN_TICK untouched.  This is a machine-dependent issue, actually.  */
   INSN_TICK (insn) = clock_var;
 
+  check_clobbered_conditions (insn);
+
   /* Update dependent instructions.  */
   for (sd_it = sd_iterator_start (insn, SD_LIST_FORW);
        sd_iterator_cond (&sd_it, &dep);)
     {
       rtx next = DEP_CON (dep);
+      bool cancelled = (DEP_STATUS (dep) & DEP_CANCELLED) != 0;
 
       /* Resolve the dependence between INSN and NEXT.
         sd_resolve_dep () moves current dep to another list thus
         advancing the iterator.  */
       sd_resolve_dep (sd_it);
 
+      if (cancelled)
+       {
+         if (QUEUE_INDEX (next) != QUEUE_SCHEDULED)
+           {
+             int tick = INSN_TICK (next);
+             gcc_assert (ORIG_PAT (next) != NULL_RTX);
+             haifa_change_pattern (next, ORIG_PAT (next));
+             INSN_TICK (next) = tick;
+             if (sd_lists_empty_p (next, SD_LIST_BACK))
+               TODO_SPEC (next) = 0;
+             else if (!sd_lists_empty_p (next, SD_LIST_HARD_BACK))
+               TODO_SPEC (next) = HARD_DEP;
+           }
+         continue;
+       }
+
+      /* Don't bother trying to mark next as ready if insn is a debug
+        insn.  If insn is the last hard dependency, it will have
+        already been discounted.  */
+      if (DEBUG_INSN_P (insn) && !DEBUG_INSN_P (next))
+       continue;
+
       if (!IS_SPECULATION_BRANCHY_CHECK_P (insn))
        {
-         int effective_cost;      
-         
+         int effective_cost;
+
          effective_cost = try_ready (next);
-         
+
          if (effective_cost >= 0
              && SCHED_GROUP_P (next)
              && advance < effective_cost)
@@ -1292,18 +2373,6 @@ schedule_insn (rtx insn)
        }
     }
 
-  /* This is the place where scheduler doesn't *basically* need backward and
-     forward dependencies for INSN anymore.  Nevertheless they are used in
-     heuristics in rank_for_schedule (), early_queue_to_ready () and in
-     some targets (e.g. rs6000).  Thus the earliest place where we *can*
-     remove dependencies is after targetm.sched.md_finish () call in
-     schedule_block ().  But, on the other side, the safest place to remove
-     dependencies is when we are finishing scheduling entire region.  As we
-     don't generate [many] dependencies during scheduling itself, we won't
-     need memory until beginning of next region.
-     Bottom line: Dependencies are removed for all insns in the end of
-     scheduling the region.  */
-
   /* Annotate the instruction with issue information -- TImode
      indicates that the instruction is expected not to be able
      to issue on the same cycle as the previous insn.  A machine
@@ -1311,7 +2380,8 @@ schedule_insn (rtx insn)
      be aligned.  */
   if (issue_rate > 1
       && GET_CODE (PATTERN (insn)) != USE
-      && GET_CODE (PATTERN (insn)) != CLOBBER)
+      && GET_CODE (PATTERN (insn)) != CLOBBER
+      && !DEBUG_INSN_P (insn))
     {
       if (reload_completed)
        PUT_MODE (insn, clock_var > last_clock_var ? TImode : VOIDmode);
@@ -1323,89 +2393,571 @@ schedule_insn (rtx insn)
 
 /* Functions for handling of notes.  */
 
-/* Insert the INSN note at the end of the notes list.  */
-static void 
-add_to_note_list (rtx insn, rtx *note_list_end_p)
-{
-  PREV_INSN (insn) = *note_list_end_p;
-  if (*note_list_end_p)
-    NEXT_INSN (*note_list_end_p) = insn;
-  *note_list_end_p = insn;
-}
-
 /* Add note list that ends on FROM_END to the end of TO_ENDP.  */
 void
 concat_note_lists (rtx from_end, rtx *to_endp)
 {
   rtx from_start;
 
+  /* It's easy when have nothing to concat.  */
   if (from_end == NULL)
-    /* It's easy when have nothing to concat.  */
     return;
 
+  /* It's also easy when destination is empty.  */
   if (*to_endp == NULL)
-    /* It's also easy when destination is empty.  */
     {
       *to_endp = from_end;
       return;
     }
 
   from_start = from_end;
-  /* A note list should be traversed via PREV_INSN.  */
-  while (PREV_INSN (from_start) != NULL) 
+  while (PREV_INSN (from_start) != NULL)
     from_start = PREV_INSN (from_start);
 
-  add_to_note_list (from_start, to_endp);
+  PREV_INSN (from_start) = *to_endp;
+  NEXT_INSN (*to_endp) = from_start;
   *to_endp = from_end;
 }
 
-/* Delete notes beginning with INSN and put them in the chain
-   of notes ended by NOTE_LIST.
-   Returns the insn following the notes.  */
-static rtx
-unlink_other_notes (rtx insn, rtx tail)
-{
-  rtx prev = PREV_INSN (insn);
+/* Delete notes between HEAD and TAIL and put them in the chain
+   of notes ended by NOTE_LIST.  */
+void
+remove_notes (rtx head, rtx tail)
+{
+  rtx next_tail, insn, next;
+
+  note_list = 0;
+  if (head == tail && !INSN_P (head))
+    return;
+
+  next_tail = NEXT_INSN (tail);
+  for (insn = head; insn != next_tail; insn = next)
+    {
+      next = NEXT_INSN (insn);
+      if (!NOTE_P (insn))
+       continue;
+
+      switch (NOTE_KIND (insn))
+       {
+       case NOTE_INSN_BASIC_BLOCK:
+         continue;
+
+       case NOTE_INSN_EPILOGUE_BEG:
+         if (insn != tail)
+           {
+             remove_insn (insn);
+             add_reg_note (next, REG_SAVE_NOTE,
+                           GEN_INT (NOTE_INSN_EPILOGUE_BEG));
+             break;
+           }
+         /* FALLTHRU */
+
+       default:
+         remove_insn (insn);
+
+         /* Add the note to list that ends at NOTE_LIST.  */
+         PREV_INSN (insn) = note_list;
+         NEXT_INSN (insn) = NULL_RTX;
+         if (note_list)
+           NEXT_INSN (note_list) = insn;
+         note_list = insn;
+         break;
+       }
+
+      gcc_assert ((sel_sched_p () || insn != tail) && insn != head);
+    }
+}
+
+/* A structure to record enough data to allow us to backtrack the scheduler to
+   a previous state.  */
+struct haifa_saved_data
+{
+  /* Next entry on the list.  */
+  struct haifa_saved_data *next;
+
+  /* Backtracking is associated with scheduling insns that have delay slots.
+     DELAY_PAIR points to the structure that contains the insns involved, and
+     the number of cycles between them.  */
+  struct delay_pair *delay_pair;
+
+  /* Data used by the frontend (e.g. sched-ebb or sched-rgn).  */
+  void *fe_saved_data;
+  /* Data used by the backend.  */
+  void *be_saved_data;
+
+  /* Copies of global state.  */
+  int clock_var, last_clock_var;
+  struct ready_list ready;
+  state_t curr_state;
+
+  rtx last_scheduled_insn;
+  rtx last_nondebug_scheduled_insn;
+  int cycle_issued_insns;
+
+  /* Copies of state used in the inner loop of schedule_block.  */
+  struct sched_block_state sched_block;
+
+  /* We don't need to save q_ptr, as its value is arbitrary and we can set it
+     to 0 when restoring.  */
+  int q_size;
+  rtx *insn_queue;
+};
+
+/* A record, in reverse order, of all scheduled insns which have delay slots
+   and may require backtracking.  */
+static struct haifa_saved_data *backtrack_queue;
+
+/* For every dependency of INSN, set the FEEDS_BACKTRACK_INSN bit according
+   to SET_P.  */
+static void
+mark_backtrack_feeds (rtx insn, int set_p)
+{
+  sd_iterator_def sd_it;
+  dep_t dep;
+  FOR_EACH_DEP (insn, SD_LIST_HARD_BACK, sd_it, dep)
+    {
+      FEEDS_BACKTRACK_INSN (DEP_PRO (dep)) = set_p;
+    }
+}
+
+/* Save the current scheduler state so that we can backtrack to it
+   later if necessary.  PAIR gives the insns that make it necessary to
+   save this point.  SCHED_BLOCK is the local state of schedule_block
+   that need to be saved.  */
+static void
+save_backtrack_point (struct delay_pair *pair,
+                     struct sched_block_state sched_block)
+{
+  int i;
+  struct haifa_saved_data *save = XNEW (struct haifa_saved_data);
+
+  save->curr_state = xmalloc (dfa_state_size);
+  memcpy (save->curr_state, curr_state, dfa_state_size);
+
+  save->ready.first = ready.first;
+  save->ready.n_ready = ready.n_ready;
+  save->ready.n_debug = ready.n_debug;
+  save->ready.veclen = ready.veclen;
+  save->ready.vec = XNEWVEC (rtx, ready.veclen);
+  memcpy (save->ready.vec, ready.vec, ready.veclen * sizeof (rtx));
+
+  save->insn_queue = XNEWVEC (rtx, max_insn_queue_index + 1);
+  save->q_size = q_size;
+  for (i = 0; i <= max_insn_queue_index; i++)
+    {
+      int q = NEXT_Q_AFTER (q_ptr, i);
+      save->insn_queue[i] = copy_INSN_LIST (insn_queue[q]);
+    }
+
+  save->clock_var = clock_var;
+  save->last_clock_var = last_clock_var;
+  save->cycle_issued_insns = cycle_issued_insns;
+  save->last_scheduled_insn = last_scheduled_insn;
+  save->last_nondebug_scheduled_insn = last_nondebug_scheduled_insn;
+
+  save->sched_block = sched_block;
+
+  if (current_sched_info->save_state)
+    save->fe_saved_data = (*current_sched_info->save_state) ();
+
+  if (targetm.sched.alloc_sched_context)
+    {
+      save->be_saved_data = targetm.sched.alloc_sched_context ();
+      targetm.sched.init_sched_context (save->be_saved_data, false);
+    }
+  else
+    save->be_saved_data = NULL;
+
+  save->delay_pair = pair;
+
+  save->next = backtrack_queue;
+  backtrack_queue = save;
+
+  while (pair)
+    {
+      mark_backtrack_feeds (pair->i2, 1);
+      INSN_TICK (pair->i2) = INVALID_TICK;
+      INSN_EXACT_TICK (pair->i2) = clock_var + pair_delay (pair);
+      SHADOW_P (pair->i2) = pair->stages == 0;
+      pair = pair->next_same_i1;
+    }
+}
+
+/* Walk the ready list and all queues. If any insns have unresolved backwards
+   dependencies, these must be cancelled deps, broken by predication.  Set or
+   clear (depending on SET) the DEP_CANCELLED bit in DEP_STATUS.  */
+
+static void
+toggle_cancelled_flags (bool set)
+{
+  int i;
+  sd_iterator_def sd_it;
+  dep_t dep;
+
+  if (ready.n_ready > 0)
+    {
+      rtx *first = ready_lastpos (&ready);
+      for (i = 0; i < ready.n_ready; i++)
+       FOR_EACH_DEP (first[i], SD_LIST_BACK, sd_it, dep)
+         if (!DEBUG_INSN_P (DEP_PRO (dep)))
+           {
+             if (set)
+               DEP_STATUS (dep) |= DEP_CANCELLED;
+             else
+               DEP_STATUS (dep) &= ~DEP_CANCELLED;
+           }
+    }
+  for (i = 0; i <= max_insn_queue_index; i++)
+    {
+      int q = NEXT_Q_AFTER (q_ptr, i);
+      rtx link;
+      for (link = insn_queue[q]; link; link = XEXP (link, 1))
+       {
+         rtx insn = XEXP (link, 0);
+         FOR_EACH_DEP (insn, SD_LIST_BACK, sd_it, dep)
+           if (!DEBUG_INSN_P (DEP_PRO (dep)))
+             {
+               if (set)
+                 DEP_STATUS (dep) |= DEP_CANCELLED;
+               else
+                 DEP_STATUS (dep) &= ~DEP_CANCELLED;
+             }
+       }
+    }
+}
+
+/* Pop entries from the SCHEDULED_INSNS vector up to and including INSN.
+   Restore their dependencies to an unresolved state, and mark them as
+   queued nowhere.  */
+
+static void
+unschedule_insns_until (rtx insn)
+{
+  VEC (rtx, heap) *recompute_vec;
+
+  recompute_vec = VEC_alloc (rtx, heap, 0);
+
+  /* Make two passes over the insns to be unscheduled.  First, we clear out
+     dependencies and other trivial bookkeeping.  */
+  for (;;)
+    {
+      rtx last;
+      sd_iterator_def sd_it;
+      dep_t dep;
+
+      last = VEC_pop (rtx, scheduled_insns);
+
+      /* This will be changed by restore_backtrack_point if the insn is in
+        any queue.  */
+      QUEUE_INDEX (last) = QUEUE_NOWHERE;
+      if (last != insn)
+       INSN_TICK (last) = INVALID_TICK;
+
+      if (modulo_ii > 0 && INSN_UID (last) < modulo_iter0_max_uid)
+       modulo_insns_scheduled--;
+
+      for (sd_it = sd_iterator_start (last, SD_LIST_RES_FORW);
+          sd_iterator_cond (&sd_it, &dep);)
+       {
+         rtx con = DEP_CON (dep);
+         sd_unresolve_dep (sd_it);
+         if (!MUST_RECOMPUTE_SPEC_P (con))
+           {
+             MUST_RECOMPUTE_SPEC_P (con) = 1;
+             VEC_safe_push (rtx, heap, recompute_vec, con);
+           }
+       }
+
+      if (last == insn)
+       break;
+    }
+
+  /* A second pass, to update ready and speculation status for insns
+     depending on the unscheduled ones.  The first pass must have
+     popped the scheduled_insns vector up to the point where we
+     restart scheduling, as recompute_todo_spec requires it to be
+     up-to-date.  */
+  while (!VEC_empty (rtx, recompute_vec))
+    {
+      rtx con;
+
+      con = VEC_pop (rtx, recompute_vec);
+      MUST_RECOMPUTE_SPEC_P (con) = 0;
+      if (!sd_lists_empty_p (con, SD_LIST_HARD_BACK))
+       {
+         TODO_SPEC (con) = HARD_DEP;
+         INSN_TICK (con) = INVALID_TICK;
+         if (PREDICATED_PAT (con) != NULL_RTX)
+           haifa_change_pattern (con, ORIG_PAT (con));
+       }
+      else if (QUEUE_INDEX (con) != QUEUE_SCHEDULED)
+       TODO_SPEC (con) = recompute_todo_spec (con);
+    }
+  VEC_free (rtx, heap, recompute_vec);
+}
+
+/* Restore scheduler state from the topmost entry on the backtracking queue.
+   PSCHED_BLOCK_P points to the local data of schedule_block that we must
+   overwrite with the saved data.
+   The caller must already have called unschedule_insns_until.  */
+
+static void
+restore_last_backtrack_point (struct sched_block_state *psched_block)
+{
+  rtx link;
+  int i;
+  struct haifa_saved_data *save = backtrack_queue;
+
+  backtrack_queue = save->next;
+
+  if (current_sched_info->restore_state)
+    (*current_sched_info->restore_state) (save->fe_saved_data);
+
+  if (targetm.sched.alloc_sched_context)
+    {
+      targetm.sched.set_sched_context (save->be_saved_data);
+      targetm.sched.free_sched_context (save->be_saved_data);
+    }
+
+  /* Clear the QUEUE_INDEX of everything in the ready list or one
+     of the queues.  */
+  if (ready.n_ready > 0)
+    {
+      rtx *first = ready_lastpos (&ready);
+      for (i = 0; i < ready.n_ready; i++)
+       {
+         rtx insn = first[i];
+         QUEUE_INDEX (insn) = QUEUE_NOWHERE;
+         INSN_TICK (insn) = INVALID_TICK;
+       }
+    }
+  for (i = 0; i <= max_insn_queue_index; i++)
+    {
+      int q = NEXT_Q_AFTER (q_ptr, i);
+
+      for (link = insn_queue[q]; link; link = XEXP (link, 1))
+       {
+         rtx x = XEXP (link, 0);
+         QUEUE_INDEX (x) = QUEUE_NOWHERE;
+         INSN_TICK (x) = INVALID_TICK;
+       }
+      free_INSN_LIST_list (&insn_queue[q]);
+    }
+
+  free (ready.vec);
+  ready = save->ready;
+
+  if (ready.n_ready > 0)
+    {
+      rtx *first = ready_lastpos (&ready);
+      for (i = 0; i < ready.n_ready; i++)
+       {
+         rtx insn = first[i];
+         QUEUE_INDEX (insn) = QUEUE_READY;
+         TODO_SPEC (insn) = recompute_todo_spec (insn);
+         INSN_TICK (insn) = save->clock_var;
+       }
+    }
+
+  q_ptr = 0;
+  q_size = save->q_size;
+  for (i = 0; i <= max_insn_queue_index; i++)
+    {
+      int q = NEXT_Q_AFTER (q_ptr, i);
+
+      insn_queue[q] = save->insn_queue[q];
+
+      for (link = insn_queue[q]; link; link = XEXP (link, 1))
+       {
+         rtx x = XEXP (link, 0);
+         QUEUE_INDEX (x) = i;
+         TODO_SPEC (x) = recompute_todo_spec (x);
+         INSN_TICK (x) = save->clock_var + i;
+       }
+    }
+  free (save->insn_queue);
+
+  toggle_cancelled_flags (true);
+
+  clock_var = save->clock_var;
+  last_clock_var = save->last_clock_var;
+  cycle_issued_insns = save->cycle_issued_insns;
+  last_scheduled_insn = save->last_scheduled_insn;
+  last_nondebug_scheduled_insn = save->last_nondebug_scheduled_insn;
+
+  *psched_block = save->sched_block;
+
+  memcpy (curr_state, save->curr_state, dfa_state_size);
+  free (save->curr_state);
+
+  mark_backtrack_feeds (save->delay_pair->i2, 0);
+
+  free (save);
+
+  for (save = backtrack_queue; save; save = save->next)
+    {
+      mark_backtrack_feeds (save->delay_pair->i2, 1);
+    }
+}
+
+/* Discard all data associated with the topmost entry in the backtrack
+   queue.  If RESET_TICK is false, we just want to free the data.  If true,
+   we are doing this because we discovered a reason to backtrack.  In the
+   latter case, also reset the INSN_TICK for the shadow insn.  */
+static void
+free_topmost_backtrack_point (bool reset_tick)
+{
+  struct haifa_saved_data *save = backtrack_queue;
+  int i;
+
+  backtrack_queue = save->next;
+
+  if (reset_tick)
+    {
+      struct delay_pair *pair = save->delay_pair;
+      while (pair)
+       {
+         INSN_TICK (pair->i2) = INVALID_TICK;
+         INSN_EXACT_TICK (pair->i2) = INVALID_TICK;
+         pair = pair->next_same_i1;
+       }
+    }
+  if (targetm.sched.free_sched_context)
+    targetm.sched.free_sched_context (save->be_saved_data);
+  if (current_sched_info->restore_state)
+    free (save->fe_saved_data);
+  for (i = 0; i <= max_insn_queue_index; i++)
+    free_INSN_LIST_list (&save->insn_queue[i]);
+  free (save->insn_queue);
+  free (save->curr_state);
+  free (save->ready.vec);
+  free (save);
+}
+
+/* Free the entire backtrack queue.  */
+static void
+free_backtrack_queue (void)
+{
+  while (backtrack_queue)
+    free_topmost_backtrack_point (false);
+}
+
+/* Compute INSN_TICK_ESTIMATE for INSN.  PROCESSED is a bitmap of
+   instructions we've previously encountered, a set bit prevents
+   recursion.  BUDGET is a limit on how far ahead we look, it is
+   reduced on recursive calls.  Return true if we produced a good
+   estimate, or false if we exceeded the budget.  */
+static bool
+estimate_insn_tick (bitmap processed, rtx insn, int budget)
+{
+  sd_iterator_def sd_it;
+  dep_t dep;
+  int earliest = INSN_TICK (insn);
+
+  FOR_EACH_DEP (insn, SD_LIST_BACK, sd_it, dep)
+    {
+      rtx pro = DEP_PRO (dep);
+      int t;
+
+      if (DEP_STATUS (dep) & DEP_CANCELLED)
+       continue;
+
+      if (QUEUE_INDEX (pro) == QUEUE_SCHEDULED)
+       gcc_assert (INSN_TICK (pro) + dep_cost (dep) <= INSN_TICK (insn));
+      else
+       {
+         int cost = dep_cost (dep);
+         if (cost >= budget)
+           return false;
+         if (!bitmap_bit_p (processed, INSN_LUID (pro)))
+           {
+             if (!estimate_insn_tick (processed, pro, budget - cost))
+               return false;
+           }
+         gcc_assert (INSN_TICK_ESTIMATE (pro) != INVALID_TICK);
+         t = INSN_TICK_ESTIMATE (pro) + cost;
+         if (earliest == INVALID_TICK || t > earliest)
+           earliest = t;
+       }
+    }
+  bitmap_set_bit (processed, INSN_LUID (insn));
+  INSN_TICK_ESTIMATE (insn) = earliest;
+  return true;
+}
+
+/* Examine the pair of insns in P, and estimate (optimistically, assuming
+   infinite resources) the cycle in which the delayed shadow can be issued.
+   Return the number of cycles that must pass before the real insn can be
+   issued in order to meet this constraint.  */
+static int
+estimate_shadow_tick (struct delay_pair *p)
+{
+  bitmap_head processed;
+  int t;
+  bool cutoff;
+  bitmap_initialize (&processed, 0);
+
+  cutoff = !estimate_insn_tick (&processed, p->i2,
+                               max_insn_queue_index + pair_delay (p));
+  bitmap_clear (&processed);
+  if (cutoff)
+    return max_insn_queue_index;
+  t = INSN_TICK_ESTIMATE (p->i2) - (clock_var + pair_delay (p) + 1);
+  if (t > 0)
+    return t;
+  return 0;
+}
+
+/* If INSN has no unresolved backwards dependencies, add it to the schedule and
+   recursively resolve all its forward dependencies.  */
+static void
+resolve_dependencies (rtx insn)
+{
+  sd_iterator_def sd_it;
+  dep_t dep;
+
+  /* Don't use sd_lists_empty_p; it ignores debug insns.  */
+  if (DEPS_LIST_FIRST (INSN_HARD_BACK_DEPS (insn)) != NULL
+      || DEPS_LIST_FIRST (INSN_SPEC_BACK_DEPS (insn)) != NULL)
+    return;
 
-  while (insn != tail && NOTE_NOT_BB_P (insn))
-    {
-      rtx next = NEXT_INSN (insn);
-      basic_block bb = BLOCK_FOR_INSN (insn);
+  if (sched_verbose >= 4)
+    fprintf (sched_dump, ";;\tquickly resolving %d\n", INSN_UID (insn));
 
-      /* Delete the note from its current position.  */
-      if (prev)
-       NEXT_INSN (prev) = next;
-      if (next)
-       PREV_INSN (next) = prev;
+  if (QUEUE_INDEX (insn) >= 0)
+    queue_remove (insn);
 
-      if (bb)
-        {
-          /* Basic block can begin with either LABEL or
-             NOTE_INSN_BASIC_BLOCK.  */
-          gcc_assert (BB_HEAD (bb) != insn);
+  VEC_safe_push (rtx, heap, scheduled_insns, insn);
 
-          /* Check if we are removing last insn in the BB.  */
-          if (BB_END (bb) == insn)
-            BB_END (bb) = prev;
-        }
+  /* Update dependent instructions.  */
+  for (sd_it = sd_iterator_start (insn, SD_LIST_FORW);
+       sd_iterator_cond (&sd_it, &dep);)
+    {
+      rtx next = DEP_CON (dep);
 
-      /* See sched_analyze to see how these are handled.  */
-      if (NOTE_KIND (insn) != NOTE_INSN_EH_REGION_BEG
-         && NOTE_KIND (insn) != NOTE_INSN_EH_REGION_END)
-        add_to_note_list (insn, &note_list);
+      if (sched_verbose >= 4)
+       fprintf (sched_dump, ";;\t\tdep %d against %d\n", INSN_UID (insn),
+                INSN_UID (next));
 
-      insn = next;
-    }
+      /* Resolve the dependence between INSN and NEXT.
+        sd_resolve_dep () moves current dep to another list thus
+        advancing the iterator.  */
+      sd_resolve_dep (sd_it);
 
-  if (insn == tail)
-    {
-      gcc_assert (sel_sched_p ());
-      return prev;
+      if (!IS_SPECULATION_BRANCHY_CHECK_P (insn))
+       {
+         resolve_dependencies (next);
+       }
+      else
+       /* Check always has only one forward dependence (to the first insn in
+          the recovery block), therefore, this will be executed only once.  */
+       {
+         gcc_assert (sd_lists_empty_p (insn, SD_LIST_FORW));
+       }
     }
-
-  return insn;
 }
 
+
 /* Return the head and tail pointers of ebb starting at BEG and ending
    at END.  */
 void
@@ -1425,6 +2977,31 @@ get_ebb_head_tail (basic_block beg, basic_block end, rtx *headp, rtx *tailp)
   while (beg_head != beg_tail)
     if (NOTE_P (beg_head))
       beg_head = NEXT_INSN (beg_head);
+    else if (DEBUG_INSN_P (beg_head))
+      {
+       rtx note, next;
+
+       for (note = NEXT_INSN (beg_head);
+            note != beg_tail;
+            note = next)
+         {
+           next = NEXT_INSN (note);
+           if (NOTE_P (note))
+             {
+               if (sched_verbose >= 9)
+                 fprintf (sched_dump, "reorder %i\n", INSN_UID (note));
+
+               reorder_insns_nobb (note, note, PREV_INSN (beg_head));
+
+               if (BLOCK_FOR_INSN (note) != beg)
+                 df_insn_change_bb (note, beg);
+             }
+           else if (!DEBUG_INSN_P (note))
+             break;
+         }
+
+       break;
+      }
     else
       break;
 
@@ -1438,6 +3015,34 @@ get_ebb_head_tail (basic_block beg, basic_block end, rtx *headp, rtx *tailp)
   while (end_head != end_tail)
     if (NOTE_P (end_tail))
       end_tail = PREV_INSN (end_tail);
+    else if (DEBUG_INSN_P (end_tail))
+      {
+       rtx note, prev;
+
+       for (note = PREV_INSN (end_tail);
+            note != end_head;
+            note = prev)
+         {
+           prev = PREV_INSN (note);
+           if (NOTE_P (note))
+             {
+               if (sched_verbose >= 9)
+                 fprintf (sched_dump, "reorder %i\n", INSN_UID (note));
+
+               reorder_insns_nobb (note, note, end_tail);
+
+               if (end_tail == BB_END (end))
+                 BB_END (end) = note;
+
+               if (BLOCK_FOR_INSN (note) != end)
+                 df_insn_change_bb (note, end);
+             }
+           else if (!DEBUG_INSN_P (note))
+             break;
+         }
+
+       break;
+      }
     else
       break;
 
@@ -1458,62 +3063,6 @@ no_real_insns_p (const_rtx head, const_rtx tail)
   return 1;
 }
 
-/* Delete notes between HEAD and TAIL and put them in the chain
-   of notes ended by NOTE_LIST.  */
-static void
-rm_other_notes (rtx head, rtx tail)
-{
-  rtx next_tail;
-  rtx insn;
-
-  note_list = 0;
-  if (head == tail && (! INSN_P (head)))
-    return;
-
-  next_tail = NEXT_INSN (tail);
-  for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
-    {
-      rtx prev;
-
-      /* Farm out notes, and maybe save them in NOTE_LIST.
-         This is needed to keep the debugger from
-         getting completely deranged.  */
-      if (NOTE_NOT_BB_P (insn))
-       {
-         prev = insn;
-         insn = unlink_other_notes (insn, next_tail);
-
-         gcc_assert ((sel_sched_p ()
-                      || prev != tail) && prev != head && insn != next_tail);
-       }
-    }
-}
-
-/* Same as above, but also process REG_SAVE_NOTEs of HEAD.  */
-void
-remove_notes (rtx head, rtx tail)
-{
-  /* rm_other_notes only removes notes which are _inside_ the
-     block---that is, it won't remove notes before the first real insn
-     or after the last real insn of the block.  So if the first insn
-     has a REG_SAVE_NOTE which would otherwise be emitted before the
-     insn, it is redundant with the note before the start of the
-     block, and so we have to take it out.  */
-  if (INSN_P (head))
-    {
-      rtx note;
-
-      for (note = REG_NOTES (head); note; note = XEXP (note, 1))
-       if (REG_NOTE_KIND (note) == REG_SAVE_NOTE)
-         remove_note (head, note);
-    }
-
-  /* Remove remaining note insns from the block, save them in
-     note_list.  These notes are restored at the end of
-     schedule_block ().  */
-  rm_other_notes (head, tail);
-}
-
 /* Restore-other-notes: NOTE_LIST is the end of a chain of notes
    previously found among the insns.  Insert them just before HEAD.  */
 rtx
@@ -1550,66 +3099,6 @@ restore_other_notes (rtx head, basic_block head_bb)
   return head;
 }
 
-/* Functions for computation of registers live/usage info.  */
-
-/* This function looks for a new register being defined.
-   If the destination register is already used by the source,
-   a new register is not needed.  */
-static int
-find_set_reg_weight (const_rtx x)
-{
-  if (GET_CODE (x) == CLOBBER
-      && register_operand (SET_DEST (x), VOIDmode))
-    return 1;
-  if (GET_CODE (x) == SET
-      && register_operand (SET_DEST (x), VOIDmode))
-    {
-      if (REG_P (SET_DEST (x)))
-       {
-         if (!reg_mentioned_p (SET_DEST (x), SET_SRC (x)))
-           return 1;
-         else
-           return 0;
-       }
-      return 1;
-    }
-  return 0;
-}
-
-/* Calculate INSN_REG_WEIGHT for INSN.  */
-static void
-find_insn_reg_weight (const_rtx insn)
-{
-  int reg_weight = 0;
-  rtx x;
-  
-  /* Handle register life information.  */
-  if (! INSN_P (insn))
-    return;
-  
-  /* Increment weight for each register born here.  */
-  x = PATTERN (insn);
-  reg_weight += find_set_reg_weight (x);
-  if (GET_CODE (x) == PARALLEL)
-    {
-      int j;
-      for (j = XVECLEN (x, 0) - 1; j >= 0; j--)
-       {
-         x = XVECEXP (PATTERN (insn), 0, j);
-         reg_weight += find_set_reg_weight (x);
-       }
-    }
-  /* Decrement weight for each register that dies here.  */
-  for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
-    {
-      if (REG_NOTE_KIND (x) == REG_DEAD
-         || REG_NOTE_KIND (x) == REG_UNUSED)
-       reg_weight--;
-    }
-  
-  INSN_REG_WEIGHT (insn) = reg_weight;
-}
-
 /* Move insns that became ready to fire from queue to ready list.  */
 
 static void
@@ -1622,9 +3111,16 @@ queue_to_ready (struct ready_list *ready)
   q_ptr = NEXT_Q (q_ptr);
 
   if (dbg_cnt (sched_insn) == false)
-    /* If debug counter is activated do not requeue insn next after
-       last_scheduled_insn.  */
-    skip_insn = next_nonnote_insn (last_scheduled_insn);
+    {
+      /* If debug counter is activated do not requeue the first
+        nonscheduled insn.  */
+      skip_insn = nonscheduled_insns_begin;
+      do
+       {
+         skip_insn = next_nonnote_nondebug_insn (skip_insn);
+       }
+      while (QUEUE_INDEX (skip_insn) == QUEUE_SCHEDULED);
+    }
   else
     skip_insn = NULL_RTX;
 
@@ -1642,14 +3138,10 @@ queue_to_ready (struct ready_list *ready)
       /* If the ready list is full, delay the insn for 1 cycle.
         See the comment in schedule_block for the rationale.  */
       if (!reload_completed
-         && ready->n_ready > MAX_SCHED_READY_INSNS
+         && ready->n_ready - ready->n_debug > MAX_SCHED_READY_INSNS
          && !SCHED_GROUP_P (insn)
          && insn != skip_insn)
-       {
-         if (sched_verbose >= 2)
-           fprintf (sched_dump, "requeued because ready full\n");
-         queue_insn (insn, 1);
-       }
+       queue_insn (insn, 1, "ready full");
       else
        {
          ready_add (ready, insn, false);
@@ -1698,35 +3190,31 @@ queue_to_ready (struct ready_list *ready)
 }
 
 /* Used by early_queue_to_ready.  Determines whether it is "ok" to
-   prematurely move INSN from the queue to the ready list.  Currently, 
-   if a target defines the hook 'is_costly_dependence', this function 
+   prematurely move INSN from the queue to the ready list.  Currently,
+   if a target defines the hook 'is_costly_dependence', this function
    uses the hook to check whether there exist any dependences which are
-   considered costly by the target, between INSN and other insns that 
+   considered costly by the target, between INSN and other insns that
    have already been scheduled.  Dependences are checked up to Y cycles
    back, with default Y=1; The flag -fsched-stalled-insns-dep=Y allows
-   controlling this value. 
-   (Other considerations could be taken into account instead (or in 
+   controlling this value.
+   (Other considerations could be taken into account instead (or in
    addition) depending on user flags and target hooks.  */
 
-static bool 
+static bool
 ok_for_early_queue_removal (rtx insn)
 {
-  int n_cycles;
-  rtx prev_insn = last_scheduled_insn;
-
   if (targetm.sched.is_costly_dependence)
     {
+      rtx prev_insn;
+      int n_cycles;
+      int i = VEC_length (rtx, scheduled_insns);
       for (n_cycles = flag_sched_stalled_insns_dep; n_cycles; n_cycles--)
        {
-         for ( ; prev_insn; prev_insn = PREV_INSN (prev_insn))
+         while (i-- > 0)
            {
              int cost;
 
-             if (prev_insn == current_sched_info->prev_head)
-               {
-                 prev_insn = NULL;
-                 break;
-               }
+             prev_insn = VEC_index (rtx, scheduled_insns, i);
 
              if (!NOTE_P (prev_insn))
                {
@@ -1748,9 +3236,8 @@ ok_for_early_queue_removal (rtx insn)
                break;
            }
 
-         if (!prev_insn) 
+         if (i == 0)
            break;
-         prev_insn = PREV_INSN (prev_insn);     
        }
     }
 
@@ -1761,7 +3248,7 @@ ok_for_early_queue_removal (rtx insn)
 /* Remove insns from the queue, before they become "ready" with respect
    to FU latency considerations.  */
 
-static int 
+static int
 early_queue_to_ready (state_t state, struct ready_list *ready)
 {
   rtx insn;
@@ -1775,20 +3262,20 @@ early_queue_to_ready (state_t state, struct ready_list *ready)
   int insns_removed = 0;
 
   /*
-     Flag '-fsched-stalled-insns=X' determines the aggressiveness of this 
-     function: 
+     Flag '-fsched-stalled-insns=X' determines the aggressiveness of this
+     function:
 
-     X == 0: There is no limit on how many queued insns can be removed          
+     X == 0: There is no limit on how many queued insns can be removed
              prematurely.  (flag_sched_stalled_insns = -1).
 
-     X >= 1: Only X queued insns can be removed prematurely in each 
+     X >= 1: Only X queued insns can be removed prematurely in each
             invocation.  (flag_sched_stalled_insns = X).
 
      Otherwise: Early queue removal is disabled.
          (flag_sched_stalled_insns = 0)
   */
 
-  if (! flag_sched_stalled_insns)   
+  if (! flag_sched_stalled_insns)
     return 0;
 
   for (stalls = 0; stalls <= max_insn_queue_index; stalls++)
@@ -1807,7 +3294,7 @@ early_queue_to_ready (state_t state, struct ready_list *ready)
                print_rtl_single (sched_dump, insn);
 
              memcpy (temp_state, state, dfa_state_size);
-             if (recog_memoized (insn) < 0) 
+             if (recog_memoized (insn) < 0)
                /* non-negative to indicate that it's not ready
                   to avoid infinite Q->R->Q->R... */
                cost = 0;
@@ -1818,7 +3305,7 @@ early_queue_to_ready (state_t state, struct ready_list *ready)
                fprintf (sched_dump, "transition cost = %d\n", cost);
 
              move_to_ready = false;
-             if (cost < 0) 
+             if (cost < 0)
                {
                  move_to_ready = ok_for_early_queue_removal (insn);
                  if (move_to_ready == true)
@@ -1827,7 +3314,7 @@ early_queue_to_ready (state_t state, struct ready_list *ready)
                      q_size -= 1;
                      ready_add (ready, insn, false);
 
-                     if (prev_link)   
+                     if (prev_link)
                        XEXP (prev_link, 1) = next_link;
                      else
                        insn_queue[NEXT_Q_AFTER (q_ptr, stalls)] = next_link;
@@ -1851,11 +3338,11 @@ early_queue_to_ready (state_t state, struct ready_list *ready)
 
              link = next_link;
            } /* while link */
-       } /* if link */    
+       } /* if link */
 
     } /* for stalls.. */
 
-  return insns_removed; 
+  return insns_removed;
 }
 
 
@@ -1875,15 +3362,24 @@ debug_ready_list (struct ready_list *ready)
 
   p = ready_lastpos (ready);
   for (i = 0; i < ready->n_ready; i++)
-    fprintf (sched_dump, "  %s", (*current_sched_info->print_insn) (p[i], 0));
+    {
+      fprintf (sched_dump, "  %s:%d",
+              (*current_sched_info->print_insn) (p[i], 0),
+              INSN_LUID (p[i]));
+      if (sched_pressure_p)
+       fprintf (sched_dump, "(cost=%d",
+                INSN_REG_PRESSURE_EXCESS_COST_CHANGE (p[i]));
+      if (INSN_TICK (p[i]) > clock_var)
+       fprintf (sched_dump, ":delay=%d", INSN_TICK (p[i]) - clock_var);
+      if (sched_pressure_p)
+       fprintf (sched_dump, ")");
+    }
   fprintf (sched_dump, "\n");
 }
 
-/* Search INSN for REG_SAVE_NOTE note pairs for
-   NOTE_INSN_EHREGION_{BEG,END}; and convert them back into
-   NOTEs.  The REG_SAVE_NOTE note following first one is contains the
-   saved value for NOTE_BLOCK_NUMBER which is useful for
-   NOTE_INSN_EH_REGION_{BEG,END} NOTEs.  */
+/* Search INSN for REG_SAVE_NOTE notes and convert them back into insn
+   NOTEs.  This is used for NOTE_INSN_EPILOGUE_BEG, so that sched-ebb
+   replaces the epilogue note in the correct basic block.  */
 void
 reemit_notes (rtx insn)
 {
@@ -1893,7 +3389,7 @@ reemit_notes (rtx insn)
     {
       if (REG_NOTE_KIND (note) == REG_SAVE_NOTE)
        {
-         enum insn_note note_type = INTVAL (XEXP (note, 0));
+         enum insn_note note_type = (enum insn_note) INTVAL (XEXP (note, 0));
 
          last = emit_note_before (note_type, last);
          remove_note (insn, note);
@@ -1912,9 +3408,9 @@ move_insn (rtx insn, rtx last, rtx nt)
       int jump_p = 0;
 
       bb = BLOCK_FOR_INSN (insn);
+
       /* BB_HEAD is either LABEL or NOTE.  */
-      gcc_assert (BB_HEAD (bb) != insn);      
+      gcc_assert (BB_HEAD (bb) != insn);
 
       if (BB_END (bb) == insn)
        /* If this is last instruction in BB, move end marker one
@@ -1928,7 +3424,7 @@ move_insn (rtx insn, rtx last, rtx nt)
                          && IS_SPECULATION_BRANCHY_CHECK_P (insn))
                      || (common_sched_info->sched_pass_id
                          == SCHED_EBB_PASS));
-         
+
          gcc_assert (BLOCK_FOR_INSN (PREV_INSN (insn)) == bb);
 
          BB_END (bb) = PREV_INSN (insn);
@@ -1949,7 +3445,7 @@ move_insn (rtx insn, rtx last, rtx nt)
              && (LABEL_P (note)
                  || BARRIER_P (note)))
            note = NEXT_INSN (note);
-      
+
          gcc_assert (NOTE_INSN_BASIC_BLOCK_P (note));
        }
       else
@@ -1977,15 +3473,38 @@ move_insn (rtx insn, rtx last, rtx nt)
        }
 
       df_insn_change_bb (insn, bb);
-  
+
       /* Update BB_END, if needed.  */
       if (BB_END (bb) == last)
-       BB_END (bb) = insn;  
+       BB_END (bb) = insn;
     }
 
-  SCHED_GROUP_P (insn) = 0;  
+  SCHED_GROUP_P (insn) = 0;
+}
+
+/* Return true if scheduling INSN will finish current clock cycle.  */
+static bool
+insn_finishes_cycle_p (rtx insn)
+{
+  if (SCHED_GROUP_P (insn))
+    /* After issuing INSN, rest of the sched_group will be forced to issue
+       in order.  Don't make any plans for the rest of cycle.  */
+    return true;
+
+  /* Finishing the block will, apparently, finish the cycle.  */
+  if (current_sched_info->insn_finishes_block_p
+      && current_sched_info->insn_finishes_block_p (insn))
+    return true;
+
+  return false;
 }
 
+/* Define type for target data used in multipass scheduling.  */
+#ifndef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DATA_T
+# define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DATA_T int
+#endif
+typedef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DATA_T first_cycle_multipass_data_t;
+
 /* The following structure describe an entry of the stack of choices.  */
 struct choice_entry
 {
@@ -1997,17 +3516,14 @@ struct choice_entry
   int n;
   /* State after issuing the insn.  */
   state_t state;
+  /* Target-specific data.  */
+  first_cycle_multipass_data_t target_data;
 };
 
 /* The following array is used to implement a stack of choices used in
    function max_issue.  */
 static struct choice_entry *choice_stack;
 
-/* The following variable value is number of essential insns issued on
-   the current cycle.  An insn is essential one if it changes the
-   processors state.  */
-int cycle_issued_insns;
-
 /* This holds the value of the target dfa_lookahead hook.  */
 int dfa_lookahead;
 
@@ -2036,8 +3552,7 @@ static int cached_issue_rate = 0;
    insns is insns with the best rank (the first insn in READY).  To
    make this function tries different samples of ready insns.  READY
    is current queue `ready'.  Global array READY_TRY reflects what
-   insns are already issued in this try.  MAX_POINTS is the sum of points
-   of all instructions in READY.  The function stops immediately,
+   insns are already issued in this try.  The function stops immediately,
    if it reached the such a solution, that all instruction can be issued.
    INDEX will contain index of the best insn in READY.  The following
    function is used only for first cycle multipass scheduling.
@@ -2048,9 +3563,9 @@ static int cached_issue_rate = 0;
    CLOBBERs, etc must be filtered elsewhere.  */
 int
 max_issue (struct ready_list *ready, int privileged_n, state_t state,
-          int *index)
+          bool first_cycle_insn_p, int *index)
 {
-  int n, i, all, n_ready, best, delay, tries_num, points = -1, max_points;
+  int n, i, all, n_ready, best, delay, tries_num;
   int more_issue;
   struct choice_entry *top;
   rtx insn;
@@ -2069,19 +3584,9 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
     }
 
   /* Init max_points.  */
-  max_points = 0;
   more_issue = issue_rate - cycle_issued_insns;
   gcc_assert (more_issue >= 0);
 
-  for (i = 0; i < n_ready; i++)
-    if (!ready_try [i])
-      {
-       if (more_issue-- > 0)
-         max_points += ISSUE_POINTS (ready_element (ready, i));
-       else
-         break;
-      }
-
   /* The number of the issued insns in the best solution.  */
   best = 0;
 
@@ -2091,6 +3596,10 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
   memcpy (top->state, state, dfa_state_size);
   top->rest = dfa_lookahead;
   top->n = 0;
+  if (targetm.sched.first_cycle_multipass_begin)
+    targetm.sched.first_cycle_multipass_begin (&top->target_data,
+                                              ready_try, n_ready,
+                                              first_cycle_insn_p);
 
   /* Count the number of the insns to search among.  */
   for (all = i = 0; i < n_ready; i++)
@@ -2105,12 +3614,17 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
       if (/* If we've reached a dead end or searched enough of what we have
             been asked...  */
          top->rest == 0
-         /* Or have nothing else to try.  */
-         || i >= n_ready)
+         /* or have nothing else to try...  */
+         || i >= n_ready
+         /* or should not issue more.  */
+         || top->n >= more_issue)
        {
          /* ??? (... || i == n_ready).  */
          gcc_assert (i <= n_ready);
 
+         /* We should not issue more than issue_rate instructions.  */
+         gcc_assert (top->n <= more_issue);
+
          if (top == choice_stack)
            break;
 
@@ -2120,7 +3634,8 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
                {
                  n = privileged_n;
                  /* Try to find issued privileged insn.  */
-                 while (n && !ready_try[--n]);
+                 while (n && !ready_try[--n])
+                   ;
                }
 
              if (/* If all insns are equally good...  */
@@ -2133,8 +3648,7 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
                  /* This is the index of the insn issued first in this
                     solution.  */
                  *index = choice_stack [1].index;
-                 points = top->n;
-                 if (top->n == max_points || best == all)
+                 if (top->n == more_issue || best == all)
                    break;
                }
            }
@@ -2145,6 +3659,11 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
 
          /* Backtrack.  */
          ready_try [i] = 0;
+
+         if (targetm.sched.first_cycle_multipass_backtrack)
+           targetm.sched.first_cycle_multipass_backtrack (&top->target_data,
+                                                          ready_try, n_ready);
+
          top--;
          memcpy (state, top->state, dfa_state_size);
        }
@@ -2157,14 +3676,17 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
          delay = state_transition (state, insn);
          if (delay < 0)
            {
-             if (state_dead_lock_p (state))
+             if (state_dead_lock_p (state)
+                 || insn_finishes_cycle_p (insn))
+               /* We won't issue any more instructions in the next
+                  choice_state.  */
                top->rest = 0;
              else
                top->rest--;
 
              n = top->n;
              if (memcmp (top->state, state, dfa_state_size) != 0)
-               n += ISSUE_POINTS (insn);
+               n++;
 
              /* Advance to the next choice_entry.  */
              top++;
@@ -2173,8 +3695,15 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
              top->index = i;
              top->n = n;
              memcpy (top->state, state, dfa_state_size);
-
              ready_try [i] = 1;
+
+             if (targetm.sched.first_cycle_multipass_issue)
+               targetm.sched.first_cycle_multipass_issue (&top->target_data,
+                                                          ready_try, n_ready,
+                                                          insn,
+                                                          &((top - 1)
+                                                            ->target_data));
+
              i = -1;
            }
        }
@@ -2183,8 +3712,13 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
       i++;
     }
 
+  if (targetm.sched.first_cycle_multipass_end)
+    targetm.sched.first_cycle_multipass_end (best != 0
+                                            ? &choice_stack[1].target_data
+                                            : NULL);
+
   /* Restore the original state of the DFA.  */
-  memcpy (state, choice_stack->state, dfa_state_size);  
+  memcpy (state, choice_stack->state, dfa_state_size);
 
   return best;
 }
@@ -2197,19 +3731,24 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
    0 if INSN_PTR is set to point to the desirable insn,
    1 if choose_ready () should be restarted without advancing the cycle.  */
 static int
-choose_ready (struct ready_list *ready, rtx *insn_ptr)
+choose_ready (struct ready_list *ready, bool first_cycle_insn_p,
+             rtx *insn_ptr)
 {
   int lookahead;
 
   if (dbg_cnt (sched_insn) == false)
     {
-      rtx insn;
-
-      insn = next_nonnote_insn (last_scheduled_insn);
+      rtx insn = nonscheduled_insns_begin;
+      do
+       {
+         insn = next_nonnote_insn (insn);
+       }
+      while (QUEUE_INDEX (insn) == QUEUE_SCHEDULED);
 
       if (QUEUE_INDEX (insn) == QUEUE_READY)
        /* INSN is in the ready_list.  */
        {
+         nonscheduled_insns_begin = insn;
          ready_remove_insn (insn);
          *insn_ptr = insn;
          return 0;
@@ -2223,9 +3762,14 @@ choose_ready (struct ready_list *ready, rtx *insn_ptr)
 
   if (targetm.sched.first_cycle_multipass_dfa_lookahead)
     lookahead = targetm.sched.first_cycle_multipass_dfa_lookahead ();
-  if (lookahead <= 0 || SCHED_GROUP_P (ready_element (ready, 0)))
+  if (lookahead <= 0 || SCHED_GROUP_P (ready_element (ready, 0))
+      || DEBUG_INSN_P (ready_element (ready, 0)))
     {
-      *insn_ptr = ready_remove_first (ready);
+      if (targetm.sched.dispatch (NULL_RTX, IS_DISPATCH_ON))
+       *insn_ptr = ready_remove_first_dispatch (ready);
+      else
+       *insn_ptr = ready_remove_first (ready);
+
       return 0;
     }
   else
@@ -2235,7 +3779,7 @@ choose_ready (struct ready_list *ready, rtx *insn_ptr)
       rtx insn;
       int try_data = 1, try_control = 1;
       ds_t ts;
-      
+
       insn = ready_element (ready, 0);
       if (INSN_CODE (insn) < 0)
        {
@@ -2254,16 +3798,16 @@ choose_ready (struct ready_list *ready, rtx *insn_ptr)
 
              x = ready_element (ready, i);
              s = TODO_SPEC (x);
-             
+
              if (spec_info->flags & PREFER_NON_DATA_SPEC
                  && !(s & DATA_SPEC))
-               {                 
+               {
                  try_data = 0;
                  if (!(spec_info->flags & PREFER_NON_CONTROL_SPEC)
                      || !try_control)
                    break;
                }
-             
+
              if (spec_info->flags & PREFER_NON_CONTROL_SPEC
                  && !(s & CONTROL_SPEC))
                {
@@ -2284,68 +3828,273 @@ choose_ready (struct ready_list *ready, rtx *insn_ptr)
        /* Discard speculative instruction that stands first in the ready
           list.  */
        {
-         change_queue_index (insn, 1);
-         return 1;
+         change_queue_index (insn, 1);
+         return 1;
+       }
+
+      ready_try[0] = 0;
+
+      for (i = 1; i < ready->n_ready; i++)
+       {
+         insn = ready_element (ready, i);
+
+         ready_try [i]
+           = ((!try_data && (TODO_SPEC (insn) & DATA_SPEC))
+               || (!try_control && (TODO_SPEC (insn) & CONTROL_SPEC)));
+       }
+
+      /* Let the target filter the search space.  */
+      for (i = 1; i < ready->n_ready; i++)
+       if (!ready_try[i])
+         {
+           insn = ready_element (ready, i);
+
+           /* If this insn is recognizable we should have already
+              recognized it earlier.
+              ??? Not very clear where this is supposed to be done.
+              See dep_cost_1.  */
+           gcc_checking_assert (INSN_CODE (insn) >= 0
+                                || recog_memoized (insn) < 0);
+
+           ready_try [i]
+             = (/* INSN_CODE check can be omitted here as it is also done later
+                   in max_issue ().  */
+                INSN_CODE (insn) < 0
+                || (targetm.sched.first_cycle_multipass_dfa_lookahead_guard
+                    && !targetm.sched.first_cycle_multipass_dfa_lookahead_guard
+                    (insn)));
+         }
+
+      if (max_issue (ready, 1, curr_state, first_cycle_insn_p, &index) == 0)
+       {
+         *insn_ptr = ready_remove_first (ready);
+         if (sched_verbose >= 4)
+           fprintf (sched_dump, ";;\t\tChosen insn (but can't issue) : %s \n",
+                     (*current_sched_info->print_insn) (*insn_ptr, 0));
+         return 0;
+       }
+      else
+       {
+         if (sched_verbose >= 4)
+           fprintf (sched_dump, ";;\t\tChosen insn : %s\n",
+                    (*current_sched_info->print_insn)
+                    (ready_element (ready, index), 0));
+
+         *insn_ptr = ready_remove (ready, index);
+         return 0;
+       }
+    }
+}
+
+/* This function is called when we have successfully scheduled a
+   block.  It uses the schedule stored in the scheduled_insns vector
+   to rearrange the RTL.  PREV_HEAD is used as the anchor to which we
+   append the scheduled insns; TAIL is the insn after the scheduled
+   block.  TARGET_BB is the argument passed to schedule_block.  */
+
+static void
+commit_schedule (rtx prev_head, rtx tail, basic_block *target_bb)
+{
+  unsigned int i;
+  rtx insn;
+
+  last_scheduled_insn = prev_head;
+  for (i = 0;
+       VEC_iterate (rtx, scheduled_insns, i, insn);
+       i++)
+    {
+      if (control_flow_insn_p (last_scheduled_insn)
+         || current_sched_info->advance_target_bb (*target_bb, insn))
+       {
+         *target_bb = current_sched_info->advance_target_bb (*target_bb, 0);
+
+         if (sched_verbose)
+           {
+             rtx x;
+
+             x = next_real_insn (last_scheduled_insn);
+             gcc_assert (x);
+             dump_new_block_header (1, *target_bb, x, tail);
+           }
+
+         last_scheduled_insn = bb_note (*target_bb);
+       }
+
+      if (current_sched_info->begin_move_insn)
+       (*current_sched_info->begin_move_insn) (insn, last_scheduled_insn);
+      move_insn (insn, last_scheduled_insn,
+                current_sched_info->next_tail);
+      if (!DEBUG_INSN_P (insn))
+       reemit_notes (insn);
+      last_scheduled_insn = insn;
+    }
+
+  VEC_truncate (rtx, scheduled_insns, 0);
+}
+
+/* Examine all insns on the ready list and queue those which can't be
+   issued in this cycle.  TEMP_STATE is temporary scheduler state we
+   can use as scratch space.  If FIRST_CYCLE_INSN_P is true, no insns
+   have been issued for the current cycle, which means it is valid to
+   issue an asm statement.
+
+   If SHADOWS_ONLY_P is true, we eliminate all real insns and only
+   leave those for which SHADOW_P is true.  If MODULO_EPILOGUE is true,
+   we only leave insns which have an INSN_EXACT_TICK.  */
+
+static void
+prune_ready_list (state_t temp_state, bool first_cycle_insn_p,
+                 bool shadows_only_p, bool modulo_epilogue_p)
+{
+  int i;
+  bool sched_group_found = false;
+
+ restart:
+  for (i = 0; i < ready.n_ready; i++)
+    {
+      rtx insn = ready_element (&ready, i);
+      int cost = 0;
+      const char *reason = "resource conflict";
+
+      if (DEBUG_INSN_P (insn))
+       continue;
+
+      if (SCHED_GROUP_P (insn) && !sched_group_found)
+       {
+         sched_group_found = true;
+         if (i > 0)
+           goto restart;
+       }
+
+      if (sched_group_found && !SCHED_GROUP_P (insn))
+       {
+         cost = 1;
+         reason = "not in sched group";
+       }
+      else if (modulo_epilogue_p && INSN_EXACT_TICK (insn) == INVALID_TICK)
+       {
+         cost = max_insn_queue_index;
+         reason = "not an epilogue insn";
+       }
+      else if (shadows_only_p && !SHADOW_P (insn))
+       {
+         cost = 1;
+         reason = "not a shadow";
+       }
+      else if (recog_memoized (insn) < 0)
+       {
+         if (!first_cycle_insn_p
+             && (GET_CODE (PATTERN (insn)) == ASM_INPUT
+                 || asm_noperands (PATTERN (insn)) >= 0))
+           cost = 1;
+         reason = "asm";
        }
+      else if (sched_pressure_p)
+       cost = 0;
+      else
+       {
+         int delay_cost = 0;
 
-      ready_try[0] = 0;
+         if (delay_htab)
+           {
+             struct delay_pair *delay_entry;
+             delay_entry
+               = (struct delay_pair *)htab_find_with_hash (delay_htab, insn,
+                                                           htab_hash_pointer (insn));
+             while (delay_entry && delay_cost == 0)
+               {
+                 delay_cost = estimate_shadow_tick (delay_entry);
+                 if (delay_cost > max_insn_queue_index)
+                   delay_cost = max_insn_queue_index;
+                 delay_entry = delay_entry->next_same_i1;
+               }
+           }
 
-      for (i = 1; i < ready->n_ready; i++)
+         memcpy (temp_state, curr_state, dfa_state_size);
+         cost = state_transition (temp_state, insn);
+         if (cost < 0)
+           cost = 0;
+         else if (cost == 0)
+           cost = 1;
+         if (cost < delay_cost)
+           {
+             cost = delay_cost;
+             reason = "shadow tick";
+           }
+       }
+      if (cost >= 1)
        {
-         insn = ready_element (ready, i);
-
-         ready_try [i]
-           = ((!try_data && (TODO_SPEC (insn) & DATA_SPEC))
-               || (!try_control && (TODO_SPEC (insn) & CONTROL_SPEC)));
+         ready_remove (&ready, i);
+         queue_insn (insn, cost, reason);
+         goto restart;
        }
+    }
+}
 
-      /* Let the target filter the search space.  */
-      for (i = 1; i < ready->n_ready; i++)
-       if (!ready_try[i])
-         {
-           insn = ready_element (ready, i);
-
-           gcc_assert (INSN_CODE (insn) >= 0
-                       || recog_memoized (insn) < 0);
+/* Called when we detect that the schedule is impossible.  We examine the
+   backtrack queue to find the earliest insn that caused this condition.  */
 
-           ready_try [i]
-             = (/* INSN_CODE check can be omitted here as it is also done later
-                   in max_issue ().  */
-                INSN_CODE (insn) < 0
-                || (targetm.sched.first_cycle_multipass_dfa_lookahead_guard
-                    && !targetm.sched.first_cycle_multipass_dfa_lookahead_guard
-                    (insn)));
-         }
+static struct haifa_saved_data *
+verify_shadows (void)
+{
+  struct haifa_saved_data *save, *earliest_fail = NULL;
+  for (save = backtrack_queue; save; save = save->next)
+    {
+      int t;
+      struct delay_pair *pair = save->delay_pair;
+      rtx i1 = pair->i1;
 
-      if (max_issue (ready, 1, curr_state, &index) == 0)
-       {
-         if (sched_verbose >= 4)
-           fprintf (sched_dump, ";;\t\tChosen none\n");
-         *insn_ptr = ready_remove_first (ready);
-         return 0;
-       }
-      else
+      for (; pair; pair = pair->next_same_i1)
        {
-         if (sched_verbose >= 4)    
-           fprintf (sched_dump, ";;\t\tChosen insn : %s\n",
-                    (*current_sched_info->print_insn)
-                    (ready_element (ready, index), 0));
-          
-         *insn_ptr = ready_remove (ready, index);
-         return 0;
+         rtx i2 = pair->i2;
+
+         if (QUEUE_INDEX (i2) == QUEUE_SCHEDULED)
+           continue;
+
+         t = INSN_TICK (i1) + pair_delay (pair);
+         if (t < clock_var)
+           {
+             if (sched_verbose >= 2)
+               fprintf (sched_dump,
+                        ";;\t\tfailed delay requirements for %d/%d (%d->%d)"
+                        ", not ready\n",
+                        INSN_UID (pair->i1), INSN_UID (pair->i2),
+                        INSN_TICK (pair->i1), INSN_EXACT_TICK (pair->i2));
+             earliest_fail = save;
+             break;
+           }
+         if (QUEUE_INDEX (i2) >= 0)
+           {
+             int queued_for = INSN_TICK (i2);
+
+             if (t < queued_for)
+               {
+                 if (sched_verbose >= 2)
+                   fprintf (sched_dump,
+                            ";;\t\tfailed delay requirements for %d/%d"
+                            " (%d->%d), queued too late\n",
+                            INSN_UID (pair->i1), INSN_UID (pair->i2),
+                            INSN_TICK (pair->i1), INSN_EXACT_TICK (pair->i2));
+                 earliest_fail = save;
+                 break;
+               }
+           }
        }
     }
+
+  return earliest_fail;
 }
 
 /* Use forward list scheduling to rearrange insns of block pointed to by
    TARGET_BB, possibly bringing insns from subsequent blocks in the same
    region.  */
 
-void
+bool
 schedule_block (basic_block *target_bb)
 {
-  int i, first_cycle_insn_p;
-  int can_issue_more;
+  int i;
+  bool success = modulo_ii == 0;
+  struct sched_block_state ls;
   state_t temp_state = NULL;  /* It is used for multipass scheduling.  */
   int sort_p, advance, start_clock_var;
 
@@ -2366,6 +4115,8 @@ schedule_block (basic_block *target_bb)
 
   haifa_recovery_bb_recently_added_p = false;
 
+  backtrack_queue = NULL;
+
   /* Debug info.  */
   if (sched_verbose)
     dump_new_block_header (0, *target_bb, head, tail);
@@ -2375,17 +4126,20 @@ schedule_block (basic_block *target_bb)
   /* Clear the ready list.  */
   ready.first = ready.veclen - 1;
   ready.n_ready = 0;
+  ready.n_debug = 0;
 
   /* It is used for first cycle multipass scheduling.  */
   temp_state = alloca (dfa_state_size);
 
-  if (targetm.sched.md_init)
-    targetm.sched.md_init (sched_dump, sched_verbose, ready.veclen);
+  if (targetm.sched.init)
+    targetm.sched.init (sched_dump, sched_verbose, ready.veclen);
 
   /* We start inserting insns after PREV_HEAD.  */
-  last_scheduled_insn = prev_head;
+  last_scheduled_insn = nonscheduled_insns_begin = prev_head;
+  last_nondebug_scheduled_insn = NULL_RTX;
 
-  gcc_assert (NOTE_P (last_scheduled_insn)
+  gcc_assert ((NOTE_P (last_scheduled_insn)
+              || DEBUG_INSN_P (last_scheduled_insn))
              && BLOCK_FOR_INSN (last_scheduled_insn) == *target_bb);
 
   /* Initialize INSN_QUEUE.  Q_SIZE is the total number of insns in the
@@ -2399,19 +4153,21 @@ schedule_block (basic_block *target_bb)
   /* Start just before the beginning of time.  */
   clock_var = -1;
 
-  /* We need queue and ready lists and clock_var be initialized 
+  /* We need queue and ready lists and clock_var be initialized
      in try_ready () (which is called through init_ready_list ()).  */
   (*current_sched_info->init_ready_list) ();
 
   /* The algorithm is O(n^2) in the number of ready insns at any given
      time in the worst case.  Before reload we are more likely to have
      big lists so truncate them to a reasonable size.  */
-  if (!reload_completed && ready.n_ready > MAX_SCHED_READY_INSNS)
+  if (!reload_completed
+      && ready.n_ready - ready.n_debug > MAX_SCHED_READY_INSNS)
     {
       ready_sort (&ready);
 
-      /* Find first free-standing insn past MAX_SCHED_READY_INSNS.  */
-      for (i = MAX_SCHED_READY_INSNS; i < ready.n_ready; i++)
+      /* Find first free-standing insn past MAX_SCHED_READY_INSNS.
+         If there are debug insns, we know they're first.  */
+      for (i = MAX_SCHED_READY_INSNS + ready.n_debug; i < ready.n_ready; i++)
        if (!SCHED_GROUP_P (ready_element (&ready, i)))
          break;
 
@@ -2425,12 +4181,12 @@ schedule_block (basic_block *target_bb)
 
       /* Delay all insns past it for 1 cycle.  If debug counter is
         activated make an exception for the insn right after
-        last_scheduled_insn.  */
+        nonscheduled_insns_begin.  */
       {
        rtx skip_insn;
 
        if (dbg_cnt (sched_insn) == false)
-         skip_insn = next_nonnote_insn (last_scheduled_insn);
+         skip_insn = next_nonnote_insn (nonscheduled_insns_begin);
        else
          skip_insn = NULL_RTX;
 
@@ -2441,8 +4197,10 @@ schedule_block (basic_block *target_bb)
            insn = ready_remove (&ready, i);
 
            if (insn != skip_insn)
-             queue_insn (insn, 1);
+             queue_insn (insn, 1, "list truncated");
          }
+       if (skip_insn)
+         ready_add (&ready, skip_insn, true);
       }
     }
 
@@ -2453,7 +4211,13 @@ schedule_block (basic_block *target_bb)
 
   advance = 0;
 
+  gcc_assert (VEC_length (rtx, scheduled_insns) == 0);
   sort_p = TRUE;
+  must_backtrack = false;
+  modulo_insns_scheduled = 0;
+
+  ls.modulo_epilogue = false;
+
   /* Loop until all the insns in BB are scheduled.  */
   while ((*current_sched_info->schedule_more_p) ())
     {
@@ -2482,48 +4246,126 @@ schedule_block (basic_block *target_bb)
        }
       while (advance > 0);
 
-      if (sort_p)
+      if (ls.modulo_epilogue)
        {
-         /* Sort the ready list based on priority.  */
-         ready_sort (&ready);
-
-         if (sched_verbose >= 2)
+         int stage = clock_var / modulo_ii;
+         if (stage > modulo_last_stage * 2 + 2)
            {
-             fprintf (sched_dump, ";;\t\tReady list after ready_sort:  ");
-             debug_ready_list (&ready);
+             if (sched_verbose >= 2)
+               fprintf (sched_dump,
+                        ";;\t\tmodulo scheduled succeeded at II %d\n",
+                        modulo_ii);
+             success = true;
+             goto end_schedule;
+           }
+       }
+      else if (modulo_ii > 0)
+       {
+         int stage = clock_var / modulo_ii;
+         if (stage > modulo_max_stages)
+           {
+             if (sched_verbose >= 2)
+               fprintf (sched_dump,
+                        ";;\t\tfailing schedule due to excessive stages\n");
+             goto end_schedule;
+           }
+         if (modulo_n_insns == modulo_insns_scheduled
+             && stage > modulo_last_stage)
+           {
+             if (sched_verbose >= 2)
+               fprintf (sched_dump,
+                        ";;\t\tfound kernel after %d stages, II %d\n",
+                        stage, modulo_ii);
+             ls.modulo_epilogue = true;
            }
        }
 
-      /* Allow the target to reorder the list, typically for
-        better instruction bundling.  */
-      if (sort_p && targetm.sched.reorder
-         && (ready.n_ready == 0
-             || !SCHED_GROUP_P (ready_element (&ready, 0))))
-       can_issue_more =
-         targetm.sched.reorder (sched_dump, sched_verbose,
-                                ready_lastpos (&ready),
-                                &ready.n_ready, clock_var);
-      else
-       can_issue_more = issue_rate;
+      prune_ready_list (temp_state, true, false, ls.modulo_epilogue);
+      if (ready.n_ready == 0)
+       continue;
+      if (must_backtrack)
+       goto do_backtrack;
 
-      first_cycle_insn_p = 1;
+      ls.first_cycle_insn_p = true;
+      ls.shadows_only_p = false;
       cycle_issued_insns = 0;
+      ls.can_issue_more = issue_rate;
       for (;;)
        {
          rtx insn;
          int cost;
-         bool asm_p = false;
+         bool asm_p;
+
+         if (sort_p && ready.n_ready > 0)
+           {
+             /* Sort the ready list based on priority.  This must be
+                done every iteration through the loop, as schedule_insn
+                may have readied additional insns that will not be
+                sorted correctly.  */
+             ready_sort (&ready);
+
+             if (sched_verbose >= 2)
+               {
+                 fprintf (sched_dump, ";;\t\tReady list after ready_sort:  ");
+                 debug_ready_list (&ready);
+               }
+           }
+
+         /* We don't want md sched reorder to even see debug isns, so put
+            them out right away.  */
+         if (ready.n_ready && DEBUG_INSN_P (ready_element (&ready, 0))
+             && (*current_sched_info->schedule_more_p) ())
+           {
+             while (ready.n_ready && DEBUG_INSN_P (ready_element (&ready, 0)))
+               {
+                 rtx insn = ready_remove_first (&ready);
+                 gcc_assert (DEBUG_INSN_P (insn));
+                 (*current_sched_info->begin_schedule_ready) (insn);
+                 VEC_safe_push (rtx, heap, scheduled_insns, insn);
+                 last_scheduled_insn = insn;
+                 advance = schedule_insn (insn);
+                 gcc_assert (advance == 0);
+                 if (ready.n_ready > 0)
+                   ready_sort (&ready);
+               }
+           }
+
+         if (ls.first_cycle_insn_p && !ready.n_ready)
+           break;
+
+       resume_after_backtrack:
+         /* Allow the target to reorder the list, typically for
+            better instruction bundling.  */
+         if (sort_p
+             && (ready.n_ready == 0
+                 || !SCHED_GROUP_P (ready_element (&ready, 0))))
+           {
+             if (ls.first_cycle_insn_p && targetm.sched.reorder)
+               ls.can_issue_more
+                 = targetm.sched.reorder (sched_dump, sched_verbose,
+                                          ready_lastpos (&ready),
+                                          &ready.n_ready, clock_var);
+             else if (!ls.first_cycle_insn_p && targetm.sched.reorder2)
+               ls.can_issue_more
+                 = targetm.sched.reorder2 (sched_dump, sched_verbose,
+                                           ready.n_ready
+                                           ? ready_lastpos (&ready) : NULL,
+                                           &ready.n_ready, clock_var);
+           }
 
+       restart_choose_ready:
          if (sched_verbose >= 2)
            {
              fprintf (sched_dump, ";;\tReady list (t = %3d):  ",
                       clock_var);
              debug_ready_list (&ready);
+             if (sched_pressure_p)
+               print_curr_reg_pressure ();
            }
 
-         if (ready.n_ready == 0 
-             && can_issue_more 
-             && reload_completed) 
+         if (ready.n_ready == 0
+             && ls.can_issue_more
+             && reload_completed)
            {
              /* Allow scheduling insns directly from the queue in case
                 there's nothing better to do (ready list is empty) but
@@ -2535,7 +4377,8 @@ schedule_block (basic_block *target_bb)
                ready_sort (&ready);
            }
 
-         if (ready.n_ready == 0 || !can_issue_more
+         if (ready.n_ready == 0
+             || !ls.can_issue_more
              || state_dead_lock_p (curr_state)
              || !(*current_sched_info->schedule_more_p) ())
            break;
@@ -2546,20 +4389,26 @@ schedule_block (basic_block *target_bb)
              int res;
 
              insn = NULL_RTX;
-             res = choose_ready (&ready, &insn);
+             res = choose_ready (&ready, ls.first_cycle_insn_p, &insn);
 
              if (res < 0)
                /* Finish cycle.  */
                break;
              if (res > 0)
-               /* Restart choose_ready ().  */
-               continue;
+               goto restart_choose_ready;
 
              gcc_assert (insn != NULL_RTX);
            }
          else
            insn = ready_remove_first (&ready);
 
+         if (sched_pressure_p && INSN_TICK (insn) > clock_var)
+           {
+             ready_add (&ready, insn, true);
+             advance = 1;
+             break;
+           }
+
          if (targetm.sched.dfa_new_cycle
              && targetm.sched.dfa_new_cycle (sched_dump, sched_verbose,
                                              insn, last_clock_var,
@@ -2571,139 +4420,195 @@ schedule_block (basic_block *target_bb)
               to have the highest priority (so it will be returned by
               the ready_remove_first call above), we invoke
               ready_add (&ready, insn, true).
-              But, still, there is one issue: INSN can be later 
-              discarded by scheduler's front end through 
+              But, still, there is one issue: INSN can be later
+              discarded by scheduler's front end through
               current_sched_info->can_schedule_ready_p, hence, won't
-              be issued next.  */ 
+              be issued next.  */
            {
              ready_add (&ready, insn, true);
               break;
            }
 
          sort_p = TRUE;
-         memcpy (temp_state, curr_state, dfa_state_size);
-         if (recog_memoized (insn) < 0)
-           {
-             asm_p = (GET_CODE (PATTERN (insn)) == ASM_INPUT
-                      || asm_noperands (PATTERN (insn)) >= 0);
-             if (!first_cycle_insn_p && asm_p)
-               /* This is asm insn which is tried to be issued on the
-                  cycle not first.  Issue it on the next cycle.  */
-               cost = 1;
-             else
-               /* A USE insn, or something else we don't need to
-                  understand.  We can't pass these directly to
-                  state_transition because it will trigger a
-                  fatal error for unrecognizable insns.  */
-               cost = 0;
-           }
-         else
-           {
-             cost = state_transition (temp_state, insn);
-             if (cost < 0)
-               cost = 0;
-             else if (cost == 0)
-               cost = 1;
-           }
-
-         if (cost >= 1)
-           {
-             queue_insn (insn, cost);
-             if (SCHED_GROUP_P (insn))
-               {
-                 advance = cost;
-                 break;
-               }
-             continue;
-           }
 
          if (current_sched_info->can_schedule_ready_p
              && ! (*current_sched_info->can_schedule_ready_p) (insn))
            /* We normally get here only if we don't want to move
               insn from the split block.  */
            {
-             TODO_SPEC (insn) = (TODO_SPEC (insn) & ~SPECULATIVE) | HARD_DEP;
-             continue;
+             TODO_SPEC (insn) = HARD_DEP;
+             goto restart_choose_ready;
            }
 
-         /* DECISION is made.  */      
-  
-          if (TODO_SPEC (insn) & SPECULATIVE)
-            generate_recovery_code (insn);
-
-         if (control_flow_insn_p (last_scheduled_insn)      
-             /* This is used to switch basic blocks by request
-                from scheduler front-end (actually, sched-ebb.c only).
-                This is used to process blocks with single fallthru
-                edge.  If succeeding block has jump, it [jump] will try
-                move at the end of current bb, thus corrupting CFG.  */
-             || current_sched_info->advance_target_bb (*target_bb, insn))
+         if (delay_htab)
            {
-             *target_bb = current_sched_info->advance_target_bb
-               (*target_bb, 0);
-             
-             if (sched_verbose)
+             /* If this insn is the first part of a delay-slot pair, record a
+                backtrack point.  */
+             struct delay_pair *delay_entry;
+             delay_entry
+               = (struct delay_pair *)htab_find_with_hash (delay_htab, insn,
+                                                           htab_hash_pointer (insn));
+             if (delay_entry)
                {
-                 rtx x;
-
-                 x = next_real_insn (last_scheduled_insn);
-                 gcc_assert (x);
-                 dump_new_block_header (1, *target_bb, x, tail);
+                 save_backtrack_point (delay_entry, ls);
+                 if (sched_verbose >= 2)
+                   fprintf (sched_dump, ";;\t\tsaving backtrack point\n");
                }
+           }
+
+         /* DECISION is made.  */
 
-             last_scheduled_insn = bb_note (*target_bb);
+         if (modulo_ii > 0 && INSN_UID (insn) < modulo_iter0_max_uid)
+           {
+             modulo_insns_scheduled++;
+             modulo_last_stage = clock_var / modulo_ii;
            }
+          if (TODO_SPEC (insn) & SPECULATIVE)
+            generate_recovery_code (insn);
+
+         if (targetm.sched.dispatch (NULL_RTX, IS_DISPATCH_ON))
+           targetm.sched.dispatch_do (insn, ADD_TO_DISPATCH_WINDOW);
+
          /* Update counters, etc in the scheduler's front end.  */
-         (*current_sched_info->begin_schedule_ready) (insn,
-                                                      last_scheduled_insn);
-         move_insn (insn, last_scheduled_insn, current_sched_info->next_tail);
-         reemit_notes (insn);
-         last_scheduled_insn = insn;
-         
-         if (memcmp (curr_state, temp_state, dfa_state_size) != 0)
-            {
-              cycle_issued_insns++;
-              memcpy (curr_state, temp_state, dfa_state_size);
-            }
+         (*current_sched_info->begin_schedule_ready) (insn);
+         VEC_safe_push (rtx, heap, scheduled_insns, insn);
+         gcc_assert (NONDEBUG_INSN_P (insn));
+         last_nondebug_scheduled_insn = last_scheduled_insn = insn;
+
+         if (recog_memoized (insn) >= 0)
+           {
+             memcpy (temp_state, curr_state, dfa_state_size);
+             cost = state_transition (curr_state, insn);
+             if (!sched_pressure_p)
+               gcc_assert (cost < 0);
+             if (memcmp (temp_state, curr_state, dfa_state_size) != 0)
+               cycle_issued_insns++;
+             asm_p = false;
+           }
+         else
+           asm_p = (GET_CODE (PATTERN (insn)) == ASM_INPUT
+                    || asm_noperands (PATTERN (insn)) >= 0);
 
          if (targetm.sched.variable_issue)
-           can_issue_more =
+           ls.can_issue_more =
              targetm.sched.variable_issue (sched_dump, sched_verbose,
-                                              insn, can_issue_more);
+                                           insn, ls.can_issue_more);
          /* A naked CLOBBER or USE generates no instruction, so do
             not count them against the issue rate.  */
          else if (GET_CODE (PATTERN (insn)) != USE
                   && GET_CODE (PATTERN (insn)) != CLOBBER)
-           can_issue_more--;
-
+           ls.can_issue_more--;
          advance = schedule_insn (insn);
 
+         if (SHADOW_P (insn))
+           ls.shadows_only_p = true;
+
          /* After issuing an asm insn we should start a new cycle.  */
          if (advance == 0 && asm_p)
            advance = 1;
+
+         if (must_backtrack)
+           break;
+
          if (advance != 0)
            break;
 
-         first_cycle_insn_p = 0;
+         ls.first_cycle_insn_p = false;
+         if (ready.n_ready > 0)
+           prune_ready_list (temp_state, false, ls.shadows_only_p,
+                             ls.modulo_epilogue);
+       }
 
-         /* Sort the ready list based on priority.  This must be
-            redone here, as schedule_insn may have readied additional
-            insns that will not be sorted correctly.  */
+    do_backtrack:
+      if (!must_backtrack)
+       for (i = 0; i < ready.n_ready; i++)
+         {
+           rtx insn = ready_element (&ready, i);
+           if (INSN_EXACT_TICK (insn) == clock_var)
+             {
+               must_backtrack = true;
+               clock_var++;
+               break;
+             }
+         }
+      if (must_backtrack && modulo_ii > 0)
+       {
+         if (modulo_backtracks_left == 0)
+           goto end_schedule;
+         modulo_backtracks_left--;
+       }
+      while (must_backtrack)
+       {
+         struct haifa_saved_data *failed;
+         rtx failed_insn;
+
+         must_backtrack = false;
+         failed = verify_shadows ();
+         gcc_assert (failed);
+
+         failed_insn = failed->delay_pair->i1;
+         toggle_cancelled_flags (false);
+         unschedule_insns_until (failed_insn);
+         while (failed != backtrack_queue)
+           free_topmost_backtrack_point (true);
+         restore_last_backtrack_point (&ls);
+         if (sched_verbose >= 2)
+           fprintf (sched_dump, ";;\t\trewind to cycle %d\n", clock_var);
+         /* Delay by at least a cycle.  This could cause additional
+            backtracking.  */
+         queue_insn (failed_insn, 1, "backtracked");
+         advance = 0;
+         if (must_backtrack)
+           continue;
          if (ready.n_ready > 0)
-           ready_sort (&ready);
+           goto resume_after_backtrack;
+         else
+           {
+             if (clock_var == 0 && ls.first_cycle_insn_p)
+               goto end_schedule;
+             advance = 1;
+             break;
+           }
+       }
+    }
+  if (ls.modulo_epilogue)
+    success = true;
+ end_schedule:
+  if (modulo_ii > 0)
+    {
+      /* Once again, debug insn suckiness: they can be on the ready list
+        even if they have unresolved dependencies.  To make our view
+        of the world consistent, remove such "ready" insns.  */
+    restart_debug_insn_loop:
+      for (i = ready.n_ready - 1; i >= 0; i--)
+       {
+         rtx x;
 
-         if (targetm.sched.reorder2
-             && (ready.n_ready == 0
-                 || !SCHED_GROUP_P (ready_element (&ready, 0))))
+         x = ready_element (&ready, i);
+         if (DEPS_LIST_FIRST (INSN_HARD_BACK_DEPS (x)) != NULL
+             || DEPS_LIST_FIRST (INSN_SPEC_BACK_DEPS (x)) != NULL)
+           {
+             ready_remove (&ready, i);
+             goto restart_debug_insn_loop;
+           }
+       }
+      for (i = ready.n_ready - 1; i >= 0; i--)
+       {
+         rtx x;
+
+         x = ready_element (&ready, i);
+         resolve_dependencies (x);
+       }
+      for (i = 0; i <= max_insn_queue_index; i++)
+       {
+         rtx link;
+         while ((link = insn_queue[i]) != NULL)
            {
-             can_issue_more =
-               targetm.sched.reorder2 (sched_dump, sched_verbose,
-                                       ready.n_ready
-                                       ? ready_lastpos (&ready) : NULL,
-                                       &ready.n_ready, clock_var);
+             rtx x = XEXP (link, 0);
+             insn_queue[i] = XEXP (link, 1);
+             QUEUE_INDEX (x) = QUEUE_NOWHERE;
+             free_INSN_LIST_node (link);
+             resolve_dependencies (x);
            }
        }
     }
@@ -2715,23 +4620,23 @@ schedule_block (basic_block *target_bb)
       debug_ready_list (&ready);
     }
 
-  if (current_sched_info->queue_must_finish_empty)
+  if (modulo_ii == 0 && current_sched_info->queue_must_finish_empty)
     /* Sanity check -- queue must be empty now.  Meaningless if region has
        multiple bbs.  */
-    gcc_assert (!q_size && !ready.n_ready);
-  else 
+    gcc_assert (!q_size && !ready.n_ready && !ready.n_debug);
+  else if (modulo_ii == 0)
     {
       /* We must maintain QUEUE_INDEX between blocks in region.  */
       for (i = ready.n_ready - 1; i >= 0; i--)
        {
          rtx x;
-         
+
          x = ready_element (&ready, i);
          QUEUE_INDEX (x) = QUEUE_NOWHERE;
-         TODO_SPEC (x) = (TODO_SPEC (x) & ~SPECULATIVE) | HARD_DEP;
+         TODO_SPEC (x) = HARD_DEP;
        }
 
-      if (q_size)   
+      if (q_size)
        for (i = 0; i <= max_insn_queue_index; i++)
          {
            rtx link;
@@ -2741,14 +4646,22 @@ schedule_block (basic_block *target_bb)
 
                x = XEXP (link, 0);
                QUEUE_INDEX (x) = QUEUE_NOWHERE;
-               TODO_SPEC (x) = (TODO_SPEC (x) & ~SPECULATIVE) | HARD_DEP;
+               TODO_SPEC (x) = HARD_DEP;
              }
            free_INSN_LIST_list (&insn_queue[i]);
          }
     }
 
-  if (sched_verbose)
-    fprintf (sched_dump, ";;   total time = %d\n", clock_var);
+  if (success)
+    {
+      commit_schedule (prev_head, tail, target_bb);
+      if (sched_verbose)
+       fprintf (sched_dump, ";;   total time = %d\n", clock_var);
+    }
+  else
+    last_scheduled_insn = tail;
+
+  VEC_truncate (rtx, scheduled_insns, 0);
 
   if (!current_sched_info->queue_must_finish_empty
       || haifa_recovery_bb_recently_added_p)
@@ -2762,14 +4675,14 @@ schedule_block (basic_block *target_bb)
       fix_inter_tick (NEXT_INSN (prev_head), last_scheduled_insn);
     }
 
-  if (targetm.sched.md_finish)
+  if (targetm.sched.finish)
     {
-      targetm.sched.md_finish (sched_dump, sched_verbose);
+      targetm.sched.finish (sched_dump, sched_verbose);
       /* Target might have added some instructions to the scheduled block
         in its md_finish () hook.  These new insns don't have any data
         initialized and to identify them we extend h_i_d so that they'll
         get zero luids.  */
-      sched_init_luids (NULL, NULL, NULL, NULL);
+      sched_extend_luids ();
     }
 
   if (sched_verbose)
@@ -2784,6 +4697,10 @@ schedule_block (basic_block *target_bb)
 
   current_sched_info->head = head;
   current_sched_info->tail = tail;
+
+  free_backtrack_queue ();
+
+  return success;
 }
 \f
 /* Set_priorities: compute priority of each insn in the block.  */
@@ -2793,12 +4710,12 @@ set_priorities (rtx head, rtx tail)
 {
   rtx insn;
   int n_insn;
-  int sched_max_insns_priority = 
+  int sched_max_insns_priority =
        current_sched_info->sched_max_insns_priority;
   rtx prev_head;
 
-  if (head == tail && (! INSN_P (head)))
-    return 0;
+  if (head == tail && ! INSN_P (head))
+    gcc_unreachable ();
 
   n_insn = 0;
 
@@ -2835,7 +4752,7 @@ setup_sched_dump (void)
                ? stderr : dump_file);
 }
 
-/* Initialize some global state for the scheduler.  This function works 
+/* Initialize some global state for the scheduler.  This function works
    with the common data shared between all the schedulers.  It is called
    from the scheduler specific initialization routine.  */
 
@@ -2847,6 +4764,15 @@ sched_init (void)
   flag_schedule_speculative_load = 0;
 #endif
 
+  if (targetm.sched.dispatch (NULL_RTX, IS_DISPATCH_ON))
+    targetm.sched.dispatch_do (NULL_RTX, DISPATCH_INIT);
+
+  sched_pressure_p = (flag_sched_pressure && ! reload_completed
+                     && common_sched_info->sched_pass_id == SCHED_RGN_PASS);
+
+  if (sched_pressure_p)
+    ira_setup_eliminable_regset ();
+
   /* Initialize SPEC_INFO.  */
   if (targetm.sched.set_sched_flags)
     {
@@ -2899,7 +4825,8 @@ sched_init (void)
 
   init_alias_analysis ();
 
-  df_set_flags (DF_LR_RUN_DCE);
+  if (!sched_no_dce)
+    df_set_flags (DF_LR_RUN_DCE);
   df_note_add_problem ();
 
   /* More problems needed for interloop dep calculation in SMS.  */
@@ -2910,17 +4837,37 @@ sched_init (void)
     }
 
   df_analyze ();
-  
-  /* Do not run DCE after reload, as this can kill nops inserted 
+
+  /* Do not run DCE after reload, as this can kill nops inserted
      by bundling.  */
   if (reload_completed)
     df_clear_flags (DF_LR_RUN_DCE);
 
   regstat_compute_calls_crossed ();
 
-  if (targetm.sched.md_init_global)
-    targetm.sched.md_init_global (sched_dump, sched_verbose,
-                                 get_max_uid () + 1);
+  if (targetm.sched.init_global)
+    targetm.sched.init_global (sched_dump, sched_verbose, get_max_uid () + 1);
+
+  if (sched_pressure_p)
+    {
+      int i, max_regno = max_reg_num ();
+
+      if (sched_dump != NULL)
+       /* We need info about pseudos for rtl dumps about pseudo
+          classes and costs.  */
+       regstat_init_n_sets_and_refs ();
+      ira_set_pseudo_classes (sched_verbose ? sched_dump : NULL);
+      sched_regno_pressure_class
+       = (enum reg_class *) xmalloc (max_regno * sizeof (enum reg_class));
+      for (i = 0; i < max_regno; i++)
+       sched_regno_pressure_class[i]
+         = (i < FIRST_PSEUDO_REGISTER
+            ? ira_pressure_class_translate[REGNO_REG_CLASS (i)]
+            : ira_pressure_class_translate[reg_allocno_class (i)]);
+      curr_reg_live = BITMAP_ALLOC (NULL);
+      saved_reg_live = BITMAP_ALLOC (NULL);
+      region_ref_regs = BITMAP_ALLOC (NULL);
+    }
 
   curr_state = xmalloc (dfa_state_size);
 }
@@ -2934,6 +4881,8 @@ haifa_sched_init (void)
   setup_sched_dump ();
   sched_init ();
 
+  scheduled_insns = VEC_alloc (rtx, heap, 0);
+
   if (spec_info != NULL)
     {
       sched_deps_info->use_deps_list = 1;
@@ -2950,10 +4899,10 @@ haifa_sched_init (void)
 
     FOR_EACH_BB (bb)
       VEC_quick_push (basic_block, bbs, bb);
-    sched_init_luids (bbs, NULL, NULL, NULL);
+    sched_init_luids (bbs);
     sched_deps_init (true);
     sched_extend_target ();
-    haifa_init_h_i_d (bbs, NULL, NULL, NULL);
+    haifa_init_h_i_d (bbs);
 
     VEC_free (basic_block, heap, bbs);
   }
@@ -2963,16 +4912,11 @@ haifa_sched_init (void)
   sched_create_empty_bb = sched_create_empty_bb_1;
   haifa_recovery_bb_ever_added_p = false;
 
-#ifdef ENABLE_CHECKING
-  /* This is used preferably for finding bugs in check_cfg () itself.
-     We must call sched_bbs_init () before check_cfg () because check_cfg ()
-     assumes that the last insn in the last bb has a non-null successor.  */
-  check_cfg (0, 0);
-#endif
-
   nr_begin_data = nr_begin_control = nr_be_in_data = nr_be_in_control = 0;
   before_recovery = 0;
   after_recovery = 0;
+
+  modulo_ii = 0;
 }
 
 /* Finish work with the data specific to the Haifa scheduler.  */
@@ -3004,6 +4948,8 @@ haifa_sched_finish (void)
                c, nr_be_in_control);
     }
 
+  VEC_free (rtx, heap, scheduled_insns);
+
   /* Finalize h_i_d, dependency caches, and luids for the whole
      function.  Target will be finalized in md_global_finish ().  */
   sched_deps_finish ();
@@ -3012,29 +4958,43 @@ haifa_sched_finish (void)
   sched_finish ();
 }
 
-/* Free global data used during insn scheduling.  This function works with 
+/* Free global data used during insn scheduling.  This function works with
    the common data shared between the schedulers.  */
 
 void
 sched_finish (void)
 {
   haifa_finish_h_i_d ();
+  if (sched_pressure_p)
+    {
+      if (regstat_n_sets_and_refs != NULL)
+       regstat_free_n_sets_and_refs ();
+      free (sched_regno_pressure_class);
+      BITMAP_FREE (region_ref_regs);
+      BITMAP_FREE (saved_reg_live);
+      BITMAP_FREE (curr_reg_live);
+    }
   free (curr_state);
 
-  if (targetm.sched.md_finish_global)
-    targetm.sched.md_finish_global (sched_dump, sched_verbose);
+  if (targetm.sched.finish_global)
+    targetm.sched.finish_global (sched_dump, sched_verbose);
 
   end_alias_analysis ();
 
   regstat_free_calls_crossed ();
 
   dfa_finish ();
+}
 
-#ifdef ENABLE_CHECKING
-  /* After reload ia64 backend clobbers CFG, so can't check anything.  */
-  if (!reload_completed)
-    check_cfg (0, 0);
-#endif
+/* Free all delay_pair structures that were recorded.  */
+void
+free_delay_pairs (void)
+{
+  if (delay_htab)
+    {
+      htab_empty (delay_htab);
+      htab_empty (delay_htab_i2);
+    }
 }
 
 /* Fix INSN_TICKs of the instructions in the current block as well as
@@ -3052,7 +5012,7 @@ fix_inter_tick (rtx head, rtx tail)
   int next_clock = clock_var + 1;
 
   bitmap_initialize (&processed, 0);
-  
+
   /* Iterates over scheduled instructions and fix their INSN_TICKs and
      INSN_TICKs of dependent instructions, so that INSN_TICKs are consistent
      across different blocks.  */
@@ -3063,26 +5023,28 @@ fix_inter_tick (rtx head, rtx tail)
          int tick;
          sd_iterator_def sd_it;
          dep_t dep;
-                  
+
          tick = INSN_TICK (head);
          gcc_assert (tick >= MIN_TICK);
-         
+
          /* Fix INSN_TICK of instruction from just scheduled block.  */
-         if (!bitmap_bit_p (&processed, INSN_LUID (head)))
+         if (bitmap_set_bit (&processed, INSN_LUID (head)))
            {
-             bitmap_set_bit (&processed, INSN_LUID (head));
              tick -= next_clock;
-             
+
              if (tick < MIN_TICK)
                tick = MIN_TICK;
-             
-             INSN_TICK (head) = tick;           
+
+             INSN_TICK (head) = tick;
            }
-         
+
+         if (DEBUG_INSN_P (head))
+           continue;
+
          FOR_EACH_DEP (head, SD_LIST_RES_FORW, sd_it, dep)
            {
              rtx next;
-             
+
              next = DEP_CON (dep);
              tick = INSN_TICK (next);
 
@@ -3090,14 +5052,13 @@ fix_inter_tick (rtx head, rtx tail)
                  /* If NEXT has its INSN_TICK calculated, fix it.
                     If not - it will be properly calculated from
                     scratch later in fix_tick_ready.  */
-                 && !bitmap_bit_p (&processed, INSN_LUID (next)))
+                 && bitmap_set_bit (&processed, INSN_LUID (next)))
                {
-                 bitmap_set_bit (&processed, INSN_LUID (next));
                  tick -= next_clock;
-                 
+
                  if (tick < MIN_TICK)
                    tick = MIN_TICK;
-                 
+
                  if (tick > INTER_TICK (next))
                    INTER_TICK (next) = tick;
                  else
@@ -3111,8 +5072,6 @@ fix_inter_tick (rtx head, rtx tail)
   bitmap_clear (&processed);
 }
 
-static int haifa_speculate_insn (rtx, ds_t, rtx *);
-  
 /* Check if NEXT is ready to be added to the ready or queue list.
    If "yes", add it to the proper list.
    Returns:
@@ -3121,69 +5080,23 @@ static int haifa_speculate_insn (rtx, ds_t, rtx *);
    0 < N - queued for N cycles.  */
 int
 try_ready (rtx next)
-{  
-  ds_t old_ts, *ts;
+{
+  ds_t old_ts, new_ts;
 
-  ts = &TODO_SPEC (next);
-  old_ts = *ts;
+  old_ts = TODO_SPEC (next);
 
-  gcc_assert (!(old_ts & ~(SPECULATIVE | HARD_DEP))
+  gcc_assert (!(old_ts & ~(SPECULATIVE | HARD_DEP | DEP_CONTROL))
              && ((old_ts & HARD_DEP)
-                 || (old_ts & SPECULATIVE)));
-  
-  if (sd_lists_empty_p (next, SD_LIST_BACK))
-    /* NEXT has all its dependencies resolved.  */
-    {
-      /* Remove HARD_DEP bit from NEXT's status.  */
-      *ts &= ~HARD_DEP;
-
-      if (current_sched_info->flags & DO_SPECULATION)
-       /* Remove all speculative bits from NEXT's status.  */
-       *ts &= ~SPECULATIVE;
-    }
-  else
-    {
-      /* One of the NEXT's dependencies has been resolved.
-        Recalculate NEXT's status.  */
-
-      *ts &= ~SPECULATIVE & ~HARD_DEP;
-
-      if (sd_lists_empty_p (next, SD_LIST_HARD_BACK))
-       /* Now we've got NEXT with speculative deps only.
-          1. Look at the deps to see what we have to do.
-          2. Check if we can do 'todo'.  */
-       {
-         sd_iterator_def sd_it;
-         dep_t dep;
-         bool first_p = true;
-
-         FOR_EACH_DEP (next, SD_LIST_BACK, sd_it, dep)
-           {
-             ds_t ds = DEP_STATUS (dep) & SPECULATIVE;
-
-             if (first_p)
-               {
-                 first_p = false;
+                 || (old_ts & SPECULATIVE)
+                 || (old_ts & DEP_CONTROL)));
 
-                 *ts = ds;
-               }
-             else
-               *ts = ds_merge (*ts, ds);
-           }
-
-         if (ds_weak (*ts) < spec_info->data_weakness_cutoff)
-           /* Too few points.  */
-           *ts = (*ts & ~SPECULATIVE) | HARD_DEP;
-       }
-      else
-       *ts |= HARD_DEP;
-    }
+  new_ts = recompute_todo_spec (next);
 
-  if (*ts & HARD_DEP)
-    gcc_assert (*ts == old_ts
+  if (new_ts & HARD_DEP)
+    gcc_assert (new_ts == old_ts
                && QUEUE_INDEX (next) == QUEUE_NOWHERE);
   else if (current_sched_info->new_ready)
-    *ts = current_sched_info->new_ready (next, *ts);
+    new_ts = current_sched_info->new_ready (next, new_ts);
 
   /* * if !(old_ts & SPECULATIVE) (e.g. HARD_DEP or 0), then insn might
      have its original pattern or changed (speculative) one.  This is due
@@ -3191,101 +5104,107 @@ try_ready (rtx next)
      * But if (old_ts & SPECULATIVE), then we are pretty sure that insn
      has speculative pattern.
 
-     We can't assert (!(*ts & HARD_DEP) || *ts == old_ts) here because
+     We can't assert (!(new_ts & HARD_DEP) || new_ts == old_ts) here because
      control-speculative NEXT could have been discarded by sched-rgn.c
      (the same case as when discarded by can_schedule_ready_p ()).  */
 
-  if ((*ts & SPECULATIVE)
-      /* If (old_ts == *ts), then (old_ts & SPECULATIVE) and we don't
+  if ((new_ts & SPECULATIVE)
+      /* If (old_ts == new_ts), then (old_ts & SPECULATIVE) and we don't
         need to change anything.  */
-      && *ts != old_ts)
+      && new_ts != old_ts)
     {
       int res;
       rtx new_pat;
-      
-      gcc_assert ((*ts & SPECULATIVE) && !(*ts & ~SPECULATIVE));
-      
-      res = haifa_speculate_insn (next, *ts, &new_pat);
-       
+
+      gcc_assert ((new_ts & SPECULATIVE) && !(new_ts & ~SPECULATIVE));
+
+      res = haifa_speculate_insn (next, new_ts, &new_pat);
+
       switch (res)
        {
        case -1:
          /* It would be nice to change DEP_STATUS of all dependences,
-            which have ((DEP_STATUS & SPECULATIVE) == *ts) to HARD_DEP,
+            which have ((DEP_STATUS & SPECULATIVE) == new_ts) to HARD_DEP,
             so we won't reanalyze anything.  */
-         *ts = (*ts & ~SPECULATIVE) | HARD_DEP;
+         new_ts = HARD_DEP;
          break;
-         
+
        case 0:
          /* We follow the rule, that every speculative insn
             has non-null ORIG_PAT.  */
          if (!ORIG_PAT (next))
            ORIG_PAT (next) = PATTERN (next);
          break;
-         
-       case 1:                  
+
+       case 1:
          if (!ORIG_PAT (next))
            /* If we gonna to overwrite the original pattern of insn,
               save it.  */
            ORIG_PAT (next) = PATTERN (next);
-         
-         haifa_change_pattern (next, new_pat);
+
+         res = haifa_change_pattern (next, new_pat);
+         gcc_assert (res);
          break;
-         
+
        default:
          gcc_unreachable ();
        }
     }
-  
-  /* We need to restore pattern only if (*ts == 0), because otherwise it is
-     either correct (*ts & SPECULATIVE),
-     or we simply don't care (*ts & HARD_DEP).  */
-  
+
+  /* We need to restore pattern only if (new_ts == 0), because otherwise it is
+     either correct (new_ts & SPECULATIVE),
+     or we simply don't care (new_ts & HARD_DEP).  */
+
   gcc_assert (!ORIG_PAT (next)
              || !IS_SPECULATION_BRANCHY_CHECK_P (next));
-  
-  if (*ts & HARD_DEP)
+
+  TODO_SPEC (next) = new_ts;
+
+  if (new_ts & HARD_DEP)
     {
       /* We can't assert (QUEUE_INDEX (next) == QUEUE_NOWHERE) here because
         control-speculative NEXT could have been discarded by sched-rgn.c
         (the same case as when discarded by can_schedule_ready_p ()).  */
       /*gcc_assert (QUEUE_INDEX (next) == QUEUE_NOWHERE);*/
-      
+
       change_queue_index (next, QUEUE_NOWHERE);
+
       return -1;
     }
-  else if (!(*ts & BEGIN_SPEC) && ORIG_PAT (next) && !IS_SPECULATION_CHECK_P (next))
-    /* We should change pattern of every previously speculative 
+  else if (!(new_ts & BEGIN_SPEC)
+          && ORIG_PAT (next) && PREDICATED_PAT (next) == NULL_RTX
+          && !IS_SPECULATION_CHECK_P (next))
+    /* We should change pattern of every previously speculative
        instruction - and we determine if NEXT was speculative by using
        ORIG_PAT field.  Except one case - speculation checks have ORIG_PAT
        pat too, so skip them.  */
     {
-      haifa_change_pattern (next, ORIG_PAT (next));
+      bool success = haifa_change_pattern (next, ORIG_PAT (next));
+      gcc_assert (success);
       ORIG_PAT (next) = 0;
     }
 
   if (sched_verbose >= 2)
-    {        
-      int s = TODO_SPEC (next);
-          
+    {
       fprintf (sched_dump, ";;\t\tdependencies resolved: insn %s",
                (*current_sched_info->print_insn) (next, 0));
-          
+
       if (spec_info && spec_info->dump)
         {
-          if (s & BEGIN_DATA)
+          if (new_ts & BEGIN_DATA)
             fprintf (spec_info->dump, "; data-spec;");
-          if (s & BEGIN_CONTROL)
+          if (new_ts & BEGIN_CONTROL)
             fprintf (spec_info->dump, "; control-spec;");
-          if (s & BE_IN_CONTROL)
+          if (new_ts & BE_IN_CONTROL)
             fprintf (spec_info->dump, "; in-control-spec;");
         }
-
+      if (TODO_SPEC (next) & DEP_CONTROL)
+       fprintf (sched_dump, " predicated");
       fprintf (sched_dump, "\n");
-    }          
-  
+    }
+
   adjust_priority (next);
-        
+
   return fix_tick_ready (next);
 }
 
@@ -3295,7 +5214,7 @@ fix_tick_ready (rtx next)
 {
   int tick, delay;
 
-  if (!sd_lists_empty_p (next, SD_LIST_RES_BACK))
+  if (!DEBUG_INSN_P (next) && !sd_lists_empty_p (next, SD_LIST_RES_BACK))
     {
       int full_p;
       sd_iterator_def sd_it;
@@ -3308,10 +5227,10 @@ fix_tick_ready (rtx next)
       full_p = (tick == INVALID_TICK);
 
       FOR_EACH_DEP (next, SD_LIST_RES_BACK, sd_it, dep)
-        {       
+        {
           rtx pro = DEP_PRO (dep);
           int tick1;
-              
+
          gcc_assert (INSN_TICK (pro) >= MIN_TICK);
 
           tick1 = INSN_TICK (pro) + dep_cost (dep);
@@ -3328,7 +5247,7 @@ fix_tick_ready (rtx next)
   INSN_TICK (next) = tick;
 
   delay = tick - clock_var;
-  if (delay <= 0)
+  if (delay <= 0 || sched_pressure_p)
     delay = QUEUE_READY;
 
   change_queue_index (next, delay);
@@ -3344,10 +5263,10 @@ change_queue_index (rtx next, int delay)
 {
   int i = QUEUE_INDEX (next);
 
-  gcc_assert (QUEUE_NOWHERE <= delay && delay <= max_insn_queue_index 
+  gcc_assert (QUEUE_NOWHERE <= delay && delay <= max_insn_queue_index
              && delay != 0);
   gcc_assert (i != QUEUE_SCHEDULED);
-  
+
   if ((delay > 0 && NEXT_Q_AFTER (q_ptr, delay) == i)
       || (delay < 0 && delay == i))
     /* We have nothing to do.  */
@@ -3358,18 +5277,18 @@ change_queue_index (rtx next, int delay)
     ready_remove_insn (next);
   else if (i >= 0)
     queue_remove (next);
-    
+
   /* Add it to the proper place.  */
   if (delay == QUEUE_READY)
     ready_add (readyp, next, false);
   else if (delay >= 1)
-    queue_insn (next, delay);
-    
+    queue_insn (next, delay, "change queue index");
+
   if (sched_verbose >= 2)
-    {        
+    {
       fprintf (sched_dump, ";;\t\ttick updated: insn %s",
               (*current_sched_info->print_insn) (next, 0));
-      
+
       if (delay == QUEUE_READY)
        fprintf (sched_dump, " into ready\n");
       else if (delay >= 1)
@@ -3393,6 +5312,7 @@ sched_extend_ready_list (int new_sched_ready_n_insns)
     {
       i = 0;
       sched_ready_n_insns = 0;
+      VEC_reserve (rtx, heap, scheduled_insns, new_sched_ready_n_insns);
     }
   else
     i = sched_ready_n_insns + 1;
@@ -3411,7 +5331,13 @@ sched_extend_ready_list (int new_sched_ready_n_insns)
                             new_sched_ready_n_insns + 1);
 
   for (; i <= new_sched_ready_n_insns; i++)
-    choice_stack[i].state = xmalloc (dfa_state_size);
+    {
+      choice_stack[i].state = xmalloc (dfa_state_size);
+
+      if (targetm.sched.first_cycle_multipass_init)
+       targetm.sched.first_cycle_multipass_init (&(choice_stack[i]
+                                                   .target_data));
+    }
 
   sched_ready_n_insns = new_sched_ready_n_insns;
 }
@@ -3430,7 +5356,13 @@ sched_finish_ready_list (void)
   ready_try = NULL;
 
   for (i = 0; i <= sched_ready_n_insns; i++)
-    free (choice_stack [i].state);
+    {
+      if (targetm.sched.first_cycle_multipass_fini)
+       targetm.sched.first_cycle_multipass_fini (&(choice_stack[i]
+                                                   .target_data));
+
+      free (choice_stack [i].state);
+    }
   free (choice_stack);
   choice_stack = NULL;
 
@@ -3451,10 +5383,10 @@ generate_recovery_code (rtx insn)
 {
   if (TODO_SPEC (insn) & BEGIN_SPEC)
     begin_speculative_block (insn);
-  
+
   /* Here we have insn with no dependencies to
      instructions other then CHECK_SPEC ones.  */
-  
+
   if (TODO_SPEC (insn) & BE_IN_SPEC)
     add_to_speculative_block (insn);
 }
@@ -3498,7 +5430,7 @@ process_insn_forw_deps_be_in_spec (rtx insn, rtx twin, ds_t fs)
                  ds_t new_ds;
 
                  new_ds = (ds & ~BEGIN_SPEC) | fs;
-                 
+
                  if (/* consumer can 'be in speculative'.  */
                      sched_insn_is_legitimate_for_speculation_p (consumer,
                                                                  new_ds))
@@ -3525,7 +5457,7 @@ static void
 begin_speculative_block (rtx insn)
 {
   if (TODO_SPEC (insn) & BEGIN_DATA)
-    nr_begin_data++;      
+    nr_begin_data++;
   if (TODO_SPEC (insn) & BEGIN_CONTROL)
     nr_begin_control++;
 
@@ -3556,7 +5488,7 @@ add_to_speculative_block (rtx insn)
 
   TODO_SPEC (insn) &= ~BE_IN_SPEC;
   gcc_assert (!TODO_SPEC (insn));
-  
+
   DONE_SPEC (insn) |= ts;
 
   /* First we convert all simple checks to branchy.  */
@@ -3667,7 +5599,7 @@ add_to_speculative_block (rtx insn)
 
       twin = XEXP (twins, 1);
       free_INSN_LIST_node (twins);
-      twins = twin;      
+      twins = twin;
     }
 
   calc_priorities (priorities_roots);
@@ -3687,10 +5619,9 @@ xrecalloc (void *p, size_t new_nmemb, size_t old_nmemb, size_t size)
 /* Helper function.
    Find fallthru edge from PRED.  */
 edge
-find_fallthru_edge (basic_block pred)
+find_fallthru_edge_from (basic_block pred)
 {
   edge e;
-  edge_iterator ei;
   basic_block succ;
 
   succ = pred->next_bb;
@@ -3698,21 +5629,23 @@ find_fallthru_edge (basic_block pred)
 
   if (EDGE_COUNT (pred->succs) <= EDGE_COUNT (succ->preds))
     {
-      FOR_EACH_EDGE (e, ei, pred->succs)
-       if (e->flags & EDGE_FALLTHRU)
-         {
-           gcc_assert (e->dest == succ);
-           return e;
-         }
+      e = find_fallthru_edge (pred->succs);
+
+      if (e)
+       {
+         gcc_assert (e->dest == succ);
+         return e;
+       }
     }
   else
     {
-      FOR_EACH_EDGE (e, ei, succ->preds)
-       if (e->flags & EDGE_FALLTHRU)
-         {
-           gcc_assert (e->src == pred);
-           return e;
-         }
+      e = find_fallthru_edge (succ->preds);
+
+      if (e)
+       {
+         gcc_assert (e->src == pred);
+         return e;
+       }
     }
 
   return NULL;
@@ -3754,20 +5687,20 @@ init_before_recovery (basic_block *before_recovery_ptr)
   edge e;
 
   last = EXIT_BLOCK_PTR->prev_bb;
-  e = find_fallthru_edge (last);
+  e = find_fallthru_edge_from (last);
 
   if (e)
     {
-      /* We create two basic blocks: 
+      /* We create two basic blocks:
          1. Single instruction block is inserted right after E->SRC
-         and has jump to 
+         and has jump to
          2. Empty block right before EXIT_BLOCK.
          Between these two blocks recovery blocks will be emitted.  */
 
       basic_block single, empty;
       rtx x, label;
 
-      /* If the fallthrough edge to exit we've found is from the block we've 
+      /* If the fallthrough edge to exit we've found is from the block we've
         created before, don't do anything more.  */
       if (last == after_recovery)
        return;
@@ -3801,7 +5734,7 @@ init_before_recovery (basic_block *before_recovery_ptr)
       JUMP_LABEL (x) = label;
       LABEL_NUSES (label)++;
       haifa_init_insn (x);
-          
+
       emit_barrier_after (x);
 
       sched_init_only_bb (empty, NULL);
@@ -3817,8 +5750,8 @@ init_before_recovery (basic_block *before_recovery_ptr)
 
       if (sched_verbose >= 2 && spec_info->dump)
         fprintf (spec_info->dump,
-                ";;\t\tFixed fallthru to EXIT : %d->>%d->%d->>EXIT\n", 
-                 last->index, single->index, empty->index);      
+                ";;\t\tFixed fallthru to EXIT : %d->>%d->%d->>EXIT\n",
+                 last->index, single->index, empty->index);
     }
   else
     before_recovery = last;
@@ -3831,7 +5764,7 @@ sched_create_recovery_block (basic_block *before_recovery_ptr)
   rtx label;
   rtx barrier;
   basic_block rec;
-  
+
   haifa_recovery_bb_recently_added_p = true;
   haifa_recovery_bb_ever_added_p = true;
 
@@ -3849,8 +5782,8 @@ sched_create_recovery_block (basic_block *before_recovery_ptr)
 
   if (BB_PARTITION (before_recovery) != BB_UNPARTITIONED)
     BB_SET_PARTITION (rec, BB_COLD_PARTITION);
-  
-  if (sched_verbose && spec_info->dump)    
+
+  if (sched_verbose && spec_info->dump)
     fprintf (spec_info->dump, ";;\t\tGenerated recovery block rec%d\n",
              rec->index);
 
@@ -3865,18 +5798,17 @@ sched_create_recovery_edges (basic_block first_bb, basic_block rec,
 {
   rtx label;
   rtx jump;
-  edge e;
   int edge_flags;
 
   /* This is fixing of incoming edge.  */
-  /* ??? Which other flags should be specified?  */      
+  /* ??? Which other flags should be specified?  */
   if (BB_PARTITION (first_bb) != BB_PARTITION (rec))
     /* Partition type is the same, if it is "unpartitioned".  */
     edge_flags = EDGE_CROSSING;
   else
     edge_flags = 0;
-      
-  e = make_edge (first_bb, rec, edge_flags);
+
+  make_edge (first_bb, rec, edge_flags);
   label = block_label (second_bb);
   jump = emit_jump_insn_after (gen_jump (label), BB_END (rec));
   JUMP_LABEL (jump) = label;
@@ -3887,20 +5819,20 @@ sched_create_recovery_edges (basic_block first_bb, basic_block rec,
     {
       /* Rewritten from cfgrtl.c.  */
       if (flag_reorder_blocks_and_partition
-         && targetm.have_named_sections)
-       /* We don't need the same note for the check because
-          any_condjump_p (check) == true.  */
+         && targetm_common.have_named_sections)
        {
-         REG_NOTES (jump) = gen_rtx_EXPR_LIST (REG_CROSSING_JUMP,
-                                               NULL_RTX,
-                                               REG_NOTES (jump));
+         /* We don't need the same note for the check because
+            any_condjump_p (check) == true.  */
+         add_reg_note (jump, REG_CROSSING_JUMP, NULL_RTX);
        }
       edge_flags = EDGE_CROSSING;
     }
   else
-    edge_flags = 0;  
+    edge_flags = 0;
 
-  make_single_succ_edge (rec, second_bb, edge_flags);  
+  make_single_succ_edge (rec, second_bb, edge_flags);
+  if (dom_info_available_p (CDI_DOMINATORS))
+    set_immediate_dominator (CDI_DOMINATORS, rec, first_bb);
 }
 
 /* This function creates recovery code for INSN.  If MUTATE_P is nonzero,
@@ -3931,7 +5863,7 @@ create_check_block_twin (rtx insn, bool mutate_p)
   todo_spec &= SPECULATIVE;
 
   /* Create recovery block.  */
-  if (mutate_p || targetm.sched.needs_block_p (insn))
+  if (mutate_p || targetm.sched.needs_block_p (todo_spec))
     {
       rec = sched_create_recovery_block (NULL);
       label = BB_HEAD (rec);
@@ -3943,12 +5875,12 @@ create_check_block_twin (rtx insn, bool mutate_p)
     }
 
   /* Emit CHECK.  */
-  check = targetm.sched.gen_spec_check (insn, label, mutate_p);
+  check = targetm.sched.gen_spec_check (insn, label, todo_spec);
 
   if (rec != EXIT_BLOCK_PTR)
     {
       /* To have mem_reg alive at the beginning of second_bb,
-        we emit check BEFORE insn, so insn after splitting 
+        we emit check BEFORE insn, so insn after splitting
         insn will be at the beginning of second_bb, which will
         provide us with the correct life information.  */
       check = emit_jump_insn_before (check, insn);
@@ -4026,14 +5958,14 @@ create_check_block_twin (rtx insn, bool mutate_p)
 
       sched_create_recovery_edges (first_bb, rec, second_bb);
 
-      sched_init_only_bb (second_bb, first_bb);      
+      sched_init_only_bb (second_bb, first_bb);
       sched_init_only_bb (rec, EXIT_BLOCK_PTR);
 
       jump = BB_END (rec);
       haifa_init_insn (jump);
     }
 
-  /* Move backward dependences from INSN to CHECK and 
+  /* Move backward dependences from INSN to CHECK and
      move forward dependences from INSN to TWIN.  */
 
   /* First, create dependencies between INSN's producers and CHECK & TWIN.  */
@@ -4046,7 +5978,7 @@ create_check_block_twin (rtx insn, bool mutate_p)
         check --TRUE--> producer  ??? or ANTI ???
         twin  --TRUE--> producer
         twin  --ANTI--> check
-        
+
         If BEGIN_CONTROL: [insn ~~ANTI~~> producer]:
         check --ANTI--> producer
         twin  --ANTI--> producer
@@ -4055,7 +5987,7 @@ create_check_block_twin (rtx insn, bool mutate_p)
         If BE_IN_SPEC: [insn ~~TRUE~~> producer]:
         check ~~TRUE~~> producer
         twin  ~~TRUE~~> producer
-        twin  --ANTI--> check  */                
+        twin  --ANTI--> check  */
 
       ds = DEP_STATUS (dep);
 
@@ -4072,7 +6004,7 @@ create_check_block_twin (rtx insn, bool mutate_p)
        {
          DEP_CON (new_dep) = twin;
          sd_add_dep (new_dep, false);
-       }    
+       }
     }
 
   /* Second, remove backward dependencies of INSN.  */
@@ -4093,11 +6025,11 @@ create_check_block_twin (rtx insn, bool mutate_p)
 
   /* Fields (DONE_SPEC (x) & BEGIN_SPEC) and CHECK_SPEC (x) are set only
      here.  */
-  
+
   gcc_assert (!DONE_SPEC (insn));
-  
+
   if (!mutate_p)
-    { 
+    {
       ds_t ts = TODO_SPEC (insn);
 
       DONE_SPEC (insn) = ts & BEGIN_SPEC;
@@ -4133,7 +6065,7 @@ create_check_block_twin (rtx insn, bool mutate_p)
        }
       else
        {
-         if (spec_info->dump)    
+         if (spec_info->dump)
            fprintf (spec_info->dump, ";;\t\tRemoved simple check : %s\n",
                     (*current_sched_info->print_insn) (insn, 0));
 
@@ -4188,7 +6120,7 @@ fix_recovery_deps (basic_block rec)
   rtx link;
 
   bitmap_initialize (&in_ready, 0);
-  
+
   /* NOTE - a basic block note.  */
   note = NEXT_INSN (BB_HEAD (rec));
   gcc_assert (NOTE_INSN_BASIC_BLOCK_P (note));
@@ -4210,11 +6142,8 @@ fix_recovery_deps (basic_block rec)
            {
              sd_delete_dep (sd_it);
 
-             if (!bitmap_bit_p (&in_ready, INSN_LUID (consumer)))
-               {
-                 ready_list = alloc_INSN_LIST (consumer, ready_list);
-                 bitmap_set_bit (&in_ready, INSN_LUID (consumer));
-               }
+             if (bitmap_set_bit (&in_ready, INSN_LUID (consumer)))
+               ready_list = alloc_INSN_LIST (consumer, ready_list);
            }
          else
            {
@@ -4223,7 +6152,7 @@ fix_recovery_deps (basic_block rec)
              sd_iterator_next (&sd_it);
            }
        }
-      
+
       insn = PREV_INSN (insn);
     }
   while (insn != note);
@@ -4238,36 +6167,41 @@ fix_recovery_deps (basic_block rec)
   /* Fixing jump's dependences.  */
   insn = BB_HEAD (rec);
   jump = BB_END (rec);
-      
+
   gcc_assert (LABEL_P (insn));
   insn = NEXT_INSN (insn);
-  
+
   gcc_assert (NOTE_INSN_BASIC_BLOCK_P (insn));
   add_jump_dependencies (insn, jump);
 }
 
-/* Change pattern of INSN to NEW_PAT.  */
-void
-sched_change_pattern (rtx insn, rtx new_pat)
+/* Change pattern of INSN to NEW_PAT.  Invalidate cached haifa
+   instruction data.  */
+static bool
+haifa_change_pattern (rtx insn, rtx new_pat)
 {
+  sd_iterator_def sd_it;
+  dep_t dep;
   int t;
 
   t = validate_change (insn, &PATTERN (insn), new_pat, 0);
-  gcc_assert (t);
+  if (!t)
+    return false;
   dfa_clear_single_insn_cache (insn);
-}
 
-/* Change pattern of INSN to NEW_PAT.  Invalidate cached haifa
-   instruction data.  */
-static void
-haifa_change_pattern (rtx insn, rtx new_pat)
-{
-  sched_change_pattern (insn, new_pat);
+  sd_it = sd_iterator_start (insn,
+                            SD_LIST_FORW | SD_LIST_BACK | SD_LIST_RES_BACK);
+  while (sd_iterator_cond (&sd_it, &dep))
+    {
+      DEP_COST (dep) = UNKNOWN_DEP_COST;
+      sd_iterator_next (&sd_it);
+    }
 
   /* Invalidate INSN_COST, so it'll be recalculated.  */
   INSN_COST (insn) = -1;
   /* Invalidate INSN_TICK, so it'll be recalculated.  */
   INSN_TICK (insn) = INVALID_TICK;
+  return true;
 }
 
 /* -1 - can't speculate,
@@ -4355,7 +6289,7 @@ unlink_bb_notes (basic_block first, basic_block last)
       if (LABEL_P (label))
        note = NEXT_INSN (label);
       else
-       note = label;      
+       note = label;
       gcc_assert (NOTE_INSN_BASIC_BLOCK_P (note));
 
       prev = PREV_INSN (label);
@@ -4369,7 +6303,7 @@ unlink_bb_notes (basic_block first, basic_block last)
 
       if (last == first)
        break;
-      
+
       last = last->prev_bb;
     }
   while (1);
@@ -4384,14 +6318,14 @@ restore_bb_notes (basic_block first)
     return;
 
   /* We DON'T unlink basic block notes of the first block in the ebb.  */
-  first = first->next_bb;  
+  first = first->next_bb;
   /* Remember: FIRST is actually a second basic block in the ebb.  */
 
   while (first != EXIT_BLOCK_PTR
         && bb_header[first->index])
     {
       rtx prev, label, note, next;
-      
+
       label = bb_header[first->index];
       prev = PREV_INSN (label);
       next = NEXT_INSN (prev);
@@ -4399,7 +6333,7 @@ restore_bb_notes (basic_block first)
       if (LABEL_P (label))
        note = NEXT_INSN (label);
       else
-       note = label;      
+       note = label;
       gcc_assert (NOTE_INSN_BASIC_BLOCK_P (note));
 
       bb_header[first->index] = 0;
@@ -4407,7 +6341,7 @@ restore_bb_notes (basic_block first)
       NEXT_INSN (prev) = label;
       NEXT_INSN (note) = next;
       PREV_INSN (next) = note;
-      
+
       first = first->next_bb;
     }
 
@@ -4429,7 +6363,7 @@ fix_jump_move (rtx jump)
 
   gcc_assert (common_sched_info->sched_pass_id == SCHED_EBB_PASS
              || IS_SPECULATION_BRANCHY_CHECK_P (jump));
-  
+
   if (!NOTE_INSN_BASIC_BLOCK_P (BB_END (jump_bb_next)))
     /* if jump_bb_next is not empty.  */
     BB_END (jump_bb) = BB_END (jump_bb_next);
@@ -4458,9 +6392,9 @@ move_block_after_check (rtx jump)
   bb = BLOCK_FOR_INSN (PREV_INSN (jump));
   jump_bb = BLOCK_FOR_INSN (jump);
   jump_bb_next = jump_bb->next_bb;
-  
+
   update_bb_for_insn (jump_bb);
-  
+
   gcc_assert (IS_SPECULATION_CHECK_P (jump)
              || IS_SPECULATION_CHECK_P (BB_END (jump_bb_next)));
 
@@ -4474,7 +6408,7 @@ move_block_after_check (rtx jump)
   move_succs (&t, jump_bb_next);
 
   df_mark_solutions_dirty ();
-  
+
   common_sched_info->fix_recovery_cfg
     (bb->index, jump_bb->index, jump_bb_next->index);
 }
@@ -4552,7 +6486,7 @@ calc_priorities (rtx_vec_t roots)
   int i;
   rtx insn;
 
-  for (i = 0; VEC_iterate (rtx, roots, i, insn); i++)
+  FOR_EACH_VEC_ELT (rtx, roots, i, insn)
     priority (insn);
 }
 
@@ -4567,8 +6501,8 @@ add_jump_dependencies (rtx insn, rtx jump)
       insn = NEXT_INSN (insn);
       if (insn == jump)
        break;
-      
-      if (sd_lists_empty_p (insn, SD_LIST_FORW))
+
+      if (dep_list_size (insn) == 0)
        {
          dep_def _new_dep, *new_dep = &_new_dep;
 
@@ -4581,231 +6515,9 @@ add_jump_dependencies (rtx insn, rtx jump)
   gcc_assert (!sd_lists_empty_p (jump, SD_LIST_BACK));
 }
 
-/* Return the NOTE_INSN_BASIC_BLOCK of BB.  */
-rtx
-bb_note (basic_block bb)
-{
-  rtx note;
-
-  note = BB_HEAD (bb);
-  if (LABEL_P (note))
-    note = NEXT_INSN (note);
-
-  gcc_assert (NOTE_INSN_BASIC_BLOCK_P (note));
-  return note;
-}
-
-#ifdef ENABLE_CHECKING
-/* Helper function for check_cfg.
-   Return nonzero, if edge vector pointed to by EL has edge with TYPE in
-   its flags.  */
-static int
-has_edge_p (VEC(edge,gc) *el, int type)
-{
-  edge e;
-  edge_iterator ei;
-
-  FOR_EACH_EDGE (e, ei, el)
-    if (e->flags & type)
-      return 1;
-  return 0;
-}
-
-/* Check few properties of CFG between HEAD and TAIL.
-   If HEAD (TAIL) is NULL check from the beginning (till the end) of the
-   instruction stream.  */
-static void
-check_cfg (rtx head, rtx tail)
-{
-  rtx next_tail;
-  basic_block bb = 0;
-  int not_first = 0, not_last;
-
-  if (head == NULL)
-    head = get_insns ();
-  if (tail == NULL)
-    tail = get_last_insn ();
-  next_tail = NEXT_INSN (tail);
-
-  do
-    {      
-      not_last = head != tail;        
-
-      if (not_first)
-       gcc_assert (NEXT_INSN (PREV_INSN (head)) == head);
-      if (not_last)
-       gcc_assert (PREV_INSN (NEXT_INSN (head)) == head);
-
-      if (LABEL_P (head) 
-         || (NOTE_INSN_BASIC_BLOCK_P (head)
-             && (!not_first
-                 || (not_first && !LABEL_P (PREV_INSN (head))))))
-       {
-         gcc_assert (bb == 0);   
-         bb = BLOCK_FOR_INSN (head);
-         if (bb != 0)
-           gcc_assert (BB_HEAD (bb) == head);      
-         else
-           /* This is the case of jump table.  See inside_basic_block_p ().  */
-           gcc_assert (LABEL_P (head) && !inside_basic_block_p (head));
-       }
-
-      if (bb == 0)
-       {
-         gcc_assert (!inside_basic_block_p (head));
-         head = NEXT_INSN (head);
-       }
-      else
-       {
-         gcc_assert (inside_basic_block_p (head)
-                     || NOTE_P (head));
-         gcc_assert (BLOCK_FOR_INSN (head) == bb);
-       
-         if (LABEL_P (head))
-           {
-             head = NEXT_INSN (head);
-             gcc_assert (NOTE_INSN_BASIC_BLOCK_P (head));
-           }
-         else
-           {
-             if (control_flow_insn_p (head))
-               {
-                 gcc_assert (BB_END (bb) == head);
-                 
-                 if (any_uncondjump_p (head))
-                   gcc_assert (EDGE_COUNT (bb->succs) == 1
-                               && BARRIER_P (NEXT_INSN (head)));
-                 else if (any_condjump_p (head))
-                   gcc_assert (/* Usual case.  */
-                                (EDGE_COUNT (bb->succs) > 1
-                                 && !BARRIER_P (NEXT_INSN (head)))
-                                /* Or jump to the next instruction.  */
-                                || (EDGE_COUNT (bb->succs) == 1
-                                    && (BB_HEAD (EDGE_I (bb->succs, 0)->dest)
-                                        == JUMP_LABEL (head))));
-               }
-             if (BB_END (bb) == head)
-               {
-                 if (EDGE_COUNT (bb->succs) > 1)
-                   gcc_assert (control_flow_insn_p (head)
-                               || has_edge_p (bb->succs, EDGE_COMPLEX));
-                 bb = 0;
-               }
-                             
-             head = NEXT_INSN (head);
-           }
-       }
-
-      not_first = 1;
-    }
-  while (head != next_tail);
-
-  gcc_assert (bb == 0);
-}
-
-#endif /* ENABLE_CHECKING */
-
-const struct sched_scan_info_def *sched_scan_info;
-
-/* Extend per basic block data structures.  */
-static void
-extend_bb (void)
-{
-  if (sched_scan_info->extend_bb)
-    sched_scan_info->extend_bb ();
-}
-
-/* Init data for BB.  */
-static void
-init_bb (basic_block bb)
-{
-  if (sched_scan_info->init_bb)
-    sched_scan_info->init_bb (bb);
-}
-
-/* Extend per insn data structures.  */
-static void
-extend_insn (void)
-{
-  if (sched_scan_info->extend_insn)
-    sched_scan_info->extend_insn ();
-}
-
-/* Init data structures for INSN.  */
-static void
-init_insn (rtx insn)
-{
-  if (sched_scan_info->init_insn)
-    sched_scan_info->init_insn (insn);
-}
-
-/* Init all insns in BB.  */
-static void
-init_insns_in_bb (basic_block bb)
-{
-  rtx insn;
-
-  FOR_BB_INSNS (bb, insn)
-    init_insn (insn);
-}
-
-/* A driver function to add a set of basic blocks (BBS),
-   a single basic block (BB), a set of insns (INSNS) or a single insn (INSN)
-   to the scheduling region.  */
-void
-sched_scan (const struct sched_scan_info_def *ssi,
-           bb_vec_t bbs, basic_block bb, insn_vec_t insns, rtx insn)
-{
-  sched_scan_info = ssi;
-
-  if (bbs != NULL || bb != NULL)
-    {
-      extend_bb ();
-
-      if (bbs != NULL)
-       {
-         unsigned i;
-         basic_block x;
-
-         for (i = 0; VEC_iterate (basic_block, bbs, i, x); i++)
-           init_bb (x);
-       }
-
-      if (bb != NULL)
-       init_bb (bb);
-    }
-
-  extend_insn ();
-
-  if (bbs != NULL)
-    {      
-      unsigned i;
-      basic_block x;
-
-      for (i = 0; VEC_iterate (basic_block, bbs, i, x); i++)
-       init_insns_in_bb (x);
-    }
-
-  if (bb != NULL)
-    init_insns_in_bb (bb);
-
-  if (insns != NULL)
-    {
-      unsigned i;
-      rtx x;
-
-      for (i = 0; VEC_iterate (rtx, insns, i, x); i++)
-       init_insn (x);
-    }
-
-  if (insn != NULL)
-    init_insn (insn);
-}
-
-
 /* Extend data structures for logical insn UID.  */
-static void
-luids_extend_insn (void)
+void
+sched_extend_luids (void)
 {
   int new_luids_max_uid = get_max_uid () + 1;
 
@@ -4813,8 +6525,8 @@ luids_extend_insn (void)
 }
 
 /* Initialize LUID for INSN.  */
-static void
-luids_init_insn (rtx insn)
+void
+sched_init_insn_luid (rtx insn)
 {
   int i = INSN_P (insn) ? 1 : common_sched_info->luid_for_non_insn (insn);
   int luid;
@@ -4830,21 +6542,23 @@ luids_init_insn (rtx insn)
   SET_INSN_LUID (insn, luid);
 }
 
-/* Initialize luids for BBS, BB, INSNS and INSN.
+/* Initialize luids for BBS.
    The hook common_sched_info->luid_for_non_insn () is used to determine
    if notes, labels, etc. need luids.  */
 void
-sched_init_luids (bb_vec_t bbs, basic_block bb, insn_vec_t insns, rtx insn)
+sched_init_luids (bb_vec_t bbs)
 {
-  const struct sched_scan_info_def ssi =
+  int i;
+  basic_block bb;
+
+  sched_extend_luids ();
+  FOR_EACH_VEC_ELT (basic_block, bbs, i, bb)
     {
-      NULL, /* extend_bb */
-      NULL, /* init_bb */
-      luids_extend_insn, /* extend_insn */
-      luids_init_insn /* init_insn */
-    };
+      rtx insn;
 
-  sched_scan (&ssi, bbs, bb, insns, insn);
+      FOR_BB_INSNS (bb, insn)
+       sched_init_insn_luid (insn);
+    }
 }
 
 /* Free LUIDs.  */
@@ -4875,12 +6589,12 @@ sched_extend_target (void)
 static void
 extend_h_i_d (void)
 {
-  int reserve = (get_max_uid () + 1 
+  int reserve = (get_max_uid () + 1
                  - VEC_length (haifa_insn_data_def, h_i_d));
-  if (reserve > 0 
+  if (reserve > 0
       && ! VEC_space (haifa_insn_data_def, h_i_d, reserve))
     {
-      VEC_safe_grow_cleared (haifa_insn_data_def, heap, h_i_d, 
+      VEC_safe_grow_cleared (haifa_insn_data_def, heap, h_i_d,
                              3 * get_max_uid () / 2);
       sched_extend_target ();
     }
@@ -4894,33 +6608,48 @@ init_h_i_d (rtx insn)
   if (INSN_LUID (insn) > 0)
     {
       INSN_COST (insn) = -1;
-      find_insn_reg_weight (insn);
       QUEUE_INDEX (insn) = QUEUE_NOWHERE;
       INSN_TICK (insn) = INVALID_TICK;
+      INSN_EXACT_TICK (insn) = INVALID_TICK;
       INTER_TICK (insn) = INVALID_TICK;
       TODO_SPEC (insn) = HARD_DEP;
     }
 }
 
-/* Initialize haifa_insn_data for BBS, BB, INSNS and INSN.  */
+/* Initialize haifa_insn_data for BBS.  */
 void
-haifa_init_h_i_d (bb_vec_t bbs, basic_block bb, insn_vec_t insns, rtx insn)
+haifa_init_h_i_d (bb_vec_t bbs)
 {
-  const struct sched_scan_info_def ssi =
+  int i;
+  basic_block bb;
+
+  extend_h_i_d ();
+  FOR_EACH_VEC_ELT (basic_block, bbs, i, bb)
     {
-      NULL, /* extend_bb */
-      NULL, /* init_bb */
-      extend_h_i_d, /* extend_insn */
-      init_h_i_d /* init_insn */
-    };
+      rtx insn;
 
-  sched_scan (&ssi, bbs, bb, insns, insn);
+      FOR_BB_INSNS (bb, insn)
+       init_h_i_d (insn);
+    }
 }
 
 /* Finalize haifa_insn_data.  */
 void
 haifa_finish_h_i_d (void)
 {
+  int i;
+  haifa_insn_data_t data;
+  struct reg_use_data *use, *next;
+
+  FOR_EACH_VEC_ELT (haifa_insn_data_def, h_i_d, i, data)
+    {
+      free (data->reg_pressure);
+      for (use = data->reg_use_list; use != NULL; use = next)
+       {
+         next = use->next_insn_use;
+         free (use);
+       }
+    }
   VEC_free (haifa_insn_data_def, heap, h_i_d);
 }
 
@@ -4930,10 +6659,12 @@ haifa_init_insn (rtx insn)
 {
   gcc_assert (insn != NULL);
 
-  sched_init_luids (NULL, NULL, NULL, insn);
+  sched_extend_luids ();
+  sched_init_insn_luid (insn);
   sched_extend_target ();
   sched_deps_init (false);
-  haifa_init_h_i_d (NULL, NULL, NULL, insn);
+  extend_h_i_d ();
+  init_h_i_d (insn);
 
   if (adding_bb_to_current_region_p)
     {
@@ -4942,6 +6673,8 @@ haifa_init_insn (rtx insn)
       /* Extend dependency caches by one element.  */
       extend_dependency_caches (1, false);
     }
+  if (sched_pressure_p)
+    init_insn_reg_pressure_info (insn);
 }
 
 /* Init data for the new basic block BB which comes after AFTER.  */
@@ -4966,7 +6699,7 @@ sched_split_block_1 (basic_block first_bb, rtx after)
   e = split_block (first_bb, after);
   gcc_assert (e->src == first_bb);
 
-  /* sched_split_block emits note if *check == BB_END.  Probably it 
+  /* sched_split_block emits note if *check == BB_END.  Probably it
      is better to rip that note off.  */
 
   return e->dest;
@@ -4979,4 +6712,91 @@ sched_create_empty_bb_1 (basic_block after)
   return create_empty_bb (after);
 }
 
+/* Insert PAT as an INSN into the schedule and update the necessary data
+   structures to account for it. */
+rtx
+sched_emit_insn (rtx pat)
+{
+  rtx insn = emit_insn_before (pat, nonscheduled_insns_begin);
+  haifa_init_insn (insn);
+
+  if (current_sched_info->add_remove_insn)
+    current_sched_info->add_remove_insn (insn, 0);
+
+  (*current_sched_info->begin_schedule_ready) (insn);
+  VEC_safe_push (rtx, heap, scheduled_insns, insn);
+
+  last_scheduled_insn = insn;
+  return insn;
+}
+
+/* This function returns a candidate satisfying dispatch constraints from
+   the ready list.  */
+
+static rtx
+ready_remove_first_dispatch (struct ready_list *ready)
+{
+  int i;
+  rtx insn = ready_element (ready, 0);
+
+  if (ready->n_ready == 1
+      || INSN_CODE (insn) < 0
+      || !INSN_P (insn)
+      || !active_insn_p (insn)
+      || targetm.sched.dispatch (insn, FITS_DISPATCH_WINDOW))
+    return ready_remove_first (ready);
+
+  for (i = 1; i < ready->n_ready; i++)
+    {
+      insn = ready_element (ready, i);
+
+      if (INSN_CODE (insn) < 0
+         || !INSN_P (insn)
+         || !active_insn_p (insn))
+       continue;
+
+      if (targetm.sched.dispatch (insn, FITS_DISPATCH_WINDOW))
+       {
+         /* Return ith element of ready.  */
+         insn = ready_remove (ready, i);
+         return insn;
+       }
+    }
+
+  if (targetm.sched.dispatch (NULL_RTX, DISPATCH_VIOLATION))
+    return ready_remove_first (ready);
+
+  for (i = 1; i < ready->n_ready; i++)
+    {
+      insn = ready_element (ready, i);
+
+      if (INSN_CODE (insn) < 0
+         || !INSN_P (insn)
+         || !active_insn_p (insn))
+       continue;
+
+      /* Return i-th element of ready.  */
+      if (targetm.sched.dispatch (insn, IS_CMP))
+       return ready_remove (ready, i);
+    }
+
+  return ready_remove_first (ready);
+}
+
+/* Get number of ready insn in the ready list.  */
+
+int
+number_in_ready (void)
+{
+  return ready.n_ready;
+}
+
+/* Get number of ready's in the ready list.  */
+
+rtx
+get_ready_element (int i)
+{
+  return ready_element (&ready, i);
+}
+
 #endif /* INSN_SCHEDULING */