OSDN Git Service

Merge branch 'trunk' of git://gcc.gnu.org/git/gcc into rework
[pf3gnuchains/gcc-fork.git] / gcc / modulo-sched.c
index 62918a0..9179de5 100644 (file)
@@ -1,5 +1,5 @@
 /* Swing Modulo Scheduling implementation.
-   Copyright (C) 2004, 2005, 2006
+   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
    Contributed by Ayal Zaks and Mustafa Hagog <zaks,mustafa@il.ibm.com>
 
@@ -7,7 +7,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -16,16 +16,15 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "rtl.h"
 #include "tm_p.h"
 #include "hard-reg-set.h"
@@ -35,7 +34,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "insn-config.h"
 #include "insn-attr.h"
 #include "except.h"
-#include "toplev.h"
 #include "recog.h"
 #include "sched-int.h"
 #include "target.h"
@@ -45,10 +43,11 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "expr.h"
 #include "params.h"
 #include "gcov-io.h"
-#include "df.h"
 #include "ddg.h"
 #include "timevar.h"
 #include "tree-pass.h"
+#include "dbgcnt.h"
+#include "df.h"
 
 #ifdef INSN_SCHEDULING
 
@@ -84,8 +83,21 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
       perform modulo variable expansion for live ranges that span more than
       II cycles (i.e. use register copies to prevent a def from overwriting
       itself before reaching the use).
-*/
 
+    SMS works with countable loops (1) whose control part can be easily
+    decoupled from the rest of the loop and (2) whose loop count can
+    be easily adjusted.  This is because we peel a constant number of
+    iterations into a prologue and epilogue for which we want to avoid
+    emitting the control part, and a kernel which is to iterate that
+    constant number of iterations less than the original loop.  So the
+    control part should be a set of insns clearly identified and having
+    its own iv, not otherwise used in the loop (at-least for now), which
+    initializes a register before the loop to the number of iterations.
+    Currently SMS relies on the do-loop pattern to recognize such loops,
+    where (1) the control part comprises of all insns defining and/or
+    using a certain 'count' register and (2) the loop count can be
+    adjusted by modifying this register prior to the loop.
+    TODO: Rely on cfgloop analysis instead.  */
 \f
 /* This page defines partial-schedule structures and functions for
    modulo scheduling.  */
@@ -156,39 +168,33 @@ struct undo_replace_buff_elem
 };
 
 
-  
+
 static partial_schedule_ptr create_partial_schedule (int ii, ddg_ptr, int history);
 static void free_partial_schedule (partial_schedule_ptr);
 static void reset_partial_schedule (partial_schedule_ptr, int new_ii);
 void print_partial_schedule (partial_schedule_ptr, FILE *);
-static int kernel_number_of_cycles (rtx first_insn, rtx last_insn);
+static void verify_partial_schedule (partial_schedule_ptr, sbitmap);
 static ps_insn_ptr ps_add_node_check_conflicts (partial_schedule_ptr,
                                                ddg_node_ptr node, int cycle,
                                                sbitmap must_precede,
                                                sbitmap must_follow);
 static void rotate_partial_schedule (partial_schedule_ptr, int);
 void set_row_column_for_ps (partial_schedule_ptr);
-static bool ps_unschedule_node (partial_schedule_ptr, ddg_node_ptr );
+static void ps_insert_empty_row (partial_schedule_ptr, int, sbitmap);
+static int compute_split_row (sbitmap, int, int, int, ddg_node_ptr);
 
 \f
 /* This page defines constants and structures for the modulo scheduling
    driver.  */
 
-/* As in haifa-sched.c:  */
-/* issue_rate is the number of insns that can be scheduled in the same
-   machine cycle.  It can be defined in the config/mach/mach.h file,
-   otherwise we set it to 1.  */
-
-static int issue_rate;
-
-static int sms_order_nodes (ddg_ptr, int, int * result);
+static int sms_order_nodes (ddg_ptr, int, int *, int *);
 static void set_node_sched_params (ddg_ptr);
 static partial_schedule_ptr sms_schedule_by_order (ddg_ptr, int, int, int *);
-static void permute_partial_schedule (partial_schedule_ptr ps, rtx last);
-static void generate_prolog_epilog (partial_schedule_ptr ,struct loop * loop, rtx);
-static void duplicate_insns_of_cycles (partial_schedule_ptr ps,
-                                      int from_stage, int to_stage,
-                                      int is_prolog);
+static void permute_partial_schedule (partial_schedule_ptr, rtx);
+static void generate_prolog_epilog (partial_schedule_ptr, struct loop *,
+                                    rtx, rtx);
+static void duplicate_insns_of_cycles (partial_schedule_ptr,
+                                      int, int, int, rtx);
 
 #define SCHED_ASAP(x) (((node_sched_params_ptr)(x)->aux.info)->asap)
 #define SCHED_TIME(x) (((node_sched_params_ptr)(x)->aux.info)->time)
@@ -229,7 +235,7 @@ typedef struct node_sched_params
    code in order to use sched_analyze() for computing the dependencies.
    They are used when initializing the sched_info structure.  */
 static const char *
