OSDN Git Service

* config/s390/s390.c (s390_fixup_clobbered_return_reg):
[pf3gnuchains/gcc-fork.git] / gcc / haifa-sched.c
index 5a0c208..a8b587e 100644 (file)
@@ -305,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
@@ -319,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));
@@ -366,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 *));
 
@@ -851,8 +1016,13 @@ 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;
 
@@ -1017,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];
 }
 
@@ -1101,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
@@ -1124,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)
@@ -1152,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))
@@ -1177,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
@@ -1186,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;
+           }
        }
     }
 
@@ -1195,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.  */
@@ -1228,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)
        {
@@ -1536,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
@@ -1558,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))
        {
@@ -1731,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.  */
@@ -1743,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
@@ -1772,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;
 }
 
@@ -1868,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);
@@ -1903,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;
@@ -1957,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);
@@ -1984,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),
@@ -2021,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;
@@ -2050,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)
                {
@@ -2155,7 +2410,11 @@ 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 =
@@ -2167,18 +2426,25 @@ schedule_block (b, rgn_n_insns)
                   && 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);
@@ -2214,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.  */
@@ -2250,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.  */
@@ -2275,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);
     }