OSDN Git Service

PR libgcj/49315
[pf3gnuchains/gcc-fork.git] / gcc / modulo-sched.c
index 9a806c1..e9749b2 100644 (file)
@@ -1,5 +1,5 @@
 /* Swing Modulo Scheduling implementation.
-   Copyright (C) 2004, 2005, 2006, 2007
+   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Ayal Zaks and Mustafa Hagog <zaks,mustafa@il.ibm.com>
 
@@ -24,7 +24,7 @@ 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 "rtl.h"
 #include "tm_p.h"
 #include "hard-reg-set.h"
@@ -34,7 +34,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "insn-config.h"
 #include "insn-attr.h"
 #include "except.h"
-#include "toplev.h"
 #include "recog.h"
 #include "sched-int.h"
 #include "target.h"
@@ -48,6 +47,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "timevar.h"
 #include "tree-pass.h"
 #include "dbgcnt.h"
+#include "df.h"
 
 #ifdef INSN_SCHEDULING
 
@@ -84,19 +84,18 @@ along with GCC; see the file COPYING3.  If not see
       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
+    SMS works with countable loops 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.  
+    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
@@ -116,8 +115,10 @@ typedef struct ps_insn *ps_insn_ptr;
 
 /* The number of different iterations the nodes in ps span, assuming
    the stage boundaries are placed efficiently.  */
-#define PS_STAGE_COUNT(ps) ((PS_MAX_CYCLE (ps) - PS_MIN_CYCLE (ps) \
-                            + 1 + (ps)->ii - 1) / (ps)->ii)
+#define CALC_STAGE_COUNT(max_cycle,min_cycle,ii) ((max_cycle - min_cycle \
+                         + 1 + ii - 1) / ii)
+/* The stage count of ps.  */
+#define PS_STAGE_COUNT(ps) (((partial_schedule_ptr)(ps))->stage_count)
 
 /* A single instruction in the partial schedule.  */
 struct ps_insn
@@ -133,8 +134,6 @@ struct ps_insn
   ps_insn_ptr next_in_row,
              prev_in_row;
 
-  /* The number of nodes in the same row that come after this node.  */
-  int row_rest_count;
 };
 
 /* Holds the partial schedule as an array of II rows.  Each entry of the
@@ -148,6 +147,12 @@ struct partial_schedule
   /* rows[i] points to linked list of insns scheduled in row i (0<=i<ii).  */
   ps_insn_ptr *rows;
 
+  /*  rows_length[i] holds the number of instructions in the row.
+      It is used only (as an optimization) to back off quickly from
+      trying to schedule a node in a full row; that is, to avoid running
+      through futile DFA state transitions.  */
+  int *rows_length;
+  
   /* The earliest absolute cycle of an insn in the partial schedule.  */
   int min_cycle;
 
@@ -155,6 +160,8 @@ struct partial_schedule
   int max_cycle;
 
   ddg_ptr g;   /* The DDG of the insns in the partial schedule.  */
+
+  int stage_count;  /* The stage count of the partial schedule.  */
 };
 
 /* We use this to record all the register replacements we do in
@@ -168,7 +175,7 @@ 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);
@@ -187,23 +194,15 @@ static int compute_split_row (sbitmap, int, int, int, ddg_node_ptr);
 /* 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,
+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 ps,
-                                      int from_stage, int to_stage,
-                                      int is_prolog, rtx count_reg);
-
+static void duplicate_insns_of_cycles (partial_schedule_ptr,
+                                      int, int, int, rtx);
+static int calculate_stage_count (partial_schedule_ptr ps);
 #define SCHED_ASAP(x) (((node_sched_params_ptr)(x)->aux.info)->asap)
 #define SCHED_TIME(x) (((node_sched_params_ptr)(x)->aux.info)->time)
 #define SCHED_FIRST_REG_MOVE(x) \
@@ -243,7 +242,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];
 
@@ -259,7 +258,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,
@@ -268,16 +277,15 @@ 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,
+  NULL, NULL, NULL, NULL,
   0
 };
 
-
 /* 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
@@ -286,8 +294,7 @@ static rtx
 doloop_register_get (rtx head ATTRIBUTE_UNUSED, rtx tail ATTRIBUTE_UNUSED)
 {
 #ifdef HAVE_doloop_end
-  rtx reg, condition, insn;
-  bool found = false;
+  rtx reg, condition, insn, first_insn_not_to_check;
 
   if (!JUMP_P (tail))
     return NULL_RTX;
@@ -309,25 +316,23 @@ doloop_register_get (rtx head ATTRIBUTE_UNUSED, rtx tail ATTRIBUTE_UNUSED)
      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.  */