-sms_print_insn (rtx insn, int aligned ATTRIBUTE_UNUSED)
+sms_print_insn (const_rtx insn, int aligned ATTRIBUTE_UNUSED)
 {
   static char tmp[80];
 
@@ -245,7 +251,17 @@ compute_jump_reg_dependencies (rtx insn ATTRIBUTE_UNUSED,
 {
 }
 
-static struct sched_info sms_sched_info =
+static struct common_sched_info_def sms_common_sched_info;
+
+static struct sched_deps_info_def sms_sched_deps_info =
+  {
+    compute_jump_reg_dependencies,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL,
+    0, 0, 0
+  };
+
+static struct haifa_sched_info sms_sched_info =
 {
   NULL,
   NULL,
@@ -254,33 +270,30 @@ static struct sched_info sms_sched_info =
   NULL,
   sms_print_insn,
   NULL,
-  compute_jump_reg_dependencies,
+  NULL, /* insn_finishes_block_p */
   NULL, NULL,
   NULL, NULL,
-  0, 0, 0,
+  0, 0,
 
-  NULL, NULL, NULL, NULL, NULL,
-#ifdef ENABLE_CHECKING
-  NULL,
-#endif
+  NULL, NULL, NULL,
   0
 };
 
-
-/* Return the register decremented and tested in INSN,
-   or zero if it is not a decrement-and-branch insn.  */
-
+/* Given HEAD and TAIL which are the first and last insns in a loop;
+   return the register which controls the loop.  Return zero if it has
+   more than one occurrence in the loop besides the control part or the
+   do-loop pattern is not of the form we expect.  */
 static rtx
-doloop_register_get (rtx insn ATTRIBUTE_UNUSED)
+doloop_register_get (rtx head ATTRIBUTE_UNUSED, rtx tail ATTRIBUTE_UNUSED)
 {
 #ifdef HAVE_doloop_end
-  rtx pattern, reg, condition;
+  rtx reg, condition, insn, first_insn_not_to_check;
 
-  if (! JUMP_P (insn))
+  if (!JUMP_P (tail))
     return NULL_RTX;
 
-  pattern = PATTERN (insn);
-  condition = doloop_condition_get (pattern);
+  /* TODO: Free SMS's dependence on doloop_condition_get.  */
+  condition = doloop_condition_get (tail);
   if (! condition)
     return NULL_RTX;
 
@@ -292,6 +305,27 @@ doloop_register_get (rtx insn ATTRIBUTE_UNUSED)
   else
     gcc_unreachable ();
 
+  /* Check that the COUNT_REG has no other occurrences in the loop
+     until the decrement.  We assume the control part consists of
+     either a single (parallel) branch-on-count or a (non-parallel)
+     branch immediately preceded by a single (decrement) insn.  */
+  first_insn_not_to_check = (GET_CODE (PATTERN (tail)) == PARALLEL ? tail
+                             : PREV_INSN (tail));
+
+  for (insn = head; insn != first_insn_not_to_check; insn = NEXT_INSN (insn))
+    if (reg_mentioned_p (reg, insn))
+      {
+        if (dump_file)
+        {
+          fprintf (dump_file, "SMS count_reg found ");
+          print_rtl_single (dump_file, reg);
+          fprintf (dump_file, " outside control in insn:\n");
+          print_rtl_single (dump_file, insn);
+        }
+
+        return NULL_RTX;
+      }
+
   return reg;
 #else
   return NULL_RTX;
@@ -315,12 +349,12 @@ const_iteration_count (rtx count_reg, basic_block pre_header,
   get_ebb_head_tail (pre_header, pre_header, &head, &tail);
 
   for (insn = tail; insn != PREV_INSN (head); insn = PREV_INSN (insn))
-    if (INSN_P (insn) && single_set (insn) &&
+    if (NONDEBUG_INSN_P (insn) && single_set (insn) &&
        rtx_equal_p (count_reg, SET_DEST (single_set (insn))))
       {
        rtx pat = single_set (insn);
 
-       if (GET_CODE (SET_SRC (pat)) == CONST_INT)
+       if (CONST_INT_P (SET_SRC (pat)))
          {
            *count = INTVAL (SET_SRC (pat));
            return insn;
@@ -338,7 +372,10 @@ const_iteration_count (rtx count_reg, basic_block pre_header,
 static int
 res_MII (ddg_ptr g)
 {
-  return (g->num_nodes / issue_rate);
+  if (targetm.sched.sms_res_mii)
+    return targetm.sched.sms_res_mii (g);
+
+  return ((g->num_nodes - g->num_debug) / issue_rate);
 }
 
 
@@ -370,7 +407,7 @@ set_node_sched_params (ddg_ptr g)
 }
 
 static void
-print_node_sched_params (FILE * file, int num_nodes)
+print_node_sched_params (FILE *file, int num_nodes, ddg_ptr g)
 {
   int i;
 
@@ -382,7 +419,8 @@ print_node_sched_params (FILE * file, int num_nodes)
       rtx reg_move = nsp->first_reg_move;
       int j;
 
-      fprintf (file, "Node %d:\n", i);
+      fprintf (file, "Node = %d; INSN = %d\n", i,
+              (INSN_UID (g->nodes[i].insn)));
       fprintf (file, " asap = %d:\n", nsp->asap);
       fprintf (file, " time = %d:\n", nsp->time);
       fprintf (file, " nreg_moves = %d:\n", nsp->nreg_moves);
@@ -395,29 +433,6 @@ print_node_sched_params (FILE * file, int num_nodes)
     }
 }
 
-/* Calculate an upper bound for II.  SMS should not schedule the loop if it
-   requires more cycles than this bound.  Currently set to the sum of the
-   longest latency edge for each node.  Reset based on experiments.  */
-static int
-calculate_maxii (ddg_ptr g)
-{
-  int i;
-  int maxii = 0;
-
-  for (i = 0; i < g->num_nodes; i++)
-    {
-      ddg_node_ptr u = &g->nodes[i];
-      ddg_edge_ptr e;
-      int max_edge_latency = 0;
-
-      for (e = u->out; e; e = e->next_out)
-       max_edge_latency = MAX (max_edge_latency, e->latency);
-
-      maxii += max_edge_latency;
-    }
-  return maxii;
-}
-
 /*
    Breaking intra-loop register anti-dependences:
    Each intra-loop register anti-dependence implies a cross-iteration true
@@ -430,7 +445,7 @@ calculate_maxii (ddg_ptr g)
                             ii                          { 1 if not.
 */
 static struct undo_replace_buff_elem *
-generate_reg_moves (partial_schedule_ptr ps)
+generate_reg_moves (partial_schedule_ptr ps, bool rescan)
 {
   ddg_ptr g = ps->g;
   int ii = ps->ii;
@@ -493,7 +508,9 @@ generate_reg_moves (partial_schedule_ptr ps)
       /* Now generate the reg_moves, attaching relevant uses to them.  */
       SCHED_NREG_MOVES (u) = nreg_moves;
       old_reg = prev_reg = copy_rtx (SET_DEST (single_set (u->insn)));
-      last_reg_move = u->insn;
+      /* Insert the reg-moves right before the notes which precede
+         the insn they relates to.  */
+      last_reg_move = u->first_note;
 
       for (i_reg_move = 0; i_reg_move < nreg_moves; i_reg_move++)
        {
@@ -502,7 +519,7 @@ generate_reg_moves (partial_schedule_ptr ps)
          rtx reg_move = gen_move_insn (new_reg, prev_reg);
          sbitmap_iterator sbi;
 
-         add_insn_before (reg_move, last_reg_move);
+         add_insn_before (reg_move, last_reg_move, NULL);
          last_reg_move = reg_move;
 
          if (!SCHED_FIRST_REG_MOVE (u))
@@ -527,6 +544,8 @@ generate_reg_moves (partial_schedule_ptr ps)
                }
 
              replace_rtx (g->nodes[i_use].insn, old_reg, new_reg);
+             if (rescan)
+               df_insn_rescan (g->nodes[i_use].insn);
            }
 
          prev_reg = new_reg;
@@ -536,40 +555,6 @@ generate_reg_moves (partial_schedule_ptr ps)
   return reg_move_replaces;
 }
 
-/* We call this when we want to undo the SMS schedule for a given loop.
-   One of the things that we do is to delete the register moves generated
-   for the sake of SMS; this function deletes the register move instructions
-   recorded in the undo buffer.  */
-static void
-undo_generate_reg_moves (partial_schedule_ptr ps,
-                        struct undo_replace_buff_elem *reg_move_replaces)
-{
-  int i,j;
-
-  for (i = 0; i < ps->g->num_nodes; i++)
-    {
-      ddg_node_ptr u = &ps->g->nodes[i];
-      rtx prev;
-      rtx crr = SCHED_FIRST_REG_MOVE (u);
-
-      for (j = 0; j < SCHED_NREG_MOVES (u); j++)
-       {
-         prev = PREV_INSN (crr);
-         delete_insn (crr);
-         crr = prev;
-       }
-      SCHED_FIRST_REG_MOVE (u) = NULL_RTX;
-    }
-
-  while (reg_move_replaces)
-    {
-      struct undo_replace_buff_elem *rep = reg_move_replaces;
-
-      reg_move_replaces = reg_move_replaces->next;
-      replace_rtx (rep->insn, rep->new_reg, rep->orig_reg);
-    }
-}
-
 /* Free memory allocated for the undo buffer.  */
 static void
 free_undo_replace_buff (struct undo_replace_buff_elem *reg_move_replaces)
@@ -589,23 +574,27 @@ free_undo_replace_buff (struct undo_replace_buff_elem *reg_move_replaces)
 static void
 normalize_sched_times (partial_schedule_ptr ps)
 {
-  int i;
-  ddg_ptr g = ps->g;
+  int row;
   int amount = PS_MIN_CYCLE (ps);
   int ii = ps->ii;
+  ps_insn_ptr crr_insn;
 
-  /* Don't include the closing branch assuming that it is the last node.  */
-  for (i = 0; i < g->num_nodes - 1; i++)
-    {
-      ddg_node_ptr u = &g->nodes[i];
-      int normalized_time = SCHED_TIME (u) - amount;
-
-      gcc_assert (normalized_time >= 0);
-
-      SCHED_TIME (u) = normalized_time;
-      SCHED_ROW (u) = normalized_time % ii;
-      SCHED_STAGE (u) = normalized_time / ii;
-    }
+  for (row = 0; row < ii; row++)
+    for (crr_insn = ps->rows[row]; crr_insn; crr_insn = crr_insn->next_in_row)
+      {
+       ddg_node_ptr u = crr_insn->node;
+       int normalized_time = SCHED_TIME (u) - amount;
+
+       if (dump_file)
+         fprintf (dump_file, "crr_insn->node=%d, crr_insn->cycle=%d,\
+                  min_cycle=%d\n", crr_insn->node->cuid, SCHED_TIME
+                  (u), ps->min_cycle);
+       gcc_assert (SCHED_TIME (u) >= ps->min_cycle);
+       gcc_assert (SCHED_TIME (u) <= ps->max_cycle);
+       SCHED_TIME (u) = normalized_time;
+       SCHED_ROW (u) = normalized_time % ii;
+       SCHED_STAGE (u) = normalized_time / ii;
+      }
 }
 
 /* Set SCHED_COLUMN of each node according to its position in PS.  */
@@ -641,31 +630,9 @@ permute_partial_schedule (partial_schedule_ptr ps, rtx last)
                            PREV_INSN (last));
 }
 
-/* As part of undoing SMS we return to the original ordering of the
-   instructions inside the loop kernel.  Given the partial schedule PS, this
-   function returns the ordering of the instruction according to their CUID
-   in the DDG (PS->G), which is the original order of the instruction before
-   performing SMS.  */
-static void
-undo_permute_partial_schedule (partial_schedule_ptr ps, rtx last)
-{
-  int i;
-
-  for (i = 0 ; i < ps->g->num_nodes; i++)
-    if (last == ps->g->nodes[i].insn
-       || last == ps->g->nodes[i].first_note)
-      break;
-    else if (PREV_INSN (last) != ps->g->nodes[i].insn)
-      reorder_insns_nobb (ps->g->nodes[i].first_note, ps->g->nodes[i].insn,
-                         PREV_INSN (last));
-}
-
-/* Used to generate the prologue & epilogue.  Duplicate the subset of
-   nodes whose stages are between FROM_STAGE and TO_STAGE (inclusive
-   of both), together with a prefix/suffix of their reg_moves.  */
 static void
 duplicate_insns_of_cycles (partial_schedule_ptr ps, int from_stage,
-                          int to_stage, int for_prolog)
+                          int to_stage, int for_prolog, rtx count_reg)
 {
   int row;
   ps_insn_ptr ps_ij;
@@ -677,6 +644,13 @@ duplicate_insns_of_cycles (partial_schedule_ptr ps, int from_stage,
        int j, i_reg_moves;
        rtx reg_move = NULL_RTX;
 
+        /* Do not duplicate any insn which refers to count_reg as it
+           belongs to the control part.
+           TODO: This should be done by analyzing the control part of
+           the loop.  */
+        if (reg_mentioned_p (count_reg, u_node->insn))
+          continue;
+
        if (for_prolog)
          {
            /* SCHED_STAGE (u_node) >= from_stage == 0.  Generate increasing
@@ -725,7 +699,8 @@ duplicate_insns_of_cycles (partial_schedule_ptr ps, int from_stage,
 
 /* Generate the instructions (including reg_moves) for prolog & epilog.  */
 static void
-generate_prolog_epilog (partial_schedule_ptr ps, struct loop * loop, rtx count_reg)
+generate_prolog_epilog (partial_schedule_ptr ps, struct loop *loop,
+                        rtx count_reg, rtx count_init)
 {
   int i;
   int last_stage = PS_STAGE_COUNT (ps) - 1;
@@ -734,17 +709,28 @@ generate_prolog_epilog (partial_schedule_ptr ps, struct loop * loop, rtx count_r
   /* Generate the prolog, inserting its insns on the loop-entry edge.  */
   start_sequence ();
 
-  if (count_reg)
-   /* Generate a subtract instruction at the beginning of the prolog to
-      adjust the loop count by STAGE_COUNT.  */
-   emit_insn (gen_sub2_insn (count_reg, GEN_INT (last_stage)));
+  if (!count_init)
+    {
+      /* Generate instructions at the beginning of the prolog to
+         adjust the loop count by STAGE_COUNT.  If loop count is constant
+         (count_init), this constant is adjusted by STAGE_COUNT in
+         generate_prolog_epilog function.  */
+      rtx sub_reg = NULL_RTX;
+
+      sub_reg = expand_simple_binop (GET_MODE (count_reg), MINUS,
+                                     count_reg, GEN_INT (last_stage),
+                                     count_reg, 1, OPTAB_DIRECT);
+      gcc_assert (REG_P (sub_reg));
+      if (REGNO (sub_reg) != REGNO (count_reg))
+        emit_move_insn (count_reg, sub_reg);
+    }
 
   for (i = 0; i < last_stage; i++)
-    duplicate_insns_of_cycles (ps, 0, i, 1);
+    duplicate_insns_of_cycles (ps, 0, i, 1, count_reg);
 
   /* Put the prolog on the entry edge.  */
   e = loop_preheader_edge (loop);
-  split_edge_and_insert (e, get_insns());
+  split_edge_and_insert (e, get_insns ());
 
   end_sequence ();
 
@@ -752,12 +738,12 @@ generate_prolog_epilog (partial_schedule_ptr ps, struct loop * loop, rtx count_r
   start_sequence ();
 
   for (i = 0; i < last_stage; i++)
-    duplicate_insns_of_cycles (ps, i + 1, last_stage, 0);
+    duplicate_insns_of_cycles (ps, i + 1, last_stage, 0, count_reg);
 
   /* Put the epilogue on the exit edge.  */
-  gcc_assert (loop->single_exit);
-  e = loop->single_exit;
-  split_edge_and_insert (e, get_insns());
+  gcc_assert (single_exit (loop));
+  e = single_exit (loop);
+  split_edge_and_insert (e, get_insns ());
   end_sequence ();
 }
 
@@ -783,7 +769,7 @@ loop_single_full_bb_p (struct loop *loop)
       for (; head != NEXT_INSN (tail); head = NEXT_INSN (head))
         {
           if (NOTE_P (head) || LABEL_P (head)
-             || (INSN_P (head) && JUMP_P (head)))
+             || (INSN_P (head) && (DEBUG_INSN_P (head) || JUMP_P (head))))
            continue;
          empty_bb = false;
          break;
@@ -811,14 +797,22 @@ static bool
 loop_canon_p (struct loop *loop)
 {
 
-  if (loop->inner || ! loop->outer)
+  if (loop->inner || !loop_outer (loop))
+  {
+    if (dump_file)
+      fprintf (dump_file, "SMS loop inner or !loop_outer\n");
     return false;
+  }
 
-  if (!loop->single_exit)
+  if (!single_exit (loop))
     {
       if (dump_file)
        {
+         rtx insn = BB_END (loop->header);
+
          fprintf (dump_file, "SMS loop many exits ");
+                 fprintf (dump_file, " %s %d (file, line)\n",
+                          insn_file (insn), insn_line (insn));
        }
       return false;
     }
@@ -827,7 +821,11 @@ loop_canon_p (struct loop *loop)
     {
       if (dump_file)
        {
+         rtx insn = BB_END (loop->header);
+
          fprintf (dump_file, "SMS loop many BBs. ");
+         fprintf (dump_file, " %s %d (file, line)\n",
+                  insn_file (insn), insn_line (insn));
        }
       return false;
     }
@@ -860,30 +858,50 @@ canon_loop (struct loop *loop)
     }
 }
 
+/* Setup infos.  */
+static void
+setup_sched_infos (void)
+{
+  memcpy (&sms_common_sched_info, &haifa_common_sched_info,
+         sizeof (sms_common_sched_info));
+  sms_common_sched_info.sched_pass_id = SCHED_SMS_PASS;
+  common_sched_info = &sms_common_sched_info;
+
+  sched_deps_info = &sms_sched_deps_info;
+  current_sched_info = &sms_sched_info;
+}
+
+/* Probability in % that the sms-ed loop rolls enough so that optimized
+   version may be entered.  Just a guess.  */
+#define PROB_SMS_ENOUGH_ITERATIONS 80
+
+/* Used to calculate the upper bound of ii.  */
+#define MAXII_FACTOR 2
+
 /* Main entry point, perform SMS scheduling on the loops of the function
    that consist of single basic blocks.  */
 static void
 sms_schedule (void)
 {
-  static int passes = 0;
   rtx insn;
   ddg_ptr *g_arr, g;
   int * node_order;
-  int maxii;
-  unsigned i,num_loops;
+  int maxii, max_asap;
+  loop_iterator li;
   partial_schedule_ptr ps;
-  struct df *df;
   basic_block bb = NULL;
-  /* vars to the versioning only if needed*/
-  struct loop * nloop;
+  struct loop *loop;
   basic_block condition_bb = NULL;
   edge latch_edge;
   gcov_type trip_count = 0;
 
   loop_optimizer_init (LOOPS_HAVE_PREHEADERS
-                      | LOOPS_HAVE_MARKED_SINGLE_EXITS);
-  if (!current_loops)
-    return;  /* There are no loops to schedule.  */
+                      | LOOPS_HAVE_RECORDED_EXITS);
+  if (number_of_loops () <= 1)
+    {
+      loop_optimizer_finalize ();
+      return;  /* There are no loops to schedule.  */
+    }
 
   /* Initialize issue_rate.  */
   if (targetm.sched.issue_rate)
@@ -898,62 +916,71 @@ sms_schedule (void)
     issue_rate = 1;
 
   /* Initialize the scheduler.  */
-  current_sched_info = &sms_sched_info;
-  sched_init ();
-
-  /* Init Data Flow analysis, to be used in interloop dep calculation.  */
-  df = df_init (DF_HARD_REGS | DF_EQUIV_NOTES | DF_SUBREGS);
-  df_rd_add_problem (df, 0);
-  df_ru_add_problem (df, 0);
-  df_chain_add_problem (df, DF_DU_CHAIN | DF_UD_CHAIN);
-  df_analyze (df);
-
-  if (dump_file)
-    df_dump (df, dump_file);
+  setup_sched_infos ();
+  haifa_sched_init ();
 
   /* Allocate memory to hold the DDG array one entry for each loop.
      We use loop->num as index into this array.  */
-  g_arr = XCNEWVEC (ddg_ptr, current_loops->num);
+  g_arr = XCNEWVEC (ddg_ptr, number_of_loops ());
 
+  if (dump_file)
+  {
+    fprintf (dump_file, "\n\nSMS analysis phase\n");
+    fprintf (dump_file, "===================\n\n");
+  }
 
   /* Build DDGs for all the relevant loops and hold them in G_ARR
      indexed by the loop index.  */
-  for (i = 0; i < current_loops->num; i++)
+  FOR_EACH_LOOP (li, loop, 0)
     {
       rtx head, tail;
       rtx count_reg;
-      struct loop *loop = current_loops->parray[i];
 
       /* For debugging.  */
-      if ((passes++ > MAX_SMS_LOOP_NUMBER) && (MAX_SMS_LOOP_NUMBER != -1))
+      if (dbg_cnt (sms_sched_loop) == false)
         {
           if (dump_file)
-            fprintf (dump_file, "SMS reached MAX_PASSES... \n");
+            fprintf (dump_file, "SMS reached max limit... \n");
 
           break;
         }
 
+      if (dump_file)
+      {
+         rtx insn = BB_END (loop->header);
+
+         fprintf (dump_file, "SMS loop num: %d, file: %s, line: %d\n",
+                  loop->num, insn_file (insn), insn_line (insn));
+
+      }
+
       if (! loop_canon_p (loop))
         continue;
 
       if (! loop_single_full_bb_p (loop))
+      {
+        if (dump_file)
+          fprintf (dump_file, "SMS not loop_single_full_bb_p\n");
        continue;
+      }
 
       bb = loop->header;
 
       get_ebb_head_tail (bb, bb, &head, &tail);
       latch_edge = loop_latch_edge (loop);
-      gcc_assert (loop->single_exit);
-      if (loop->single_exit->count)
-       trip_count = latch_edge->count / loop->single_exit->count;
+      gcc_assert (single_exit (loop));
+      if (single_exit (loop)->count)
+       trip_count = latch_edge->count / single_exit (loop)->count;
 
-      /* Perfrom SMS only on loops that their average count is above threshold.  */
+      /* Perform SMS only on loops that their average count is above threshold.  */
 
       if ( latch_edge->count
-          && (latch_edge->count < loop->single_exit->count * SMS_LOOP_AVERAGE_COUNT_THRESHOLD))
+          && (latch_edge->count < single_exit (loop)->count * SMS_LOOP_AVERAGE_COUNT_THRESHOLD))
        {
          if (dump_file)
            {
+             fprintf (dump_file, " %s %d (file, line)\n",
+                      insn_file (tail), insn_line (tail));
              fprintf (dump_file, "SMS single-bb-loop\n");
              if (profile_info && flag_branch_probabilities)
                {
@@ -975,16 +1002,31 @@ sms_schedule (void)
         }
 
       /* Make sure this is a doloop.  */
-      if ( !(count_reg = doloop_register_get (tail)))
+      if ( !(count_reg = doloop_register_get (head, tail)))
+      {
+        if (dump_file)
+          fprintf (dump_file, "SMS doloop_register_get failed\n");
        continue;
+      }
 
-      /* Don't handle BBs with calls or barriers, or !single_set insns.  */
-      for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn))
-       if (CALL_P (insn)
-           || BARRIER_P (insn)
-           || (INSN_P (insn) && !JUMP_P (insn)
-               && !single_set (insn) && GET_CODE (PATTERN (insn)) != USE))
-         break;
+      /* Don't handle BBs with calls or barriers, or !single_set insns,
+         or auto-increment insns (to avoid creating invalid reg-moves
+         for the auto-increment insns).
+         ??? Should handle auto-increment insns.
+         ??? Should handle insns defining subregs.  */
+     for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn))
+      {
+         rtx set;
+
+        if (CALL_P (insn)
+            || BARRIER_P (insn)
+            || (NONDEBUG_INSN_P (insn) && !JUMP_P (insn)
+                && !single_set (insn) && GET_CODE (PATTERN (insn)) != USE)
+            || (FIND_REG_INC_NOTE (insn, NULL_RTX) != 0)
+            || (INSN_P (insn) && (set = single_set (insn))
+                && GET_CODE (SET_DEST (set)) == SUBREG))
+        break;
+      }
 
       if (insn != NEXT_INSN (tail))
        {
@@ -994,55 +1036,70 @@ sms_schedule (void)
                fprintf (dump_file, "SMS loop-with-call\n");
              else if (BARRIER_P (insn))
                fprintf (dump_file, "SMS loop-with-barrier\n");
-             else
-               fprintf (dump_file, "SMS loop-with-not-single-set\n");
+              else if (FIND_REG_INC_NOTE (insn, NULL_RTX) != 0)
+                fprintf (dump_file, "SMS reg inc\n");
+              else if ((NONDEBUG_INSN_P (insn) && !JUMP_P (insn)
+                && !single_set (insn) && GET_CODE (PATTERN (insn)) != USE))
+                fprintf (dump_file, "SMS loop-with-not-single-set\n");
+              else
+               fprintf (dump_file, "SMS loop with subreg in lhs\n");
              print_rtl_single (dump_file, insn);
            }
 
          continue;
        }
 
-      if (! (g = create_ddg (bb, df, 0)))
+      if (! (g = create_ddg (bb, 0)))
         {
           if (dump_file)
-           fprintf (dump_file, "SMS doloop\n");
+           fprintf (dump_file, "SMS create_ddg failed\n");
          continue;
         }
 
-      g_arr[i] = g;
-    }
+      g_arr[loop->num] = g;
+      if (dump_file)
+        fprintf (dump_file, "...OK\n");
 
-  /* Release Data Flow analysis data structures.  */
-  df_finish (df);
-  df = NULL;
+    }
+  if (dump_file)
+  {
+    fprintf (dump_file, "\nSMS transformation phase\n");
+    fprintf (dump_file, "=========================\n\n");
+  }
 
   /* We don't want to perform SMS on new loops - created by versioning.  */
-  num_loops = current_loops->num;
-  /* Go over the built DDGs and perfrom SMS for each one of them.  */
-  for (i = 0; i < num_loops; i++)
+  FOR_EACH_LOOP (li, loop, 0)
     {
       rtx head, tail;
       rtx count_reg, count_init;
       int mii, rec_mii;
       unsigned stage_count = 0;
       HOST_WIDEST_INT loop_count = 0;
-      struct loop *loop = current_loops->parray[i];
 
-      if (! (g = g_arr[i]))
+      if (! (g = g_arr[loop->num]))
         continue;
 
       if (dump_file)
-       print_ddg (dump_file, g);
+      {
+         rtx insn = BB_END (loop->header);
+
+         fprintf (dump_file, "SMS loop num: %d, file: %s, line: %d\n",
+                  loop->num, insn_file (insn), insn_line (insn));
+
+         print_ddg (dump_file, g);
+      }
 
       get_ebb_head_tail (loop->header, loop->header, &head, &tail);
 
       latch_edge = loop_latch_edge (loop);
-      gcc_assert (loop->single_exit);
-      if (loop->single_exit->count)
-       trip_count = latch_edge->count / loop->single_exit->count;
+      gcc_assert (single_exit (loop));
+      if (single_exit (loop)->count)
+       trip_count = latch_edge->count / single_exit (loop)->count;
 
       if (dump_file)
        {
+         fprintf (dump_file, " %s %d (file, line)\n",
+                  insn_file (tail), insn_line (tail));
          fprintf (dump_file, "SMS single-bb-loop\n");
          if (profile_info && flag_branch_probabilities)
            {
@@ -1065,7 +1122,7 @@ sms_schedule (void)
       /* In case of th loop have doloop register it gets special
         handling.  */
       count_init = NULL_RTX;
-      if ((count_reg = doloop_register_get (tail)))
+      if ((count_reg = doloop_register_get (head, tail)))
        {
          basic_block pre_header;
 
@@ -1086,9 +1143,9 @@ sms_schedule (void)
       node_order = XNEWVEC (int, g->num_nodes);
 
       mii = 1; /* Need to pass some estimate of mii.  */
-      rec_mii = sms_order_nodes (g, mii, node_order);
+      rec_mii = sms_order_nodes (g, mii, node_order, &max_asap);
       mii = MAX (res_MII (g), rec_mii);
-      maxii = (calculate_maxii (g) * SMS_MAX_II_FACTOR) / 100;
+      maxii = MAX (max_asap, MAXII_FACTOR * mii);
 
       if (dump_file)
        fprintf (dump_file, "SMS iis %d %d %d (rec_mii, mii, maxii)\n",
@@ -1100,12 +1157,14 @@ sms_schedule (void)
 
       ps = sms_schedule_by_order (g, mii, maxii, node_order);
 
-      if (ps)
+      if (ps){
        stage_count = PS_STAGE_COUNT (ps);
+        gcc_assert(stage_count >= 1);
+      }
 
       /* Stage count of 1 means that there is no interleaving between
          iterations, let the scheduling passes do the job.  */
-      if (stage_count < 1
+      if (stage_count <= 1
          || (count_init && (loop_count <= stage_count))
          || (flag_branch_probabilities && (trip_count <= stage_count)))
        {
@@ -1122,8 +1181,6 @@ sms_schedule (void)
        }
       else
        {
-         int orig_cycles = kernel_number_of_cycles (BB_HEAD (g->bb), BB_END (g->bb));
-         int new_cycles;
          struct undo_replace_buff_elem *reg_move_replaces;
 
          if (dump_file)
@@ -1141,69 +1198,50 @@ sms_schedule (void)
             the closing_branch was scheduled and should appear in the last (ii-1)
             row.  Otherwise, we are free to schedule the branch, and we let nodes
             that were scheduled at the first PS_MIN_CYCLE cycle appear in the first
-            row; this should reduce stage_count to minimum.  */
+            row; this should reduce stage_count to minimum.
+             TODO: Revisit the issue of scheduling the insns of the
+             control part relative to the branch when the control part
+             has more than one insn.  */
          normalize_sched_times (ps);
          rotate_partial_schedule (ps, PS_MIN_CYCLE (ps));
          set_columns_for_ps (ps);
 
-         /* Generate the kernel just to be able to measure its cycles.  */
-         permute_partial_schedule (ps, g->closing_branch->first_note);
-         reg_move_replaces = generate_reg_moves (ps);
+         canon_loop (loop);
 
-         /* Get the number of cycles the new kernel expect to execute in.  */
-         new_cycles = kernel_number_of_cycles (BB_HEAD (g->bb), BB_END (g->bb));
+          /* case the BCT count is not known , Do loop-versioning */
+         if (count_reg && ! count_init)
+            {
+             rtx comp_rtx = gen_rtx_fmt_ee (GT, VOIDmode, count_reg,
+                                            GEN_INT(stage_count));
+             unsigned prob = (PROB_SMS_ENOUGH_ITERATIONS
+                              * REG_BR_PROB_BASE) / 100;
 
-         /* Get back to the original loop so we can do loop versioning.  */
-         undo_permute_partial_schedule (ps, g->closing_branch->first_note);
-         if (reg_move_replaces)
-           undo_generate_reg_moves (ps, reg_move_replaces);
+             loop_version (loop, comp_rtx, &condition_bb,
+                           prob, prob, REG_BR_PROB_BASE - prob,
+                           true);
+            }
 
-         if ( new_cycles >= orig_cycles)
-           {
-             /* SMS is not profitable so undo the permutation and reg move generation
-                and return the kernel to its original state.  */
-             if (dump_file)
-               fprintf (dump_file, "Undoing SMS because it is not profitable.\n");
+         /* Set new iteration count of loop kernel.  */
+          if (count_reg && count_init)
+           SET_SRC (single_set (count_init)) = GEN_INT (loop_count
+                                                    - stage_count + 1);
 
-           }
-         else
-           {
-             canon_loop (loop);
+         /* Now apply the scheduled kernel to the RTL of the loop.  */
+         permute_partial_schedule (ps, g->closing_branch->first_note);
 
-              /* case the BCT count is not known , Do loop-versioning */
-             if (count_reg && ! count_init)
-               {
-                 rtx comp_rtx = gen_rtx_fmt_ee (GT, VOIDmode, count_reg,
-                                                GEN_INT(stage_count));
+          /* Mark this loop as software pipelined so the later
+            scheduling passes doesn't touch it.  */
+         if (! flag_resched_modulo_sched)
+           g->bb->flags |= BB_DISABLE_SCHEDULE;
+         /* The life-info is not valid any more.  */
+         df_set_bb_dirty (g->bb);
 
-                 nloop = loop_version (current_loops, loop, comp_rtx,
-                                       &condition_bb, true);
-               }
+         reg_move_replaces = generate_reg_moves (ps, true);
+         if (dump_file)
+           print_node_sched_params (dump_file, g->num_nodes, g);
+         /* Generate prolog and epilog.  */
+          generate_prolog_epilog (ps, loop, count_reg, count_init);
 
-             /* Set new iteration count of loop kernel.  */
-              if (count_reg && count_init)
-               SET_SRC (single_set (count_init)) = GEN_INT (loop_count
-                                                            - stage_count + 1);
-
-             /* Now apply the scheduled kernel to the RTL of the loop.  */
-             permute_partial_schedule (ps, g->closing_branch->first_note);
-
-              /* Mark this loop as software pipelined so the later
-             scheduling passes doesn't touch it.  */
-             if (! flag_resched_modulo_sched)
-               g->bb->flags |= BB_DISABLE_SCHEDULE;
-             /* The life-info is not valid any more.  */
-             g->bb->flags |= BB_DIRTY;
-
-             reg_move_replaces = generate_reg_moves (ps);
-             if (dump_file)
-               print_node_sched_params (dump_file, g->num_nodes);
-             /* Generate prolog and epilog.  */
-             if (count_reg && !count_init)
-               generate_prolog_epilog (ps, loop, count_reg);
-             else
-               generate_prolog_epilog (ps, loop, NULL_RTX);
-           }
          free_undo_replace_buff (reg_move_replaces);
        }
 
@@ -1216,7 +1254,7 @@ sms_schedule (void)
   free (g_arr);
 
   /* Release scheduler data, needed until now because of DFA.  */
-  sched_finish ();
+  haifa_sched_finish ();
   loop_optimizer_finalize ();
 }
 
@@ -1296,6 +1334,9 @@ sms_schedule (void)
    set to 0 to save compile time.  */
 #define DFA_HISTORY SMS_DFA_HISTORY
 
+/* A threshold for the number of repeated unsuccessful attempts to insert
+   an empty row, before we flush the partial schedule and start over.  */
+#define MAX_SPLIT_NUM 10
 /* Given the partial schedule PS, this function calculates and returns the
    cycles in which we can schedule the node with the given index I.
    NOTE: Here we do the backtracking in SMS, in some special cases. We have
@@ -1334,20 +1375,45 @@ get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i,
       for (e = u_node->in; e != 0; e = e->next_in)
        {
          ddg_node_ptr v_node = e->src;
+
+          if (dump_file)
+            {
+             fprintf (dump_file, "\nProcessing edge: ");
+              print_ddg_edge (dump_file, e);
+             fprintf (dump_file,
+                      "\nScheduling %d (%d) in psp_not_empty,"
+                      " checking p %d (%d): ", u_node->cuid,
+                      INSN_UID (u_node->insn), v_node->cuid, INSN_UID
+                      (v_node->insn));
+            }
+
          if (TEST_BIT (sched_nodes, v_node->cuid))
            {
-             int node_st = SCHED_TIME (v_node)
-                           + e->latency - (e->distance * ii);
+              int p_st = SCHED_TIME (v_node);
 
-             early_start = MAX (early_start, node_st);
+              early_start =
+                MAX (early_start, p_st + e->latency - (e->distance * ii));
+
+              if (dump_file)
+                fprintf (dump_file,
+                         "pred st = %d; early_start = %d; latency: %d",
+                         p_st, early_start, e->latency);
 
              if (e->data_type == MEM_DEP)
                end = MIN (end, SCHED_TIME (v_node) + ii - 1);
            }
+         else if (dump_file)
+            fprintf (dump_file, "the node is not scheduled\n");
        }
       start = early_start;
       end = MIN (end, early_start + ii);
+      /* Schedule the node close to it's predecessors.  */
       step = 1;
+
+      if (dump_file)
+        fprintf (dump_file,
+                "\nScheduling %d (%d) in a window (%d..%d) with step %d\n",
+                u_node->cuid, INSN_UID (u_node->insn), start, end, step);
     }
 
   else if (!psp_not_empty && pss_not_empty)
@@ -1358,24 +1424,58 @@ get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i,
       for (e = u_node->out; e != 0; e = e->next_out)
        {
          ddg_node_ptr v_node = e->dest;
+
+          if (dump_file)
+            {
+              fprintf (dump_file, "\nProcessing edge:");
+              print_ddg_edge (dump_file, e);
+              fprintf (dump_file,
+                       "\nScheduling %d (%d) in pss_not_empty,"
+                       " checking s %d (%d): ", u_node->cuid,
+                       INSN_UID (u_node->insn), v_node->cuid, INSN_UID
+                       (v_node->insn));
+            }
+
          if (TEST_BIT (sched_nodes, v_node->cuid))
            {
-             late_start = MIN (late_start,
-                               SCHED_TIME (v_node) - e->latency
-                               + (e->distance * ii));
+              int s_st = SCHED_TIME (v_node);
+
+              late_start = MIN (late_start,
+                                s_st - e->latency + (e->distance * ii));
+
+              if (dump_file)
+                fprintf (dump_file,
+                         "succ st = %d; late_start = %d; latency = %d",
+                         s_st, late_start, e->latency);
+
              if (e->data_type == MEM_DEP)
                end = MAX (end, SCHED_TIME (v_node) - ii + 1);
+             if (dump_file)
+                 fprintf (dump_file, "end = %d\n", end);
+
            }
+          else if (dump_file)
+            fprintf (dump_file, "the node is not scheduled\n");
+
        }
       start = late_start;
       end = MAX (end, late_start - ii);
+      /* Schedule the node close to it's successors.  */
       step = -1;
+
+      if (dump_file)
+        fprintf (dump_file,
+                 "\nScheduling %d (%d) in a window (%d..%d) with step %d\n",
+                 u_node->cuid, INSN_UID (u_node->insn), start, end, step);
+
     }
 
   else if (psp_not_empty && pss_not_empty)
     {
       int early_start = INT_MIN;
       int late_start = INT_MAX;
+      int count_preds = 0;
+      int count_succs = 0;
 
       start = INT_MIN;
       end = INT_MAX;
@@ -1383,31 +1483,91 @@ get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i,
        {
          ddg_node_ptr v_node = e->src;
 
+         if (dump_file)
+           {
+              fprintf (dump_file, "\nProcessing edge:");
+              print_ddg_edge (dump_file, e);
+             fprintf (dump_file,
+                      "\nScheduling %d (%d) in psp_pss_not_empty,"
+                      " checking p %d (%d): ", u_node->cuid, INSN_UID
+                      (u_node->insn), v_node->cuid, INSN_UID
+                      (v_node->insn));
+           }
+
          if (TEST_BIT (sched_nodes, v_node->cuid))
            {
+              int p_st = SCHED_TIME (v_node);
+
              early_start = MAX (early_start,
-                                SCHED_TIME (v_node) + e->latency
+                                p_st + e->latency
                                 - (e->distance * ii));
+
+              if (dump_file)
+                fprintf (dump_file,
+                         "pred st = %d; early_start = %d; latency = %d",
+                         p_st, early_start, e->latency);
+
+              if (e->type == TRUE_DEP && e->data_type == REG_DEP)
+                count_preds++;
+
              if (e->data_type == MEM_DEP)
                end = MIN (end, SCHED_TIME (v_node) + ii - 1);
            }
+          else if (dump_file)
+            fprintf (dump_file, "the node is not scheduled\n");
+
        }
       for (e = u_node->out; e != 0; e = e->next_out)
        {
          ddg_node_ptr v_node = e->dest;
 
+         if (dump_file)
+           {
+              fprintf (dump_file, "\nProcessing edge:");
+              print_ddg_edge (dump_file, e);
+             fprintf (dump_file,
+                      "\nScheduling %d (%d) in psp_pss_not_empty,"
+                      " checking s %d (%d): ", u_node->cuid, INSN_UID
+                      (u_node->insn), v_node->cuid, INSN_UID
+                      (v_node->insn));
+           }
+
          if (TEST_BIT (sched_nodes, v_node->cuid))
            {
+              int s_st = SCHED_TIME (v_node);
+
              late_start = MIN (late_start,
-                               SCHED_TIME (v_node) - e->latency
+                               s_st - e->latency
                                + (e->distance * ii));
+
+              if (dump_file)
+                fprintf (dump_file,
+                         "succ st = %d; late_start = %d; latency = %d",
+                         s_st, late_start, e->latency);
+
+               if (e->type == TRUE_DEP && e->data_type == REG_DEP)
+                 count_succs++;
+
              if (e->data_type == MEM_DEP)
                start = MAX (start, SCHED_TIME (v_node) - ii + 1);
            }
+          else if (dump_file)
+            fprintf (dump_file, "the node is not scheduled\n");
+
        }
       start = MAX (start, early_start);
       end = MIN (end, MIN (early_start + ii, late_start + 1));
       step = 1;
+      /* If there are more successors than predecessors schedule the
+         node close to it's successors.  */
+      if (count_succs >= count_preds)
+        {
+          int old_start = start;
+
+          start = end - 1;
+          end = old_start - 1;
+          step = -1;
+        }
     }
   else /* psp is empty && pss is empty.  */
     {
@@ -1423,21 +1583,152 @@ get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i,
   sbitmap_free (pss);
 
   if ((start >= end && step == 1) || (start <= end && step == -1))
+    {
+      if (dump_file)
+       fprintf (dump_file, "\nEmpty window: start=%d, end=%d, step=%d\n",
+                start, end, step);
     return -1;
-  else
+    }
+
     return 0;
 }
 
+/* Calculate MUST_PRECEDE/MUST_FOLLOW bitmaps of U_NODE; which is the
+   node currently been scheduled.  At the end of the calculation
+   MUST_PRECEDE/MUST_FOLLOW contains all predecessors/successors of
+   U_NODE which are (1) already scheduled in the first/last row of
+   U_NODE's scheduling window, (2) whose dependence inequality with U
+   becomes an equality when U is scheduled in this same row, and (3)
+   whose dependence latency is zero.
+
+   The first and last rows are calculated using the following parameters:
+   START/END rows - The cycles that begins/ends the traversal on the window;
+   searching for an empty cycle to schedule U_NODE.
+   STEP - The direction in which we traverse the window.
+   II - The initiation interval.  */
+
+static void
+calculate_must_precede_follow (ddg_node_ptr u_node, int start, int end,
+                              int step, int ii, sbitmap sched_nodes,
+                              sbitmap must_precede, sbitmap must_follow)
+{
+  ddg_edge_ptr e;
+  int first_cycle_in_window, last_cycle_in_window;
+
+  gcc_assert (must_precede && must_follow);
+
+  /* Consider the following scheduling window:
+     {first_cycle_in_window, first_cycle_in_window+1, ...,
+     last_cycle_in_window}.  If step is 1 then the following will be
+     the order we traverse the window: {start=first_cycle_in_window,
+     first_cycle_in_window+1, ..., end=last_cycle_in_window+1},
+     or {start=last_cycle_in_window, last_cycle_in_window-1, ...,
+     end=first_cycle_in_window-1} if step is -1.  */
+  first_cycle_in_window = (step == 1) ? start : end - step;
+  last_cycle_in_window = (step == 1) ? end - step : start;
+
+  sbitmap_zero (must_precede);
+  sbitmap_zero (must_follow);
+
+  if (dump_file)
+    fprintf (dump_file, "\nmust_precede: ");
+
+  /* Instead of checking if:
+      (SMODULO (SCHED_TIME (e->src), ii) == first_row_in_window)
+      && ((SCHED_TIME (e->src) + e->latency - (e->distance * ii)) ==
+             first_cycle_in_window)
+      && e->latency == 0
+     we use the fact that latency is non-negative:
+      SCHED_TIME (e->src) - (e->distance * ii) <=
+      SCHED_TIME (e->src) + e->latency - (e->distance * ii)) <=
+      first_cycle_in_window
+     and check only if
+      SCHED_TIME (e->src) - (e->distance * ii) == first_cycle_in_window  */
+  for (e = u_node->in; e != 0; e = e->next_in)
+    if (TEST_BIT (sched_nodes, e->src->cuid)
+       && ((SCHED_TIME (e->src) - (e->distance * ii)) ==
+             first_cycle_in_window))
+      {
+       if (dump_file)
+         fprintf (dump_file, "%d ", e->src->cuid);
+
+       SET_BIT (must_precede, e->src->cuid);
+      }
+
+  if (dump_file)
+    fprintf (dump_file, "\nmust_follow: ");
+
+  /* Instead of checking if:
+      (SMODULO (SCHED_TIME (e->dest), ii) == last_row_in_window)
+      && ((SCHED_TIME (e->dest) - e->latency + (e->distance * ii)) ==
+             last_cycle_in_window)
+      && e->latency == 0
+     we use the fact that latency is non-negative:
+      SCHED_TIME (e->dest) + (e->distance * ii) >=
+      SCHED_TIME (e->dest) - e->latency + (e->distance * ii)) >=
+      last_cycle_in_window
+     and check only if
+      SCHED_TIME (e->dest) + (e->distance * ii) == last_cycle_in_window  */
+  for (e = u_node->out; e != 0; e = e->next_out)
+    if (TEST_BIT (sched_nodes, e->dest->cuid)
+       && ((SCHED_TIME (e->dest) + (e->distance * ii)) ==
+             last_cycle_in_window))
+      {
+       if (dump_file)
+         fprintf (dump_file, "%d ", e->dest->cuid);
+
+       SET_BIT (must_follow, e->dest->cuid);
+      }
+
+  if (dump_file)
+    fprintf (dump_file, "\n");
+}
+
+/* Return 1 if U_NODE can be scheduled in CYCLE.  Use the following
+   parameters to decide if that's possible:
+   PS - The partial schedule.
+   U - The serial number of U_NODE.
+   NUM_SPLITS - The number of row splits made so far.
+   MUST_PRECEDE - The nodes that must precede U_NODE. (only valid at
+   the first row of the scheduling window)
+   MUST_FOLLOW - The nodes that must follow U_NODE. (only valid at the
+   last row of the scheduling window)  */
+
+static bool
+try_scheduling_node_in_cycle (partial_schedule_ptr ps, ddg_node_ptr u_node,
+                             int u, int cycle, sbitmap sched_nodes,
+                             int *num_splits, sbitmap must_precede,
+                             sbitmap must_follow)
+{
+  ps_insn_ptr psi;
+  bool success = 0;
+
+  verify_partial_schedule (ps, sched_nodes);
+  psi = ps_add_node_check_conflicts (ps, u_node, cycle,
+                                    must_precede, must_follow);
+  if (psi)
+    {
+      SCHED_TIME (u_node) = cycle;
+      SET_BIT (sched_nodes, u);
+      success = 1;
+      *num_splits = 0;
+      if (dump_file)
+       fprintf (dump_file, "Scheduled w/o split in %d\n", cycle);
+
+    }
+
+  return success;
+}
+
 /* This function implements the scheduling algorithm for SMS according to the
    above algorithm.  */
 static partial_schedule_ptr
 sms_schedule_by_order (ddg_ptr g, int mii, int maxii, int *nodes_order)
 {
   int ii = mii;
-  int i, c, success;
-  int try_again_with_larger_ii = true;
+  int i, c, success, num_splits = 0;
+  int flush_and_start_over = true;
   int num_nodes = g->num_nodes;
-  ddg_edge_ptr e;
   int start, end, step; /* Place together into one struct?  */
   sbitmap sched_nodes = sbitmap_alloc (num_nodes);
   sbitmap must_precede = sbitmap_alloc (num_nodes);
@@ -1449,19 +1740,13 @@ sms_schedule_by_order (ddg_ptr g, int mii, int maxii, int *nodes_order)
   sbitmap_ones (tobe_scheduled);
   sbitmap_zero (sched_nodes);
 
-  while ((! sbitmap_equal (tobe_scheduled, sched_nodes)
-        || try_again_with_larger_ii ) && ii < maxii)
+  while (flush_and_start_over && (ii < maxii))
     {
-      int j;
-      bool unscheduled_nodes = false;
 
       if (dump_file)
-       fprintf(dump_file, "Starting with ii=%d\n", ii);
-      if (try_again_with_larger_ii)
-       {
-         try_again_with_larger_ii = false;
-         sbitmap_zero (sched_nodes);
-       }
+       fprintf (dump_file, "Starting with ii=%d\n", ii);
+      flush_and_start_over = false;
+      sbitmap_zero (sched_nodes);
 
       for (i = 0; i < num_nodes; i++)
        {
@@ -1469,7 +1754,7 @@ sms_schedule_by_order (ddg_ptr g, int mii, int maxii, int *nodes_order)
          ddg_node_ptr u_node = &ps->g->nodes[u];
          rtx insn = u_node->insn;
 
-         if (!INSN_P (insn))
+         if (!NONDEBUG_INSN_P (insn))
            {
              RESET_BIT (tobe_scheduled, u);
              continue;
@@ -1485,94 +1770,262 @@ sms_schedule_by_order (ddg_ptr g, int mii, int maxii, int *nodes_order)
            continue;
 
          /* Try to get non-empty scheduling window.  */
-         j = i;
-         while (get_sched_window (ps, nodes_order, i, sched_nodes, ii, &start, &step, &end) < 0
-                && j > 0)
-           {
-             unscheduled_nodes = true;
-             if (TEST_BIT (NODE_PREDECESSORS (u_node), nodes_order[j - 1])
-                 || TEST_BIT (NODE_SUCCESSORS (u_node), nodes_order[j - 1]))
-               {
-                 ps_unschedule_node (ps, &ps->g->nodes[nodes_order[j - 1]]);
-                 RESET_BIT (sched_nodes, nodes_order [j - 1]);
-               }
-             j--;
-           }
-         if (j < 0)
-           {
-             /* ??? Try backtracking instead of immediately ii++?  */
-             ii++;
-             try_again_with_larger_ii = true;
-             reset_partial_schedule (ps, ii);
-             break;
-           }
-         /* 2. Try scheduling u in window.  */
-         if (dump_file)
-           fprintf(dump_file, "Trying to schedule node %d in (%d .. %d) step %d\n",
-                   u, start, end, step);
-
-          /* use must_follow & must_precede bitmaps to determine order
-            of nodes within the cycle.  */
-          sbitmap_zero (must_precede);
-          sbitmap_zero (must_follow);
-         for (e = u_node->in; e != 0; e = e->next_in)
-            if (TEST_BIT (sched_nodes, e->src->cuid)
-               && e->latency == (ii * e->distance)
-               && start == SCHED_TIME (e->src))
-             SET_BIT (must_precede, e->src->cuid);
-
-         for (e = u_node->out; e != 0; e = e->next_out)
-            if (TEST_BIT (sched_nodes, e->dest->cuid)
-               && e->latency == (ii * e->distance)
-               && end == SCHED_TIME (e->dest))
-             SET_BIT (must_follow, e->dest->cuid);
-
-         success = 0;
-         if ((step > 0 && start < end) ||  (step < 0 && start > end))
-           for (c = start; c != end; c += step)
-             {
-               ps_insn_ptr psi;
-
-               psi = ps_add_node_check_conflicts (ps, u_node, c,
-                                                  must_precede,
-                                                  must_follow);
-
-               if (psi)
-                 {
-                   SCHED_TIME (u_node) = c;
-                   SET_BIT (sched_nodes, u);
-                   success = 1;
-                   if (dump_file)
-                     fprintf(dump_file, "Schedule in %d\n", c);
-                   break;
-                 }
-             }
-         if (!success)
-           {
-             /* ??? Try backtracking instead of immediately ii++?  */
-             ii++;
-             try_again_with_larger_ii = true;
-             reset_partial_schedule (ps, ii);
-             break;
-           }
-         if (unscheduled_nodes)
-           break;
-
-         /* ??? If (success), check register pressure estimates.  */
-       } /* Continue with next node.  */
-    } /* While try_again_with_larger_ii.  */
+        success = 0;
+         if (get_sched_window (ps, nodes_order, i, sched_nodes, ii, &start,
+                                &step, &end) == 0)
+            {
+              if (dump_file)
+                fprintf (dump_file, "\nTrying to schedule node %d \
+                        INSN = %d  in (%d .. %d) step %d\n", u, (INSN_UID
+                        (g->nodes[u].insn)), start, end, step);
+
+              gcc_assert ((step > 0 && start < end)
+                          || (step < 0 && start > end));
+
+              calculate_must_precede_follow (u_node, start, end, step, ii,
+                                             sched_nodes, must_precede,
+                                             must_follow);
+
+              for (c = start; c != end; c += step)
+                {
+                  sbitmap tmp_precede = NULL;
+                  sbitmap tmp_follow = NULL;
+
+                  if (c == start)
+                    {
+                      if (step == 1)
+                        tmp_precede = must_precede;
+                      else      /* step == -1.  */
+                        tmp_follow = must_follow;
+                    }
+                  if (c == end - step)
+                    {
+                      if (step == 1)
+                        tmp_follow = must_follow;
+                      else      /* step == -1.  */
+                        tmp_precede = must_precede;
+                    }
+
+                  success =
+                    try_scheduling_node_in_cycle (ps, u_node, u, c,
+                                                  sched_nodes,
+                                                  &num_splits, tmp_precede,
+                                                  tmp_follow);
+                  if (success)
+                    break;
+                }
+
+              verify_partial_schedule (ps, sched_nodes);
+            }
+            if (!success)
+            {
+              int split_row;
+
+              if (ii++ == maxii)
+                break;
+
+              if (num_splits >= MAX_SPLIT_NUM)
+                {
+                  num_splits = 0;
+                  flush_and_start_over = true;
+                  verify_partial_schedule (ps, sched_nodes);
+                  reset_partial_schedule (ps, ii);
+                  verify_partial_schedule (ps, sched_nodes);
+                  break;
+                }
+
+              num_splits++;
+              /* The scheduling window is exclusive of 'end'
+                 whereas compute_split_window() expects an inclusive,
+                 ordered range.  */
+              if (step == 1)
+                split_row = compute_split_row (sched_nodes, start, end - 1,
+                                               ps->ii, u_node);
+              else
+                split_row = compute_split_row (sched_nodes, end + 1, start,
+                                               ps->ii, u_node);
+
+              ps_insert_empty_row (ps, split_row, sched_nodes);
+              i--;              /* Go back and retry node i.  */
+
+              if (dump_file)
+                fprintf (dump_file, "num_splits=%d\n", num_splits);
+            }
+
+          /* ??? If (success), check register pressure estimates.  */
+        }                       /* Continue with next node.  */
+    }                           /* While flush_and_start_over.  */
+  if (ii >= maxii)
+    {
+      free_partial_schedule (ps);
+      ps = NULL;
+    }
+  else
+    gcc_assert (sbitmap_equal (tobe_scheduled, sched_nodes));
 
   sbitmap_free (sched_nodes);
   sbitmap_free (must_precede);
   sbitmap_free (must_follow);
   sbitmap_free (tobe_scheduled);
 
-  if (ii >= maxii)
+  return ps;
+}
+
+/* This function inserts a new empty row into PS at the position
+   according to SPLITROW, keeping all already scheduled instructions
+   intact and updating their SCHED_TIME and cycle accordingly.  */
+static void
+ps_insert_empty_row (partial_schedule_ptr ps, int split_row,
+                    sbitmap sched_nodes)
+{
+  ps_insn_ptr crr_insn;
+  ps_insn_ptr *rows_new;
+  int ii = ps->ii;
+  int new_ii = ii + 1;
+  int row;
+
+  verify_partial_schedule (ps, sched_nodes);
+
+  /* We normalize sched_time and rotate ps to have only non-negative sched
+     times, for simplicity of updating cycles after inserting new row.  */
+  split_row -= ps->min_cycle;
+  split_row = SMODULO (split_row, ii);
+  if (dump_file)
+    fprintf (dump_file, "split_row=%d\n", split_row);
+
+  normalize_sched_times (ps);
+  rotate_partial_schedule (ps, ps->min_cycle);
+
+  rows_new = (ps_insn_ptr *) xcalloc (new_ii, sizeof (ps_insn_ptr));
+  for (row = 0; row < split_row; row++)
     {
-      free_partial_schedule (ps);
-      ps = NULL;
+      rows_new[row] = ps->rows[row];
+      ps->rows[row] = NULL;
+      for (crr_insn = rows_new[row];
+          crr_insn; crr_insn = crr_insn->next_in_row)
+       {
+         ddg_node_ptr u = crr_insn->node;
+         int new_time = SCHED_TIME (u) + (SCHED_TIME (u) / ii);
+
+         SCHED_TIME (u) = new_time;
+         crr_insn->cycle = new_time;
+         SCHED_ROW (u) = new_time % new_ii;
+         SCHED_STAGE (u) = new_time / new_ii;
+       }
+
     }
-  return ps;
+
+  rows_new[split_row] = NULL;
+
+  for (row = split_row; row < ii; row++)
+    {
+      rows_new[row + 1] = ps->rows[row];
+      ps->rows[row] = NULL;
+      for (crr_insn = rows_new[row + 1];
+          crr_insn; crr_insn = crr_insn->next_in_row)
+       {
+         ddg_node_ptr u = crr_insn->node;
+         int new_time = SCHED_TIME (u) + (SCHED_TIME (u) / ii) + 1;
+
+         SCHED_TIME (u) = new_time;
+         crr_insn->cycle = new_time;
+         SCHED_ROW (u) = new_time % new_ii;
+         SCHED_STAGE (u) = new_time / new_ii;
+       }
+    }
+
+  /* Updating ps.  */
+  ps->min_cycle = ps->min_cycle + ps->min_cycle / ii
+    + (SMODULO (ps->min_cycle, ii) >= split_row ? 1 : 0);
+  ps->max_cycle = ps->max_cycle + ps->max_cycle / ii
+    + (SMODULO (ps->max_cycle, ii) >= split_row ? 1 : 0);
+  free (ps->rows);
+  ps->rows = rows_new;
+  ps->ii = new_ii;
+  gcc_assert (ps->min_cycle >= 0);
+
+  verify_partial_schedule (ps, sched_nodes);
+
+  if (dump_file)
+    fprintf (dump_file, "min_cycle=%d, max_cycle=%d\n", ps->min_cycle,
+            ps->max_cycle);
+}
+
+/* Given U_NODE which is the node that failed to be scheduled; LOW and
+   UP which are the boundaries of it's scheduling window; compute using
+   SCHED_NODES and II a row in the partial schedule that can be split
+   which will separate a critical predecessor from a critical successor
+   thereby expanding the window, and return it.  */
+static int
+compute_split_row (sbitmap sched_nodes, int low, int up, int ii,
+                  ddg_node_ptr u_node)
+{
+  ddg_edge_ptr e;
+  int lower = INT_MIN, upper = INT_MAX;
+  ddg_node_ptr crit_pred = NULL;
+  ddg_node_ptr crit_succ = NULL;
+  int crit_cycle;
+
+  for (e = u_node->in; e != 0; e = e->next_in)
+    {
+      ddg_node_ptr v_node = e->src;
+
+      if (TEST_BIT (sched_nodes, v_node->cuid)
+         && (low == SCHED_TIME (v_node) + e->latency - (e->distance * ii)))
+       if (SCHED_TIME (v_node) > lower)
+         {
+           crit_pred = v_node;
+           lower = SCHED_TIME (v_node);
+         }
+    }
+
+  if (crit_pred != NULL)
+    {
+      crit_cycle = SCHED_TIME (crit_pred) + 1;
+      return SMODULO (crit_cycle, ii);
+    }
+
+  for (e = u_node->out; e != 0; e = e->next_out)
+    {
+      ddg_node_ptr v_node = e->dest;
+      if (TEST_BIT (sched_nodes, v_node->cuid)
+         && (up == SCHED_TIME (v_node) - e->latency + (e->distance * ii)))
+       if (SCHED_TIME (v_node) < upper)
+         {
+           crit_succ = v_node;
+           upper = SCHED_TIME (v_node);
+         }
+    }
+
+  if (crit_succ != NULL)
+    {
+      crit_cycle = SCHED_TIME (crit_succ);
+      return SMODULO (crit_cycle, ii);
+    }
+
+  if (dump_file)
+    fprintf (dump_file, "Both crit_pred and crit_succ are NULL\n");
+
+  return SMODULO ((low + up + 1) / 2, ii);
+}
+
+static void
+verify_partial_schedule (partial_schedule_ptr ps, sbitmap sched_nodes)
+{
+  int row;
+  ps_insn_ptr crr_insn;
+
+  for (row = 0; row < ps->ii; row++)
+    for (crr_insn = ps->rows[row]; crr_insn; crr_insn = crr_insn->next_in_row)
+      {
+       ddg_node_ptr u = crr_insn->node;
+
+       gcc_assert (TEST_BIT (sched_nodes, u->cuid));
+       /* ??? Test also that all nodes of sched_nodes are in ps, perhaps by
+          popcount (sched_nodes) == number of insns in ps.  */
+       gcc_assert (SCHED_TIME (u) >= ps->min_cycle);
+       gcc_assert (SCHED_TIME (u) <= ps->max_cycle);
+      }
 }
 
 \f
@@ -1591,7 +2044,7 @@ typedef struct node_order_params * nopa;
 
 static void order_nodes_of_sccs (ddg_all_sccs_ptr, int * result);
 static int order_nodes_in_scc (ddg_ptr, sbitmap, sbitmap, int*, int);
-static nopa  calculate_order_params (ddg_ptr, int mii);
+static nopa  calculate_order_params (ddg_ptr, int, int *);
 static int find_max_asap (ddg_ptr, sbitmap);
 static int find_max_hv_min_mob (ddg_ptr, sbitmap);
 static int find_max_dv_min_mob (ddg_ptr, sbitmap);
@@ -1614,29 +2067,40 @@ check_nodes_order (int *node_order, int num_nodes)
 
   sbitmap_zero (tmp);
 
+  if (dump_file)
+    fprintf (dump_file, "SMS final nodes order: \n");
+
   for (i = 0; i < num_nodes; i++)
     {
       int u = node_order[i];
 
+      if (dump_file)
+        fprintf (dump_file, "%d ", u);
       gcc_assert (u < num_nodes && u >= 0 && !TEST_BIT (tmp, u));
 
       SET_BIT (tmp, u);
     }
 
+  if (dump_file)
+    fprintf (dump_file, "\n");
+
   sbitmap_free (tmp);
 }
 
 /* Order the nodes of G for scheduling and pass the result in
    NODE_ORDER.  Also set aux.count of each node to ASAP.
-   Return the recMII for the given DDG.  */
+   Put maximal ASAP to PMAX_ASAP.  Return the recMII for the given DDG.  */
 static int
-sms_order_nodes (ddg_ptr g, int mii, int * node_order)
+sms_order_nodes (ddg_ptr g, int mii, int * node_order, int *pmax_asap)
 {
   int i;
   int rec_mii = 0;
   ddg_all_sccs_ptr sccs = create_ddg_all_sccs (g);
 
-  nopa nops = calculate_order_params (g, mii);
+  nopa nops = calculate_order_params (g, mii, pmax_asap);
+
+  if (dump_file)
+    print_sccs (dump_file, sccs, g);
 
   order_nodes_of_sccs (sccs, node_order);
 
@@ -1672,7 +2136,7 @@ order_nodes_of_sccs (ddg_all_sccs_ptr all_sccs, int * node_order)
   sbitmap_zero (prev_sccs);
   sbitmap_ones (ones);
 
-  /* Perfrom the node ordering starting from the SCC with the highest recMII.
+  /* Perform the node ordering starting from the SCC with the highest recMII.
      For each SCC order the nodes according to their ASAP/ALAP/HEIGHT etc.  */
   for (i = 0; i < all_sccs->num_sccs; i++)
     {
@@ -1708,7 +2172,7 @@ order_nodes_of_sccs (ddg_all_sccs_ptr all_sccs, int * node_order)
 
 /* MII is needed if we consider backarcs (that do not close recursive cycles).  */
 static struct node_order_params *
-calculate_order_params (ddg_ptr g, int mii ATTRIBUTE_UNUSED)
+calculate_order_params (ddg_ptr g, int mii ATTRIBUTE_UNUSED, int *pmax_asap)
 {
   int u;
   int max_asap;
@@ -1759,7 +2223,19 @@ calculate_order_params (ddg_ptr g, int mii ATTRIBUTE_UNUSED)
                                   HEIGHT (e->dest) + e->latency);
          }
     }
+  if (dump_file)
+  {
+    fprintf (dump_file, "\nOrder params\n");
+    for (u = 0; u < num_nodes; u++)
+      {
+        ddg_node_ptr u_node = &g->nodes[u];
 
+        fprintf (dump_file, "node %d, ASAP: %d, ALAP: %d, HEIGHT: %d\n", u,
+                 ASAP (u_node), ALAP (u_node), HEIGHT (u_node));
+      }
+  }
+
+  *pmax_asap = max_asap;
   return node_order_params_arr;
 }
 
@@ -2026,7 +2502,7 @@ print_partial_schedule (partial_schedule_ptr ps, FILE *dump)
     {
       ps_insn_ptr ps_i = ps->rows[i];
 
-      fprintf (dump, "\n[CYCLE %d ]: ", i);
+      fprintf (dump, "\n[ROW %d ]: ", i);
       while (ps_i)
        {
          fprintf (dump, "%d, ",
@@ -2109,10 +2585,10 @@ ps_insn_find_column (partial_schedule_ptr ps, ps_insn_ptr ps_i,
        next_ps_i;
        next_ps_i = next_ps_i->next_in_row)
     {
-      if (TEST_BIT (must_follow, next_ps_i->node->cuid)
+      if (must_follow && TEST_BIT (must_follow, next_ps_i->node->cuid)
          && ! first_must_follow)
         first_must_follow = next_ps_i;
-      if (TEST_BIT (must_precede, next_ps_i->node->cuid))
+      if (must_precede && TEST_BIT (must_precede, next_ps_i->node->cuid))
         {
           /* If we have already met a node that must follow, then
             there is no possible column.  */
@@ -2146,8 +2622,8 @@ ps_insn_find_column (partial_schedule_ptr ps, ps_insn_ptr ps_i,
 }
 
 /* Advances the PS_INSN one column in its current row; returns false
-   in failure and true in success.  Bit N is set in MUST_FOLLOW if 
-   the node with cuid N must be come after the node pointed to by 
+   in failure and true in success.  Bit N is set in MUST_FOLLOW if
+   the node with cuid N must be come after the node pointed to by
    PS_I when scheduled in the same cycle.  */
 static int
 ps_insn_advance_column (partial_schedule_ptr ps, ps_insn_ptr ps_i,
@@ -2169,7 +2645,7 @@ ps_insn_advance_column (partial_schedule_ptr ps, ps_insn_ptr ps_i,
 
   /* Check if next_in_row is dependent on ps_i, both having same sched
      times (typically ANTI_DEP).  If so, ps_i cannot skip over it.  */
-  if (TEST_BIT (must_follow, next_node->cuid))
+  if (must_follow && TEST_BIT (must_follow, next_node->cuid))
     return false;
 
   /* Advance PS_I over its next_in_row in the doubly linked list.  */
@@ -2195,9 +2671,9 @@ ps_insn_advance_column (partial_schedule_ptr ps, ps_insn_ptr ps_i,
 }
 
 /* Inserts a DDG_NODE to the given partial schedule at the given cycle.
-   Returns 0 if this is not possible and a PS_INSN otherwise.  Bit N is 
-   set in MUST_PRECEDE/MUST_FOLLOW if the node with cuid N must be come 
-   before/after (respectively) the node pointed to by PS_I when scheduled 
+   Returns 0 if this is not possible and a PS_INSN otherwise.  Bit N is
+   set in MUST_PRECEDE/MUST_FOLLOW if the node with cuid N must be come
+   before/after (respectively) the node pointed to by PS_I when scheduled
    in the same cycle.  */
 static ps_insn_ptr
 add_node_to_ps (partial_schedule_ptr ps, ddg_node_ptr node, int cycle,
@@ -2242,57 +2718,7 @@ advance_one_cycle (void)
                      targetm.sched.dfa_post_cycle_insn ());
 }
 
-/* Given the kernel of a loop (from FIRST_INSN to LAST_INSN), finds
-   the number of cycles according to DFA that the kernel fits in,
-   we use this to check if we done well with SMS after we add
-   register moves.  In some cases register moves overhead makes
-   it even worse than the original loop.  We want SMS to be performed
-   when it gives less cycles after register moves are added.  */
-static int
-kernel_number_of_cycles (rtx first_insn, rtx last_insn)
-{
-  int cycles = 0;
-  rtx insn;
-  int can_issue_more = issue_rate;
-
-  state_reset (curr_state);
 
-  for (insn = first_insn;
-       insn != NULL_RTX && insn != last_insn;
-       insn = NEXT_INSN (insn))
-    {
-      if (! INSN_P (insn) || GET_CODE (PATTERN (insn)) == USE)
-       continue;
-
-      /* Check if there is room for the current insn.  */
-      if (!can_issue_more || state_dead_lock_p (curr_state))
-       {
-         cycles ++;
-         advance_one_cycle ();
-         can_issue_more = issue_rate;
-       }
-
-       /* Update the DFA state and return with failure if the DFA found
-          recource conflicts.  */
-      if (state_transition (curr_state, insn) >= 0)
-       {
-         cycles ++;
-         advance_one_cycle ();
-         can_issue_more = issue_rate;
-       }
-
-      if (targetm.sched.variable_issue)
-       can_issue_more =
-         targetm.sched.variable_issue (sched_dump, sched_verbose,
-                                       insn, can_issue_more);
-      /* A naked CLOBBER or USE generates no instruction, so don't
-        let them consume issue slots.  */
-      else if (GET_CODE (PATTERN (insn)) != USE
-              && GET_CODE (PATTERN (insn)) != CLOBBER)
-       can_issue_more--;
-    }
-  return cycles;
-}
 
 /* Checks if PS has resource conflicts according to DFA, starting from
    FROM cycle to TO cycle; returns true if there are conflicts and false
@@ -2317,7 +2743,7 @@ ps_has_conflicts (partial_schedule_ptr ps, int from, int to)
        {
          rtx insn = crr_insn->node->insn;
 
-         if (!INSN_P (insn))
+         if (!NONDEBUG_INSN_P (insn))
            continue;
 
          /* Check if there is room for the current insn.  */
@@ -2325,7 +2751,7 @@ ps_has_conflicts (partial_schedule_ptr ps, int from, int to)
            return true;
 
          /* Update the DFA state and return with failure if the DFA found
-            recource conflicts.  */
+            resource conflicts.  */
          if (state_transition (curr_state, insn) >= 0)
            return true;
 
@@ -2348,8 +2774,8 @@ ps_has_conflicts (partial_schedule_ptr ps, int from, int to)
 
 /* Checks if the given node causes resource conflicts when added to PS at
    cycle C.  If not the node is added to PS and returned; otherwise zero
-   is returned.  Bit N is set in MUST_PRECEDE/MUST_FOLLOW if the node with 
-   cuid N must be come before/after (respectively) the node pointed to by 
+   is returned.  Bit N is set in MUST_PRECEDE/MUST_FOLLOW if the node with
+   cuid N must be come before/after (respectively) the node pointed to by
    PS_I when scheduled in the same cycle.  */
 ps_insn_ptr
 ps_add_node_check_conflicts (partial_schedule_ptr ps, ddg_node_ptr n,
@@ -2422,26 +2848,6 @@ rotate_partial_schedule (partial_schedule_ptr ps, int start_cycle)
   ps->min_cycle -= start_cycle;
 }
 
-/* Remove the node N from the partial schedule PS; because we restart the DFA
-   each time we want to check for resource conflicts; this is equivalent to
-   unscheduling the node N.  */
-static bool
-ps_unschedule_node (partial_schedule_ptr ps, ddg_node_ptr n)
-{
-  ps_insn_ptr ps_i;
-  int row = SMODULO (SCHED_TIME (n), ps->ii);
-
-  if (row < 0 || row > ps->ii)
-    return false;
-
-  for (ps_i = ps->rows[row];
-       ps_i &&  ps_i->node != n;
-       ps_i = ps_i->next_in_row);
-  if (!ps_i)
-    return false;
-
-  return remove_node_from_ps (ps, ps_i);
-}
 #endif /* INSN_SCHEDULING */
 \f
 static bool
@@ -2459,35 +2865,27 @@ rest_of_handle_sms (void)
 #ifdef INSN_SCHEDULING
   basic_block bb;
 
-  /* We want to be able to create new pseudos.  */
-  no_new_pseudos = 0;
   /* Collect loop information to be used in SMS.  */
-  cfg_layout_initialize (CLEANUP_UPDATE_LIFE);
+  cfg_layout_initialize (0);
   sms_schedule ();
 
   /* Update the life information, because we add pseudos.  */
   max_regno = max_reg_num ();
-  allocate_reg_info (max_regno, FALSE, FALSE);
-  update_life_info (NULL, UPDATE_LIFE_GLOBAL_RM_NOTES,
-                    (PROP_DEATH_NOTES
-                     | PROP_REG_INFO
-                     | PROP_KILL_DEAD_CODE
-                     | PROP_SCAN_DEAD_CODE));
-
-  no_new_pseudos = 1;
 
   /* Finalize layout changes.  */
   FOR_EACH_BB (bb)
     if (bb->next_bb != EXIT_BLOCK_PTR)
       bb->aux = bb->next_bb;
-  cfg_layout_finalize ();
   free_dominance_info (CDI_DOMINATORS);
+  cfg_layout_finalize ();
 #endif /* INSN_SCHEDULING */
   return 0;
 }
 
-struct tree_opt_pass pass_sms =
+struct rtl_opt_pass pass_sms =
 {
+ {
+  RTL_PASS,
   "sms",                                /* name */
   gate_handle_sms,                      /* gate */
   rest_of_handle_sms,                   /* execute */
@@ -2499,8 +2897,9 @@ struct tree_opt_pass pass_sms =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   TODO_dump_func,                       /* todo_flags_start */
+  TODO_df_finish | TODO_verify_rtl_sharing |
   TODO_dump_func |
-  TODO_ggc_collect,                     /* todo_flags_finish */
-  'm'                                   /* letter */
+  TODO_ggc_collect                      /* todo_flags_finish */
+ }
 };