OSDN Git Service

* config/s390/s390.c (s390_fixup_clobbered_return_reg):
[pf3gnuchains/gcc-fork.git] / gcc / haifa-sched.c
index b59f7e1..a8b587e 100644 (file)
@@ -134,6 +134,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 \f
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "toplev.h"
 #include "rtl.h"
 #include "tm_p.h"
@@ -158,7 +160,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 static int issue_rate;
 
-/* If the following variable value is non zero, the scheduler inserts
+/* If the following variable value is nonzero, the scheduler inserts
    bubbles (nop insns).  The value of variable affects on scheduler
    behavior only if automaton pipeline interface with multipass
    scheduling is used and hook dfa_bubble is defined.  */
@@ -198,13 +200,6 @@ fix_sched_param (param, val)
 
 struct haifa_insn_data *h_i_d;
 
-#define DONE_PRIORITY  -1
-#define MAX_PRIORITY   0x7fffffff
-#define TAIL_PRIORITY  0x7ffffffe
-#define LAUNCH_PRIORITY        0x7f000001
-#define DONE_PRIORITY_P(INSN) (INSN_PRIORITY (INSN) < 0)
-#define LOW_PRIORITY_P(INSN) ((INSN_PRIORITY (INSN) & 0x7f000000) == 0)
-
 #define LINE_NOTE(INSN)                (h_i_d[INSN_UID (INSN)].line_note)
 #define INSN_TICK(INSN)                (h_i_d[INSN_UID (INSN)].tick)
 
@@ -310,6 +305,170 @@ struct ready_list
   int n_ready;
 };
 