-  for (insn = head; insn != PREV_INSN (tail); insn = NEXT_INSN (insn))
-    if ((found = reg_mentioned_p (reg, insn)) == true)
-      break;
-  if (found)
-    {
-      if (dump_file)
-        fprintf (dump_file, "SMS count_reg found outside control\n");
+  first_insn_not_to_check = (GET_CODE (PATTERN (tail)) == PARALLEL ? tail
+                             : prev_nondebug_insn (tail));
 
-      return NULL_RTX;
-    }
-  /* One last check in case the do-loop pattern is parallel.  */
-  if (GET_CODE (PATTERN (tail)) == PARALLEL)
-    if (reg_mentioned_p (reg, PREV_INSN (tail)))
+  for (insn = head; insn != first_insn_not_to_check; insn = NEXT_INSN (insn))
+    if (!DEBUG_INSN_P (insn) && reg_mentioned_p (reg, insn))
       {
         if (dump_file)
-          fprintf (dump_file, "SMS count_reg found outside control\n");
+        {
+          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;
@@ -351,12 +356,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;
@@ -375,9 +380,9 @@ static int
 res_MII (ddg_ptr g)
 {
   if (targetm.sched.sms_res_mii)
-    return targetm.sched.sms_res_mii (g); 
-  
-  return (g->num_nodes / issue_rate);
+    return targetm.sched.sms_res_mii (g);
+
+  return ((g->num_nodes - g->num_debug) / issue_rate);
 }
 
 
@@ -510,7 +515,9 @@ generate_reg_moves (partial_schedule_ptr ps, bool rescan)
       /* 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++)
        {
@@ -569,13 +576,13 @@ free_undo_replace_buff (struct undo_replace_buff_elem *reg_move_replaces)
     }
 }
 
-/* Bump the SCHED_TIMEs of all nodes to start from zero.  Set the values
-   of SCHED_ROW and SCHED_STAGE.  */
+/* Bump the SCHED_TIMEs of all nodes by AMOUNT.  Set the values of
+   SCHED_ROW and SCHED_STAGE.  Instruction scheduled on cycle AMOUNT
+   will move to cycle zero.  */
 static void
-normalize_sched_times (partial_schedule_ptr ps)
+reset_sched_times (partial_schedule_ptr ps, int amount)
 {
   int row;
-  int amount = PS_MIN_CYCLE (ps);
   int ii = ps->ii;
   ps_insn_ptr crr_insn;
 
@@ -584,19 +591,43 @@ normalize_sched_times (partial_schedule_ptr ps)
       {
        ddg_node_ptr u = crr_insn->node;
        int normalized_time = SCHED_TIME (u) - amount;
+       int new_min_cycle = PS_MIN_CYCLE (ps) - amount;
+        int sc_until_cycle_zero, stage;
 
-       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);
+        if (dump_file)
+          {
+            /* Print the scheduling times after the rotation.  */
+            fprintf (dump_file, "crr_insn->node=%d (insn id %d), "
+                     "crr_insn->cycle=%d, min_cycle=%d", crr_insn->node->cuid,
+                     INSN_UID (crr_insn->node->insn), SCHED_TIME (u),
+                     normalized_time);
+            if (JUMP_P (crr_insn->node->insn))
+              fprintf (dump_file, " (branch)");
+            fprintf (dump_file, "\n");
+          }
+       
        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;
+       SCHED_ROW (u) = SMODULO (normalized_time, ii);
+      
+        /* The calculation of stage count is done adding the number
+           of stages before cycle zero and after cycle zero.  */
+       sc_until_cycle_zero = CALC_STAGE_COUNT (-1, new_min_cycle, ii);
+       
+       if (SCHED_TIME (u) < 0)
+         {
+           stage = CALC_STAGE_COUNT (-1, SCHED_TIME (u), ii);
+           SCHED_STAGE (u) = sc_until_cycle_zero - stage;
+         }
+       else
+         {
+           stage = CALC_STAGE_COUNT (SCHED_TIME (u), 0, ii);
+           SCHED_STAGE (u) = sc_until_cycle_zero + stage - 1;
+         }
       }
 }
-
 /* Set SCHED_COLUMN of each node according to its position in PS.  */
 static void
 set_columns_for_ps (partial_schedule_ptr ps)
@@ -646,9 +677,12 @@ duplicate_insns_of_cycles (partial_schedule_ptr ps, int from_stage,
 
         /* Do not duplicate any insn which refers to count_reg as it
            belongs to the control part.
+           The closing branch is scheduled as well and thus should
+           be ignored.
            TODO: This should be done by analyzing the control part of
            the loop.  */
-        if (reg_mentioned_p (count_reg, u_node->insn))
+        if (reg_mentioned_p (count_reg, u_node->insn)
+            || JUMP_P (ps_ij->node->insn))
           continue;
 
        if (for_prolog)
@@ -705,7 +739,7 @@ generate_prolog_epilog (partial_schedule_ptr ps, struct loop *loop,
   int i;
   int last_stage = PS_STAGE_COUNT (ps) - 1;
   edge e;
-  
+
   /* Generate the prolog, inserting its insns on the loop-entry edge.  */
   start_sequence ();
 
@@ -727,7 +761,7 @@ generate_prolog_epilog (partial_schedule_ptr ps, struct loop *loop,
 
   for (i = 0; i < last_stage; i++)
     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 ());
@@ -739,7 +773,7 @@ generate_prolog_epilog (partial_schedule_ptr ps, struct loop *loop,
 
   for (i = 0; i < last_stage; i++)
     duplicate_insns_of_cycles (ps, i + 1, last_stage, 0, count_reg);
-  
+
   /* Put the epilogue on the exit edge.  */
   gcc_assert (single_exit (loop));
   e = single_exit (loop);
@@ -769,7 +803,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;
@@ -798,14 +832,18 @@ loop_canon_p (struct loop *loop)
 {
 
   if (loop->inner || !loop_outer (loop))
+  {
+    if (dump_file)
+      fprintf (dump_file, "SMS loop inner or !loop_outer\n");
     return false;
+  }
 
   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));
@@ -818,7 +856,7 @@ 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));
@@ -854,6 +892,19 @@ 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
@@ -869,7 +920,7 @@ sms_schedule (void)
   rtx insn;
   ddg_ptr *g_arr, g;
   int * node_order;
-  int maxii;
+  int maxii, max_asap;
   loop_iterator li;
   partial_schedule_ptr ps;
   basic_block bb = NULL;
@@ -899,21 +950,19 @@ sms_schedule (void)
     issue_rate = 1;
 
   /* Initialize the scheduler.  */
-  current_sched_info = &sms_sched_info;
-
-  /* Init Data Flow analysis, to be used in interloop dep calculation.  */
-  df_set_flags (DF_LR_RUN_DCE);
-  df_rd_add_problem ();
-  df_note_add_problem ();
-  df_chain_add_problem (DF_DU_CHAIN);
-  df_analyze ();
-  regstat_compute_calls_crossed ();
-  sched_init ();
+  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, 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_EACH_LOOP (li, loop, 0)
@@ -930,11 +979,24 @@ sms_schedule (void)
           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;
 
@@ -944,7 +1006,7 @@ sms_schedule (void)
       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 < single_exit (loop)->count * SMS_LOOP_AVERAGE_COUNT_THRESHOLD))