+static int may_trap_exp PARAMS ((rtx, int));
+
+/* Nonzero iff the address is comprised from at most 1 register.  */
+#define CONST_BASED_ADDRESS_P(x)                       \
+  (GET_CODE (x) == REG                                 \
+   || ((GET_CODE (x) == PLUS || GET_CODE (x) == MINUS  \
+       || (GET_CODE (x) == LO_SUM))                    \
+       && (CONSTANT_P (XEXP (x, 0))                    \
+          || CONSTANT_P (XEXP (x, 1)))))
+
+/* Returns a class that insn with GET_DEST(insn)=x may belong to,
+   as found by analyzing insn's expression.  */
+
+static int
+may_trap_exp (x, is_store)
+     rtx x;
+     int is_store;
+{
+  enum rtx_code code;
+
+  if (x == 0)
+    return TRAP_FREE;
+  code = GET_CODE (x);
+  if (is_store)
+    {
+      if (code == MEM && may_trap_p (x))
+       return TRAP_RISKY;
+      else
+       return TRAP_FREE;
+    }
+  if (code == MEM)
+    {
+      /* The insn uses memory:  a volatile load.  */
+      if (MEM_VOLATILE_P (x))
+       return IRISKY;
+      /* An exception-free load.  */
+      if (!may_trap_p (x))
+       return IFREE;
+      /* A load with 1 base register, to be further checked.  */
+      if (CONST_BASED_ADDRESS_P (XEXP (x, 0)))
+       return PFREE_CANDIDATE;
+      /* No info on the load, to be further checked.  */
+      return PRISKY_CANDIDATE;
+    }
+  else
+    {
+      const char *fmt;
+      int i, insn_class = TRAP_FREE;
+
+      /* Neither store nor load, check if it may cause a trap.  */
+      if (may_trap_p (x))
+       return TRAP_RISKY;
+      /* Recursive step: walk the insn...  */
+      fmt = GET_RTX_FORMAT (code);
+      for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+       {
+         if (fmt[i] == 'e')
+           {
+             int tmp_class = may_trap_exp (XEXP (x, i), is_store);
+             insn_class = WORST_CLASS (insn_class, tmp_class);
+           }
+         else if (fmt[i] == 'E')
+           {
+             int j;
+             for (j = 0; j < XVECLEN (x, i); j++)
+               {
+                 int tmp_class = may_trap_exp (XVECEXP (x, i, j), is_store);
+                 insn_class = WORST_CLASS (insn_class, tmp_class);
+                 if (insn_class == TRAP_RISKY || insn_class == IRISKY)
+                   break;
+               }
+           }
+         if (insn_class == TRAP_RISKY || insn_class == IRISKY)
+           break;
+       }
+      return insn_class;
+    }
+}
+
+/* Classifies insn for the purpose of verifying that it can be
+   moved speculatively, by examining it's patterns, returning:
+   TRAP_RISKY: store, or risky non-load insn (e.g. division by variable).
+   TRAP_FREE: non-load insn.
+   IFREE: load from a globaly safe location.
+   IRISKY: volatile load.
+   PFREE_CANDIDATE, PRISKY_CANDIDATE: load that need to be checked for
+   being either PFREE or PRISKY.  */
+
+int
+haifa_classify_insn (insn)
+     rtx insn;
+{
+  rtx pat = PATTERN (insn);
+  int tmp_class = TRAP_FREE;
+  int insn_class = TRAP_FREE;
+  enum rtx_code code;
+
+  if (GET_CODE (pat) == PARALLEL)
+    {
+      int i, len = XVECLEN (pat, 0);
+
+      for (i = len - 1; i >= 0; i--)
+       {
+         code = GET_CODE (XVECEXP (pat, 0, i));
+         switch (code)
+           {
+           case CLOBBER:
+             /* Test if it is a 'store'.  */
+             tmp_class = may_trap_exp (XEXP (XVECEXP (pat, 0, i), 0), 1);
+             break;
+           case SET:
+             /* Test if it is a store.  */
+             tmp_class = may_trap_exp (SET_DEST (XVECEXP (pat, 0, i)), 1);
+             if (tmp_class == TRAP_RISKY)
+               break;
+             /* Test if it is a load.  */
+             tmp_class
+               = WORST_CLASS (tmp_class,
+                              may_trap_exp (SET_SRC (XVECEXP (pat, 0, i)),
+                                            0));
+             break;
+           case COND_EXEC:
+           case TRAP_IF:
+             tmp_class = TRAP_RISKY;
+             break;
+           default:
+             ;
+           }
+         insn_class = WORST_CLASS (insn_class, tmp_class);
+         if (insn_class == TRAP_RISKY || insn_class == IRISKY)
+           break;
+       }
+    }
+  else
+    {
+      code = GET_CODE (pat);
+      switch (code)
+       {
+       case CLOBBER:
+         /* Test if it is a 'store'.  */
+         tmp_class = may_trap_exp (XEXP (pat, 0), 1);
+         break;
+       case SET:
+         /* Test if it is a store.  */
+         tmp_class = may_trap_exp (SET_DEST (pat), 1);
+         if (tmp_class == TRAP_RISKY)
+           break;
+         /* Test if it is a load.  */
+         tmp_class =
+           WORST_CLASS (tmp_class,
+                        may_trap_exp (SET_SRC (pat), 0));
+         break;
+       case COND_EXEC:
+       case TRAP_IF:
+         tmp_class = TRAP_RISKY;
+         break;
+       default:;
+       }
+      insn_class = tmp_class;
+    }
+
+  return insn_class;
+}
+
 /* Forward declarations.  */
 
 /* The scheduler using only DFA description should never use the
@@ -324,7 +483,8 @@ static int priority PARAMS ((rtx));
 static int rank_for_schedule PARAMS ((const PTR, const PTR));
 static void swap_sort PARAMS ((rtx *, int));
 static void queue_insn PARAMS ((rtx, int));
-static void schedule_insn PARAMS ((rtx, struct ready_list *, int));
+static int schedule_insn PARAMS ((rtx, struct ready_list *, int));
+static int find_set_reg_weight PARAMS ((rtx));
 static void find_insn_reg_weight PARAMS ((int));
 static void adjust_priority PARAMS ((rtx));
 static void advance_one_cycle PARAMS ((void));
@@ -371,7 +531,7 @@ static rtx move_insn PARAMS ((rtx, rtx));
    on the first cycle.  It is used only for DFA based scheduler.  */
 static rtx ready_element PARAMS ((struct ready_list *, int));
 static rtx ready_remove PARAMS ((struct ready_list *, int));
-static int max_issue PARAMS ((struct ready_list *, state_t, int *));
+static int max_issue PARAMS ((struct ready_list *, int *));
 
 static rtx choose_ready PARAMS ((struct ready_list *));
 
@@ -396,7 +556,7 @@ static rtx last_scheduled_insn;
 
 /* Compute the function units used by INSN.  This caches the value
    returned by function_units_used.  A function unit is encoded as the
-   unit number if the value is non-negative and the compliment of a
+   unit number if the value is non-negative and the complement of a
    mask if the value is negative.  A function unit index is the
    non-negative encoding.  The scheduler using only DFA description
    should never use the following function.  */
@@ -856,15 +1016,20 @@ rank_for_schedule (x, y)
   int tmp_class, tmp2_class, depend_count1, depend_count2;
   int val, priority_val, weight_val, info_val;
 
+  /* The insn in a schedule group should be issued the first.  */
+  if (SCHED_GROUP_P (tmp) != SCHED_GROUP_P (tmp2))
+    return SCHED_GROUP_P (tmp2) ? 1 : -1;
+
   /* Prefer insn with higher priority.  */
   priority_val = INSN_PRIORITY (tmp2) - INSN_PRIORITY (tmp);
+
   if (priority_val)
     return priority_val;
 
   /* Prefer an insn with smaller contribution to registers-pressure.  */
   if (!reload_completed &&
       (weight_val = INSN_REG_WEIGHT (tmp) - INSN_REG_WEIGHT (tmp2)))
-    return (weight_val);
+    return weight_val;
 
   info_val = (*current_sched_info->rank) (tmp, tmp2);
   if (info_val)
@@ -1022,8 +1187,10 @@ ready_element (ready, index)
      struct ready_list *ready;
      int index;
 {
+#ifdef ENABLE_CHECKING
   if (ready->n_ready == 0 || index >= ready->n_ready)
     abort ();
+#endif
   return ready->vec[ready->first - index];
 }
 
@@ -1106,16 +1273,18 @@ static int last_clock_var;
 
 /* INSN is the "currently executing insn".  Launch each insn which was
    waiting on INSN.  READY is the ready list which contains the insns
-   that are ready to fire.  CLOCK is the current cycle.
-   */
+   that are ready to fire.  CLOCK is the current cycle.  The function
+   returns necessary cycle advance after issuing the insn (it is not
+   zero for insns in a schedule group).  */
 
-static void
+static int
 schedule_insn (insn, ready, clock)
      rtx insn;
      struct ready_list *ready;
      int clock;
 {
   rtx link;
+  int advance = 0;
   int unit = 0;
 
   if (!targetm.sched.use_dfa_pipeline_interface
@@ -1129,7 +1298,7 @@ schedule_insn (insn, ready, clock)
       char buf[2048];
 
       print_insn (buf, insn, 0);
-      buf[40]=0;
+      buf[40] = 0;
       fprintf (sched_dump, ";;\t%3i--> %-40s:", clock, buf);
 
       if (recog_memoized (insn) < 0)
@@ -1157,7 +1326,7 @@ schedule_insn (insn, ready, clock)
        schedule_unit (unit, insn, clock);
       
       if (INSN_DEPEND (insn) == 0)
-       return;
+       return 0;
     }
 
   for (link = INSN_DEPEND (insn); link != 0; link = XEXP (link, 1))
@@ -1182,7 +1351,8 @@ schedule_insn (insn, ready, clock)
              if (effective_cost < 1)
                fprintf (sched_dump, "into ready\n");
              else
-               fprintf (sched_dump, "into queue with cost=%d\n", effective_cost);
+               fprintf (sched_dump, "into queue with cost=%d\n",
+                        effective_cost);
            }
 
          /* Adjust the priority of NEXT and either put it on the ready
@@ -1191,7 +1361,12 @@ schedule_insn (insn, ready, clock)
          if (effective_cost < 1)
            ready_add (ready, next);
          else
-           queue_insn (next, effective_cost);
+           {
+             queue_insn (next, effective_cost);
+
+             if (SCHED_GROUP_P (next) && advance < effective_cost)
+               advance = effective_cost;
+           }
        }
     }
 
@@ -1200,13 +1375,15 @@ schedule_insn (insn, ready, clock)
      to issue on the same cycle as the previous insn.  A machine
      may use this information to decide how the instruction should
      be aligned.  */