@@ -975,11 +1037,17 @@ sms_schedule (void)
 
       /* Make sure this is a doloop.  */
       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,
-         or auto-increment insns (to avoid creating invalid reg-moves
-         for the auto-increment insns).  
+      /* Don't handle BBs with calls or barriers or auto-increment insns 
+        (to avoid creating invalid reg-moves for the auto-increment insns),
+        or !single_set with the exception of instructions that include
+        count_reg---these instructions are part of the control part
+        that do-loop recognizes.
          ??? Should handle auto-increment insns.
          ??? Should handle insns defining subregs.  */
      for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn))
@@ -988,8 +1056,9 @@ sms_schedule (void)
 
         if (CALL_P (insn)
             || BARRIER_P (insn)
-            || (INSN_P (insn) && !JUMP_P (insn)
-                && !single_set (insn) && GET_CODE (PATTERN (insn)) != USE)
+            || (NONDEBUG_INSN_P (insn) && !JUMP_P (insn)
+                && !single_set (insn) && GET_CODE (PATTERN (insn)) != USE
+                && !reg_mentioned_p (count_reg, insn))
             || (FIND_REG_INC_NOTE (insn, NULL_RTX) != 0)
             || (INSN_P (insn) && (set = single_set (insn))
                 && GET_CODE (SET_DEST (set)) == SUBREG))
@@ -1006,7 +1075,7 @@ sms_schedule (void)
                fprintf (dump_file, "SMS loop-with-barrier\n");
               else if (FIND_REG_INC_NOTE (insn, NULL_RTX) != 0)
                 fprintf (dump_file, "SMS reg inc\n");
-              else if ((INSN_P (insn) && !JUMP_P (insn)
+              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
@@ -1017,15 +1086,27 @@ sms_schedule (void)
          continue;
        }
 
-      if (! (g = create_ddg (bb, 0)))
+      /* Always schedule the closing branch with the rest of the
+         instructions. The branch is rotated to be in row ii-1 at the
+         end of the scheduling procedure to make sure it's the last
+         instruction in the iteration.  */
+      if (! (g = create_ddg (bb, 1)))
         {
           if (dump_file)
-           fprintf (dump_file, "SMS doloop\n");
+           fprintf (dump_file, "SMS create_ddg failed\n");
          continue;
         }
 
       g_arr[loop->num] = g;
+      if (dump_file)
+        fprintf (dump_file, "...OK\n");
+
     }
+  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.  */
   FOR_EACH_LOOP (li, loop, 0)
@@ -1040,7 +1121,14 @@ sms_schedule (void)
         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);
 
@@ -1096,9 +1184,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 = MAXII_FACTOR * mii;
+      maxii = MAX (max_asap, MAXII_FACTOR * mii);
 
       if (dump_file)
        fprintf (dump_file, "SMS iis %d %d %d (rec_mii, mii, maxii)\n",
@@ -1110,12 +1198,17 @@ sms_schedule (void)
 
       ps = sms_schedule_by_order (g, mii, maxii, node_order);
 
-      if (ps)
-       stage_count = PS_STAGE_COUNT (ps);
-
-      /* Stage count of 1 means that there is no interleaving between
-         iterations, let the scheduling passes do the job.  */
-      if (stage_count < 1
+       if (ps)
+       {
+         stage_count = calculate_stage_count (ps);
+         gcc_assert(stage_count >= 1);
+         PS_STAGE_COUNT(ps) = stage_count;
+       }
+
+      /* The default value of PARAM_SMS_MIN_SC is 2 as stage count of
+        1 means that there is no interleaving between iterations thus
+        we let the scheduling passes do the job in this case.  */
+      if (stage_count < (unsigned) PARAM_VALUE (PARAM_SMS_MIN_SC)
          || (count_init && (loop_count <= stage_count))
          || (flag_branch_probabilities && (trip_count <= stage_count)))
        {
@@ -1128,37 +1221,28 @@ sms_schedule (void)
              fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC, trip_count);
              fprintf (dump_file, ")\n");
            }
-         continue;
        }
       else
        {
          struct undo_replace_buff_elem *reg_move_replaces;
+          int amount = SCHED_TIME (g->closing_branch) + 1;
+         
+         /* Set the stage boundaries.  The closing_branch was scheduled
+            and should appear in the last (ii-1) row.  */
+         reset_sched_times (ps, amount);
+         rotate_partial_schedule (ps, amount);
+         set_columns_for_ps (ps);
 
-         if (dump_file)
-           {
+         canon_loop (loop);
+
+          if (dump_file)
+            {
              fprintf (dump_file,
                       "SMS succeeded %d %d (with ii, sc)\n", ps->ii,
                       stage_count);
              print_partial_schedule (ps, dump_file);
-             fprintf (dump_file,
-                      "SMS Branch (%d) will later be scheduled at cycle %d.\n",
-                      g->closing_branch->cuid, PS_MIN_CYCLE (ps) - 1);
            }
-
-         /* Set the stage boundaries.  If the DDG is built with closing_branch_deps,
-            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.  
-             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);
-         
-         canon_loop (loop);
-
           /* case the BCT count is not known , Do loop-versioning */
          if (count_reg && ! count_init)
             {
@@ -1192,7 +1276,7 @@ sms_schedule (void)
            print_node_sched_params (dump_file, g->num_nodes, g);
          /* Generate prolog and epilog.  */
           generate_prolog_epilog (ps, loop, count_reg, count_init);
+
          free_undo_replace_buff (reg_move_replaces);
        }
 
@@ -1202,11 +1286,10 @@ sms_schedule (void)
       free_ddg (g);
     }
 
-  regstat_free_calls_crossed ();
   free (g_arr);
 
   /* Release scheduler data, needed until now because of DFA.  */
-  sched_finish ();
+  haifa_sched_finish ();
   loop_optimizer_finalize ();
 }
 