-  if (reload_completed && issue_rate > 1
+  if (issue_rate > 1
       && GET_CODE (PATTERN (insn)) != USE
       && GET_CODE (PATTERN (insn)) != CLOBBER)
     {
-      PUT_MODE (insn, clock > last_clock_var ? TImode : VOIDmode);
+      if (reload_completed)
+       PUT_MODE (insn, clock > last_clock_var ? TImode : VOIDmode);
       last_clock_var = clock;
     }
+  return advance;
 }
 
 /* Functions for handling of notes.  */
@@ -1233,6 +1410,7 @@ unlink_other_notes (insn, tail)
       /* See sched_analyze to see how these are handled.  */
       if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG
          && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END
+         && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK
          && NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
          && NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_END)
        {
@@ -1541,6 +1719,32 @@ rm_other_notes (head, tail)
 
 /* Functions for computation of registers live/usage info.  */
 
+/* This function looks for a new register being defined.
+   If the destination register is already used by the source,
+   a new register is not needed.  */
+
+static int
+find_set_reg_weight (x)
+    rtx x;
+{
+  if (GET_CODE (x) == CLOBBER
+      && register_operand (SET_DEST (x), VOIDmode))
+    return 1;
+  if (GET_CODE (x) == SET
+      && register_operand (SET_DEST (x), VOIDmode))
+    {
+      if (GET_CODE (SET_DEST (x)) == REG)
+       {
+         if (!reg_mentioned_p (SET_DEST (x), SET_SRC (x)))
+           return 1;
+         else
+           return 0;
+       }
+      return 1;
+    }
+  return 0;
+}
+
 /* Calculate INSN_REG_WEIGHT for all insns of a block.  */
 
 static void
@@ -1563,21 +1767,16 @@ find_insn_reg_weight (b)
 
       /* Increment weight for each register born here.  */
       x = PATTERN (insn);
-      if ((GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
-         && register_operand (SET_DEST (x), VOIDmode))
-       reg_weight++;
-      else if (GET_CODE (x) == PARALLEL)
-       {
-         int j;
-         for (j = XVECLEN (x, 0) - 1; j >= 0; j--)
-           {
-             x = XVECEXP (PATTERN (insn), 0, j);
-             if ((GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
-                 && register_operand (SET_DEST (x), VOIDmode))
-               reg_weight++;
-           }
-       }
-
+      reg_weight += find_set_reg_weight (x);
+      if (GET_CODE (x) == PARALLEL)
+       {
+         int j;
+         for (j = XVECLEN (x, 0) - 1; j >= 0; j--)
+           {
+             x = XVECEXP (PATTERN (insn), 0, j);
+             reg_weight += find_set_reg_weight (x);
+           }
+       }
       /* Decrement weight for each register that dies here.  */
       for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
        {
@@ -1736,8 +1935,7 @@ reemit_notes (insn, last)
   return retval;
 }
 
-/* Move INSN, and all insns which should be issued before it,
-   due to SCHED_GROUP_P flag.  Reemit notes if needed.
+/* Move INSN.  Reemit notes if needed.
 
    Return the last insn emitted by the scheduler, which is the
    return value from the first call to reemit_notes.  */
@@ -1748,26 +1946,6 @@ move_insn (insn, last)
 {
   rtx retval = NULL;
 
-  /* If INSN has SCHED_GROUP_P set, then issue it and any other
-     insns with SCHED_GROUP_P set first.  */
-  while (SCHED_GROUP_P (insn))
-    {
-      rtx prev = PREV_INSN (insn);
-
-      /* Move a SCHED_GROUP_P insn.  */
-      move_insn1 (insn, last);
-      /* If this is the first call to reemit_notes, then record
-        its return value.  */
-      if (retval == NULL_RTX)
-       retval = reemit_notes (insn, insn);
-      else
-       reemit_notes (insn, insn);
-      /* Consume SCHED_GROUP_P flag.  */
-      SCHED_GROUP_P (insn) = 0;
-      insn = prev;
-    }
-
-  /* Now move the first non SCHED_GROUP_P insn.  */
   move_insn1 (insn, last);
 
   /* If this is the first call to reemit_notes, then record
@@ -1777,90 +1955,109 @@ move_insn (insn, last)
   else
     reemit_notes (insn, insn);
 
+  SCHED_GROUP_P (insn) = 0;
+
   return retval;
 }
 
+/* The following structure describe an entry of the stack of choices.  */
+struct choice_entry
+{
+  /* Ordinal number of the issued insn in the ready queue.  */
+  int index;
+  /* The number of the rest insns whose issues we should try.  */
+  int rest;
+  /* The number of issued essential insns.  */
+  int n;
+  /* State after issuing the insn.  */
+  state_t state;
+};
+
+/* The following array is used to implement a stack of choices used in
+   function max_issue.  */
+static struct choice_entry *choice_stack;
+
+/* The following variable value is number of essential insns issued on
+   the current cycle.  An insn is essential one if it changes the
+   processors state.  */
+static int cycle_issued_insns;
+
 /* The following function returns maximal (or close to maximal) number
    of insns which can be issued on the same cycle and one of which
-   insns is insns with the best rank (the last insn in READY).  To
+   insns is insns with the best rank (the first insn in READY).  To
    make this function tries different samples of ready insns.  READY
    is current queue `ready'.  Global array READY_TRY reflects what
-   insns are already issued in this try.  STATE is current processor
-   state.  If the function returns nonzero, INDEX will contain index
+   insns are already issued in this try.  INDEX will contain index
    of the best insn in READY.  The following function is used only for
    first cycle multipass scheduling.  */
-
 static int
-max_issue (ready, state, index)
-     struct ready_list *ready;
-     state_t state;
-     int *index;
+max_issue (ready, index)
+  struct ready_list *ready;
+  int *index;
 {
-  int i, best, n, temp_index, delay;
-  state_t temp_state;
+  int n, i, all, n_ready, lookahead, best, delay;
+  struct choice_entry *top;
   rtx insn;
-  int max_lookahead = (*targetm.sched.first_cycle_multipass_dfa_lookahead) ();
 
-  if (state_dead_lock_p (state))
-    return 0;
-
-  temp_state = alloca (dfa_state_size);
+  lookahead = (*targetm.sched.first_cycle_multipass_dfa_lookahead) ();
   best = 0;
-  
-  for (i = 0; i < ready->n_ready; i++)
+  memcpy (choice_stack->state, curr_state, dfa_state_size);
+  top = choice_stack;
+  top->rest = lookahead;
+  top->n = 0;
+  n_ready = ready->n_ready;
+  for (all = i = 0; i < n_ready; i++)
     if (!ready_try [i])
-      {
-       insn = ready_element (ready, i);
-       
-       if (INSN_CODE (insn) < 0)
-         continue;
-       
-       memcpy (temp_state, state, dfa_state_size);
-       
-       delay = state_transition (temp_state, insn);
-       
-       if (delay == 0)
-         {
-           if (!targetm.sched.dfa_bubble)
-             continue;
-           else
-             {
-               int j;
-               rtx bubble;
-               
-               for (j = 0;
-                    (bubble = (*targetm.sched.dfa_bubble) (j)) != NULL_RTX;
-                    j++)
-                 if (state_transition (temp_state, bubble) < 0
-                     && state_transition (temp_state, insn) < 0)
-                   break;
-               
-               if (bubble == NULL_RTX)
-                 continue;
-             }
-         }
-       else if (delay > 0)
-         continue;
-       
-       --max_lookahead;
-       
-       if (max_lookahead < 0)
-         break;
-       
-       ready_try [i] = 1;
-
-       n = max_issue (ready, temp_state, &temp_index);
-       if (n > 0 || ready_try[0])
-         n += 1;
-
-       if (best < n)
-         {
-           best = n;
-           *index = i;
-         }
-       ready_try [i] = 0;
-      }
-  
+      all++;
+  i = 0;
+  for (;;)
+    {
+      if (top->rest == 0 || i >= n_ready)
+       {
+         if (top == choice_stack)
+           break;
+         if (best < top - choice_stack && ready_try [0])
+           {
+             best = top - choice_stack;
+             *index = choice_stack [1].index;
+             if (top->n == issue_rate - cycle_issued_insns || best == all)
+               break;
+           }
+         i = top->index;
+         ready_try [i] = 0;
+         top--;
+         memcpy (curr_state, top->state, dfa_state_size);
+       }
+      else if (!ready_try [i])
+       {
+         insn = ready_element (ready, i);
+         delay = state_transition (curr_state, insn);
+         if (delay < 0)
+           {
+             if (state_dead_lock_p (curr_state))
+               top->rest = 0;
+             else
+               top->rest--;
+             n = top->n;
+             if (memcmp (top->state, curr_state, dfa_state_size) != 0)
+               n++;
+             top++;
+             top->rest = lookahead;
+             top->index = i;
+             top->n = n;
+             memcpy (top->state, curr_state, dfa_state_size);
+             ready_try [i] = 1;
+             i = -1;
+           }
+       }
+      i++;
+    }
+  while (top != choice_stack)
+    {
+      ready_try [top->index] = 0;
+      top--;
+    }
+  memcpy (curr_state, choice_stack->state, dfa_state_size);
   return best;
 }
 
@@ -1873,14 +2070,27 @@ choose_ready (ready)
      struct ready_list *ready;
 {
   if (!targetm.sched.first_cycle_multipass_dfa_lookahead
-      || (*targetm.sched.first_cycle_multipass_dfa_lookahead) () <= 0)
+      || (*targetm.sched.first_cycle_multipass_dfa_lookahead) () <= 0
+      || SCHED_GROUP_P (ready_element (ready, 0)))
     return ready_remove_first (ready);
   else
     {
       /* Try to choose the better insn.  */
-      int index;
+      int index, i;
+      rtx insn;
 
-      if (max_issue (ready, curr_state, &index) == 0)
+      insn = ready_element (ready, 0);
+      if (INSN_CODE (insn) < 0)
+       return ready_remove_first (ready);
+      for (i = 1; i < ready->n_ready; i++)
+       {
+         insn = ready_element (ready, i);
+         ready_try [i]
+           = (INSN_CODE (insn) < 0
+              || (targetm.sched.first_cycle_multipass_dfa_lookahead_guard
+                  && !(*targetm.sched.first_cycle_multipass_dfa_lookahead_guard) (insn)));
+       }
+      if (max_issue (ready, &index) == 0)
        return ready_remove_first (ready);
       else
        return ready_remove (ready, index);
@@ -1908,9 +2118,10 @@ schedule_block (b, rgn_n_insns)
      int rgn_n_insns;
 {
   struct ready_list ready;
-  int first_cycle_insn_p;
+  int i, first_cycle_insn_p;
   int can_issue_more;
   state_t temp_state = NULL;  /* It is used for multipass scheduling.  */
+  int sort_p, advance, start_clock_var;
 
   /* Head/tail info for this block.  */
   rtx prev_head = current_sched_info->prev_head;
@@ -1962,6 +2173,11 @@ schedule_block (b, rgn_n_insns)
       temp_state = alloca (dfa_state_size);
       ready_try = (char *) xmalloc ((rgn_n_insns + 1) * sizeof (char));
       memset (ready_try, 0, (rgn_n_insns + 1) * sizeof (char));
+      choice_stack
+       = (struct choice_entry *) xmalloc ((rgn_n_insns + 1)
+                                          * sizeof (struct choice_entry));
+      for (i = 0; i <= rgn_n_insns; i++)
+       choice_stack[i].state = (state_t) xmalloc (dfa_state_size);
     }
 
   (*current_sched_info->init_ready_list) (&ready);
@@ -1989,35 +2205,55 @@ schedule_block (b, rgn_n_insns)
 
   /* Start just before the beginning of time.  */
   clock_var = -1;
+  advance = 0;
 
+  sort_p = TRUE;
   /* Loop until all the insns in BB are scheduled.  */
   while ((*current_sched_info->schedule_more_p) ())
     {
-      clock_var++;
-
-      advance_one_cycle ();
-
-      /* Add to the ready list all pending insns that can be issued now.
-         If there are no ready insns, increment clock until one
-         is ready and add all pending insns at that point to the ready
-         list.  */
-      queue_to_ready (&ready);
+      do
+       {
+         start_clock_var = clock_var;
 
-      if (ready.n_ready == 0)
-       abort ();
+         clock_var++;
+         
+         advance_one_cycle ();
+         
+         /* Add to the ready list all pending insns that can be issued now.
+            If there are no ready insns, increment clock until one
+            is ready and add all pending insns at that point to the ready
+            list.  */
+         queue_to_ready (&ready);
+         
+         if (ready.n_ready == 0)
+           abort ();
+         
+         if (sched_verbose >= 2)
+           {
+             fprintf (sched_dump, ";;\t\tReady list after queue_to_ready:  ");
+             debug_ready_list (&ready);
+           }
+         advance -= clock_var - start_clock_var;
+       }
+      while (advance > 0);
 
-      if (sched_verbose >= 2)
+      if (sort_p)
        {
-         fprintf (sched_dump, ";;\t\tReady list after queue_to_ready:  ");
-         debug_ready_list (&ready);
+         /* Sort the ready list based on priority.  */
+         ready_sort (&ready);
+         
+         if (sched_verbose >= 2)
+           {
+             fprintf (sched_dump, ";;\t\tReady list after ready_sort:  ");
+             debug_ready_list (&ready);
+           }
        }
 
-      /* Sort the ready list based on priority.  */
-      ready_sort (&ready);
-
       /* Allow the target to reorder the list, typically for
         better instruction bundling.  */
-      if (targetm.sched.reorder)
+      if (sort_p && targetm.sched.reorder
+         && (ready.n_ready == 0
+             || !SCHED_GROUP_P (ready_element (&ready, 0))))
        can_issue_more =
          (*targetm.sched.reorder) (sched_dump, sched_verbose,
                                    ready_lastpos (&ready),
@@ -2026,6 +2262,7 @@ schedule_block (b, rgn_n_insns)
        can_issue_more = issue_rate;
 
       first_cycle_insn_p = 1;
+      cycle_issued_insns = 0;
       for (;;)
        {
          rtx insn;
@@ -2055,8 +2292,21 @@ schedule_block (b, rgn_n_insns)
                break;
              
              /* Select and remove the insn from the ready list.  */
-             insn = choose_ready (&ready);
+             if (sort_p)
+               insn = choose_ready (&ready);
+             else
+               insn = ready_remove_first (&ready);
              
+             if (targetm.sched.dfa_new_cycle
+                 && (*targetm.sched.dfa_new_cycle) (sched_dump, sched_verbose,
+                                                    insn, last_clock_var,
+                                                    clock_var, &sort_p))
+               {
+                 ready_add (&ready, insn);
+                 break;
+               }
+           
+             sort_p = TRUE;
              memcpy (temp_state, curr_state, dfa_state_size);
              if (recog_memoized (insn) < 0)
                {
@@ -2160,27 +2410,41 @@ schedule_block (b, rgn_n_insns)
 
          if (targetm.sched.use_dfa_pipeline_interface
              && (*targetm.sched.use_dfa_pipeline_interface) ())
-           memcpy (curr_state, temp_state, dfa_state_size);
+           {
+             if (memcmp (curr_state, temp_state, dfa_state_size) != 0)
+               cycle_issued_insns++;
+             memcpy (curr_state, temp_state, dfa_state_size);
+           }
            
          if (targetm.sched.variable_issue)
            can_issue_more =
              (*targetm.sched.variable_issue) (sched_dump, sched_verbose,
                                               insn, can_issue_more);
-         else
+         /* A naked CLOBBER or USE generates no instruction, so do
+            not count them against the issue rate.  */
+         else if (GET_CODE (PATTERN (insn)) != USE
+                  && GET_CODE (PATTERN (insn)) != CLOBBER)
            can_issue_more--;
 
-         schedule_insn (insn, &ready, clock_var);
+         advance = schedule_insn (insn, &ready, clock_var);
+         if (advance != 0)
+           break;
 
        next:
          first_cycle_insn_p = 0;
 
-         if (targetm.sched.reorder2)
+         /* Sort the ready list based on priority.  This must be
+            redone here, as schedule_insn may have readied additional
+            insns that will not be sorted correctly.  */
+         if (ready.n_ready > 0)
+           ready_sort (&ready);
+
+         if (targetm.sched.reorder2
+             && (ready.n_ready == 0
+                 || !SCHED_GROUP_P (ready_element (&ready, 0))))
            {
-             /* Sort the ready list based on priority.  */
-             if (ready.n_ready > 0)
-               ready_sort (&ready);
              can_issue_more =
-               (*targetm.sched.reorder2) (sched_dump,sched_verbose,
+               (*targetm.sched.reorder2) (sched_dump, sched_verbose,
                                           ready.n_ready
                                           ? ready_lastpos (&ready) : NULL,
                                           &ready.n_ready, clock_var);
@@ -2216,6 +2480,27 @@ schedule_block (b, rgn_n_insns)
   head = NEXT_INSN (prev_head);
   tail = last_scheduled_insn;
 
+  if (!reload_completed)
+    {
+      rtx insn, link, next;
+      
+      /* INSN_TICK (minimum clock tick at which the insn becomes
+         ready) may be not correct for the insn in the subsequent
+         blocks of the region.  We should use a correct value of
+         `clock_var' or modify INSN_TICK.  It is better to keep
+         clock_var value equal to 0 at the start of a basic block.
+         Therefore we modify INSN_TICK here.  */
+      for (insn = head; insn != tail; insn = NEXT_INSN (insn))
+       if (INSN_P (insn))
+         {
+           for (link = INSN_DEPEND (insn); link != 0; link = XEXP (link, 1))
+             {
+               next = XEXP (link, 0);
+               INSN_TICK (next) -= clock_var;
+             }
+         }
+    }
+
   /* Restore-other-notes: NOTE_LIST is the end of a chain of notes
      previously found among the insns.  Insert them at the beginning
      of the insns.  */
@@ -2252,7 +2537,12 @@ schedule_block (b, rgn_n_insns)
 
   if (targetm.sched.use_dfa_pipeline_interface
       && (*targetm.sched.use_dfa_pipeline_interface) ())
-    free (ready_try);
+    {
+      free (ready_try);
+      for (i = 0; i <= rgn_n_insns; i++)
+       free (choice_stack [i].state);
+      free (choice_stack);
+    }
 }
 \f
 /* Set_priorities: compute priority of each insn in the block.  */
@@ -2277,8 +2567,7 @@ set_priorities (head, tail)
       if (GET_CODE (insn) == NOTE)
        continue;
 
-      if (!(SCHED_GROUP_P (insn)))
-       n_insn++;
+      n_insn++;
       (void) priority (insn);
     }
 
@@ -2365,8 +2654,6 @@ sched_init (dump_file)
 
   init_dependency_caches (luid);
 
-  compute_bb_for_insn (old_max_uid);
-
   init_alias_analysis ();
 
   if (write_symbols != NO_DEBUG)