@@ -1329,29 +1412,37 @@ 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_not_empty,"
-                      " checking node %d (%d): ", u_node->cuid,
+                      " 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, p_st + e->latency - (e->distance * ii));
 
-             early_start = MAX (early_start, node_st);
+              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)
@@ -1375,18 +1466,22 @@ get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i,
               print_ddg_edge (dump_file, e);
               fprintf (dump_file,
                        "\nScheduling %d (%d) in pss_not_empty,"
-                       " checking node %d (%d): ", u_node->cuid,
+                       " 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));
-               if (dump_file)
-                 fprintf (dump_file, "late_start = %d;", late_start);
+              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);
@@ -1400,6 +1495,7 @@ get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i,
        }
       start = late_start;
       end = MAX (end, late_start - ii);
+      /* Schedule the node close to it's successors.  */
       step = -1;
 
       if (dump_file)
@@ -1413,6 +1509,8 @@ get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i,
     {
       int early_start = INT_MIN;
       int late_start = INT_MAX;
+      int count_preds = 0;
+      int count_succs = 0;
 
       start = INT_MIN;
       end = INT_MAX;
@@ -1433,12 +1531,26 @@ get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i,
 
          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)
        {
@@ -1457,16 +1569,40 @@ get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i,
 
          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.  */
     {
@@ -1492,6 +1628,133 @@ get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i,
     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
@@ -1501,8 +1764,6 @@ sms_schedule_by_order (ddg_ptr g, int mii, int maxii, int *nodes_order)
   int i, c, success, num_splits = 0;
   int flush_and_start_over = true;
   int num_nodes = g->num_nodes;
-  ddg_edge_ptr e;
-  ps_insn_ptr psi;
   int start, end, step; /* Place together into one struct?  */
   sbitmap sched_nodes = sbitmap_alloc (num_nodes);
   sbitmap must_precede = sbitmap_alloc (num_nodes);
@@ -1528,13 +1789,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))
-           {
-             RESET_BIT (tobe_scheduled, u);
-             continue;
-           }
-
-         if (JUMP_P (insn)) /* Closing branch handled later.  */
+         if (!NONDEBUG_INSN_P (insn))
            {
              RESET_BIT (tobe_scheduled, u);
              continue;
@@ -1552,53 +1807,43 @@ sms_schedule_by_order (ddg_ptr g, int mii, int maxii, int *nodes_order)
                 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);
-              /* Use must_follow & must_precede bitmaps to determine order
-                 of nodes within the cycle.  */
-
-              /* use must_follow & must_precede bitmaps to determine order
-                 of nodes within the cycle.  */
-              sbitmap_zero (must_precede);
-              sbitmap_zero (must_follow);
-              /* TODO: We can add an insn to the must_precede or must_follow
-                 bitmaps only if it has tight dependence to U and they
-                 both scheduled in the same row.  The current check is less
-                 conservative and content with the fact that both U and the
-                 insn are scheduled in the same row.  */
-              for (e = u_node->in; e != 0; e = e->next_in)
-                if (TEST_BIT (sched_nodes, e->src->cuid)
-                    && (SMODULO (SCHED_TIME (e->src), ii) ==
-                        SMODULO (start, ii)))
-                  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)
-                    && (SMODULO (SCHED_TIME (e->dest), ii) ==
-                        SMODULO ((end - step), ii)))
-                  SET_BIT (must_follow, e->dest->cuid);
 
               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)
                 {
-                  verify_partial_schedule (ps, sched_nodes);
+                  sbitmap tmp_precede = NULL;
+                  sbitmap tmp_follow = NULL;
 
-                  psi = ps_add_node_check_conflicts (ps, u_node, c,
-                                                     must_precede,
-                                                     must_follow);
-
-                  if (psi)
+                  if (c == start)
+                    {
+                      if (step == 1)
+                        tmp_precede = must_precede;
+                      else      /* step == -1.  */
+                        tmp_follow = must_follow;
+                    }
+                  if (c == end - step)
                     {
-                      SCHED_TIME (u_node) = c;
-                      SET_BIT (sched_nodes, u);
-                      success = 1;
-                      num_splits = 0;
-                      if (dump_file)
-                        fprintf (dump_file, "Scheduled w/o split in %d\n", c);
-
-                      break;
+                      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)
@@ -1619,11 +1864,14 @@ sms_schedule_by_order (ddg_ptr g, int mii, int maxii, int *nodes_order)
                 }
 
               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,
+                split_row = compute_split_row (sched_nodes, start, end - 1,
                                                ps->ii, u_node);
               else
-                split_row = compute_split_row (sched_nodes, end, start,
+                split_row = compute_split_row (sched_nodes, end + 1, start,
                                                ps->ii, u_node);
 
               ps_insert_empty_row (ps, split_row, sched_nodes);
@@ -1664,6 +1912,7 @@ ps_insert_empty_row (partial_schedule_ptr ps, int split_row,
   int ii = ps->ii;
   int new_ii = ii + 1;
   int row;
+  int *rows_length_new;
 
   verify_partial_schedule (ps, sched_nodes);
 
@@ -1674,13 +1923,15 @@ ps_insert_empty_row (partial_schedule_ptr ps, int split_row,
   if (dump_file)
     fprintf (dump_file, "split_row=%d\n", split_row);
 
-  normalize_sched_times (ps);
-  rotate_partial_schedule (ps, ps->min_cycle);
+  reset_sched_times (ps, PS_MIN_CYCLE (ps));
+  rotate_partial_schedule (ps, PS_MIN_CYCLE (ps));
 
   rows_new = (ps_insn_ptr *) xcalloc (new_ii, sizeof (ps_insn_ptr));
+  rows_length_new = (int *) xcalloc (new_ii, sizeof (int));
   for (row = 0; row < split_row; row++)
     {
       rows_new[row] = ps->rows[row];
+      rows_length_new[row] = ps->rows_length[row];
       ps->rows[row] = NULL;
       for (crr_insn = rows_new[row];
           crr_insn; crr_insn = crr_insn->next_in_row)
@@ -1701,6 +1952,7 @@ ps_insert_empty_row (partial_schedule_ptr ps, int split_row,
   for (row = split_row; row < ii; row++)
     {
       rows_new[row + 1] = ps->rows[row];
+      rows_length_new[row + 1] = ps->rows_length[row];
       ps->rows[row] = NULL;
       for (crr_insn = rows_new[row + 1];
           crr_insn; crr_insn = crr_insn->next_in_row)
@@ -1722,6 +1974,8 @@ ps_insert_empty_row (partial_schedule_ptr ps, int split_row,
     + (SMODULO (ps->max_cycle, ii) >= split_row ? 1 : 0);
   free (ps->rows);
   ps->rows = rows_new;
+  free (ps->rows_length);
+  ps->rows_length = rows_length_new;
   ps->ii = new_ii;
   gcc_assert (ps->min_cycle >= 0);
 
@@ -1734,7 +1988,7 @@ ps_insert_empty_row (partial_schedule_ptr ps, int split_row,
 
 /* 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 splitted
+   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
@@ -1797,16 +2051,23 @@ verify_partial_schedule (partial_schedule_ptr ps, sbitmap sched_nodes)
   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);
-      }
+    {
+      int length = 0;
+      
+      for (crr_insn = ps->rows[row]; crr_insn; crr_insn = crr_insn->next_in_row)
+       {
+         ddg_node_ptr u = crr_insn->node;
+         
+         length++;
+         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);
+       }
+      
+      gcc_assert (ps->rows_length[row] == length);
+    }
 }
 
 \f
@@ -1825,7 +2086,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);
@@ -1848,29 +2109,37 @@ 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);
@@ -1909,7 +2178,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++)
     {
@@ -1945,7 +2214,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;
@@ -1996,7 +2265,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;
 }
 
@@ -2192,6 +2473,7 @@ create_partial_schedule (int ii, ddg_ptr g, int history)
 {
   partial_schedule_ptr ps = XNEW (struct partial_schedule);
   ps->rows = (ps_insn_ptr *) xcalloc (ii, sizeof (ps_insn_ptr));
+  ps->rows_length = (int *) xcalloc (ii, sizeof (int));
   ps->ii = ii;
   ps->history = history;
   ps->min_cycle = INT_MAX;
@@ -2230,6 +2512,7 @@ free_partial_schedule (partial_schedule_ptr ps)
     return;
   free_ps_insns (ps);
   free (ps->rows);
+  free (ps->rows_length);
   free (ps);
 }
 
@@ -2247,6 +2530,8 @@ reset_partial_schedule (partial_schedule_ptr ps, int new_ii)
   ps->rows = (ps_insn_ptr *) xrealloc (ps->rows, new_ii
                                                 * sizeof (ps_insn_ptr));
   memset (ps->rows, 0, new_ii * sizeof (ps_insn_ptr));
+  ps->rows_length = (int *) xrealloc (ps->rows_length, new_ii * sizeof (int));
+  memset (ps->rows_length, 0, new_ii * sizeof (int));
   ps->ii = new_ii;
   ps->min_cycle = INT_MAX;
   ps->max_cycle = INT_MIN;
@@ -2263,7 +2548,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, ",
@@ -2275,14 +2560,13 @@ print_partial_schedule (partial_schedule_ptr ps, FILE *dump)
 
 /* Creates an object of PS_INSN and initializes it to the given parameters.  */
 static ps_insn_ptr
-create_ps_insn (ddg_node_ptr node, int rest_count, int cycle)
+create_ps_insn (ddg_node_ptr node, int cycle)
 {
   ps_insn_ptr ps_i = XNEW (struct ps_insn);
 
   ps_i->node = node;
   ps_i->next_in_row = NULL;
   ps_i->prev_in_row = NULL;
-  ps_i->row_rest_count = rest_count;
   ps_i->cycle = cycle;
 
   return ps_i;
@@ -2315,6 +2599,8 @@ remove_node_from_ps (partial_schedule_ptr ps, ps_insn_ptr ps_i)
       if (ps_i->next_in_row)
        ps_i->next_in_row->prev_in_row = ps_i->prev_in_row;
     }
+   
+  ps->rows_length[row] -= 1; 
   free (ps_i);
   return true;
 }
@@ -2332,6 +2618,7 @@ ps_insn_find_column (partial_schedule_ptr ps, ps_insn_ptr ps_i,
   ps_insn_ptr next_ps_i;
   ps_insn_ptr first_must_follow = NULL;
   ps_insn_ptr last_must_precede = NULL;
+  ps_insn_ptr last_in_row = NULL;
   int row;
 
   if (! ps_i)
@@ -2346,10 +2633,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.  */
@@ -2358,8 +2645,37 @@ ps_insn_find_column (partial_schedule_ptr ps, ps_insn_ptr ps_i,
          else
             last_must_precede = next_ps_i;
         }
+      /* The closing branch must be the last in the row.  */
+      if (must_precede 
+         && TEST_BIT (must_precede, next_ps_i->node->cuid) 
+         && JUMP_P (next_ps_i->node->insn))     
+       return false;
+             
+       last_in_row = next_ps_i;
     }
 
+  /* The closing branch is scheduled as well.  Make sure there is no
+     dependent instruction after it as the branch should be the last
+     instruction in the row.  */
+  if (JUMP_P (ps_i->node->insn)) 
+    {
+      if (first_must_follow)
+       return false;
+      if (last_in_row)
+       {
+         /* Make the branch the last in the row.  New instructions
+            will be inserted at the beginning of the row or after the
+            last must_precede instruction thus the branch is guaranteed
+            to remain the last instruction in the row.  */
+         last_in_row->next_in_row = ps_i;
+         ps_i->prev_in_row = last_in_row;
+         ps_i->next_in_row = NULL;
+       }
+      else
+       ps->rows[row] = ps_i;
+      return true;
+    }
+  
   /* Now insert the node after INSERT_AFTER_PSI.  */
 
   if (! last_must_precede)
@@ -2383,8 +2699,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,
@@ -2406,7 +2722,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.  */
@@ -2432,26 +2748,21 @@ 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,
                sbitmap must_precede, sbitmap must_follow)
 {
   ps_insn_ptr ps_i;
-  int rest_count = 1;
   int row = SMODULO (cycle, ps->ii);
 
-  if (ps->rows[row]
-      && ps->rows[row]->row_rest_count >= issue_rate)
+  if (ps->rows_length[row] >= issue_rate)
     return NULL;
 
-  if (ps->rows[row])
-    rest_count += ps->rows[row]->row_rest_count;
-
-  ps_i = create_ps_insn (node, rest_count, cycle);
+  ps_i = create_ps_insn (node, cycle);
 
   /* Finds and inserts PS_I according to MUST_FOLLOW and
      MUST_PRECEDE.  */
@@ -2461,6 +2772,7 @@ add_node_to_ps (partial_schedule_ptr ps, ddg_node_ptr node, int cycle,
       return NULL;
     }
 
+  ps->rows_length[row] += 1;
   return ps_i;
 }
 
@@ -2504,7 +2816,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.  */
@@ -2512,7 +2824,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;
 
@@ -2535,8 +2847,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,
@@ -2581,6 +2893,24 @@ ps_add_node_check_conflicts (partial_schedule_ptr ps, ddg_node_ptr n,
   return ps_i;
 }
 
+/* Calculate the stage count of the partial schedule PS.  The calculation
+   takes into account the rotation to bring the closing branch to row
+   ii-1.  */
+int
+calculate_stage_count (partial_schedule_ptr ps)
+{
+  int rotation_amount = (SCHED_TIME (ps->g->closing_branch)) + 1;
+  int new_min_cycle = PS_MIN_CYCLE (ps) - rotation_amount;
+  int new_max_cycle = PS_MAX_CYCLE (ps) - rotation_amount;
+  int stage_count = CALC_STAGE_COUNT (-1, new_min_cycle, ps->ii);
+
+  /* The calculation of stage count is done adding the number of stages
+     before cycle zero and after cycle zero.  */ 
+  stage_count += CALC_STAGE_COUNT (new_max_cycle, 0, ps->ii);
+
+  return stage_count;
+}
+
 /* Rotate the rows of PS such that insns scheduled at time
    START_CYCLE will appear in row 0.  Updates max/min_cycles.  */
 void
@@ -2598,11 +2928,16 @@ rotate_partial_schedule (partial_schedule_ptr ps, int start_cycle)
   for (i = 0; i < backward_rotates; i++)
     {
       ps_insn_ptr first_row = ps->rows[0];
+      int first_row_length = ps->rows_length[0];
 
       for (row = 0; row < last_row; row++)
-       ps->rows[row] = ps->rows[row+1];
+       {
+         ps->rows[row] = ps->rows[row + 1];
+         ps->rows_length[row] = ps->rows_length[row + 1]; 
+       }
 
       ps->rows[last_row] = first_row;
+      ps->rows_length[last_row] = first_row_length;
     }
 
   ps->max_cycle -= start_cycle;
@@ -2643,8 +2978,10 @@ rest_of_handle_sms (void)
   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 */
@@ -2655,10 +2992,10 @@ struct tree_opt_pass pass_sms =
   0,                                    /* properties_required */
   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 */
+  0,                                    /* todo_flags_start */
+  TODO_df_finish
+    | TODO_verify_flow
+    | TODO_verify_rtl_sharing
+    | TODO_ggc_collect                  /* todo_flags_finish */
+ }
 };
-