We can currently select an insn to be scheduled, only to find out that
it's not actually valid at the current time, either due to state
conflicts or being an asm with something else already scheduled in the
same cycle. Not only is this pointless, it causes problem with the
sched_reorder logic in the TI C6X port (which will be submitted later).
The solution is to prune the ready list earlier. More code is moved out
of the schedule_block main loop, which is IMO always a good thing.

Bootstrapped and tested (a slightly earlier version with an unused
variable) on i686-linux; I also verified that there are no changes in
code generation on any of my testcases.


Bernd
        * haifa-sched.c (prune_ready_list): New function, broken out of
        schedule_block.
        (schedule_block): Use it.

Index: gcc/haifa-sched.c
===================================================================
--- gcc/haifa-sched.c.orig
+++ gcc/haifa-sched.c
@@ -2614,8 +2614,8 @@ max_issue (struct ready_list *ready, int
            {
              if (state_dead_lock_p (state)
                  || insn_finishes_cycle_p (insn))
-               /* We won't issue any more instructions in the next
-                  choice_state.  */
+               /* We won't issue any more instructions in the next
+                  choice_state.  */
                top->rest = 0;
              else
                top->rest--;
@@ -2863,6 +2863,52 @@ commit_schedule (rtx prev_head, rtx tail
   VEC_truncate (rtx, scheduled_insns, 0);
 }
 
+/* Examine all insns on the ready list and queue those which can't be
+   issued in this cycle.  TEMP_STATE is temporary scheduler state we
+   can use as scratch space.  If FIRST_CYCLE_INSN_P is true, no insns
+   have been issued for the current cycle, which means it is valid to
+   issue an asm statement.  */
+
+static void
+prune_ready_list (state_t temp_state, bool first_cycle_insn_p)
+{
+  int i;
+
+ restart:
+  for (i = 0; i < ready.n_ready; i++)
+    {
+      rtx insn = ready_element (&ready, i);
+      int cost = 0;
+      const char *reason = "resource conflict";
+
+      if (recog_memoized (insn) < 0)
+       {
+         if (!first_cycle_insn_p
+             && (GET_CODE (PATTERN (insn)) == ASM_INPUT
+                 || asm_noperands (PATTERN (insn)) >= 0))
+           cost = 1;
+         reason = "asm";
+       }
+      else if (flag_sched_pressure)
+       cost = 0;
+      else
+       {
+         memcpy (temp_state, curr_state, dfa_state_size);
+         cost = state_transition (temp_state, insn);
+         if (cost < 0)
+           cost = 0;
+         else if (cost == 0)
+           cost = 1;
+       }
+      if (cost >= 1)
+       {
+         ready_remove (&ready, i);
+         queue_insn (insn, cost, reason);
+         goto restart;
+       }
+    }
+}
+
 /* Use forward list scheduling to rearrange insns of block pointed to by
    TARGET_BB, possibly bringing insns from subsequent blocks in the same
    region.  */
@@ -3014,6 +3060,10 @@ schedule_block (basic_block *target_bb)
        }
       while (advance > 0);
 
+      prune_ready_list (temp_state, true);
+      if (ready.n_ready == 0)
+        continue;
+
       if (sort_p)
        {
          /* Sort the ready list based on priority.  */
@@ -3144,44 +3194,6 @@ schedule_block (basic_block *target_bb)
            }
 
          sort_p = TRUE;
-         memcpy (temp_state, curr_state, dfa_state_size);
-         if (recog_memoized (insn) < 0)
-           {
-             asm_p = (GET_CODE (PATTERN (insn)) == ASM_INPUT
-                      || asm_noperands (PATTERN (insn)) >= 0);
-             if (!first_cycle_insn_p && asm_p)
-               /* This is asm insn which is tried to be issued on the
-                  cycle not first.  Issue it on the next cycle.  */
-               cost = 1;
-             else
-               /* A USE insn, or something else we don't need to
-                  understand.  We can't pass these directly to
-                  state_transition because it will trigger a
-                  fatal error for unrecognizable insns.  */
-               cost = 0;
-           }
-         else if (sched_pressure_p)
-           cost = 0;
-         else
-           {
-             cost = state_transition (temp_state, insn);
-             if (cost < 0)
-               cost = 0;
-             else if (cost == 0)
-               cost = 1;
-           }
-
-         if (cost >= 1)
-           {
-             queue_insn (insn, cost, "resource conflict");
-             if (SCHED_GROUP_P (insn))
-               {
-                 advance = cost;
-                 break;
-               }
-
-             continue;
-           }
 
          if (current_sched_info->can_schedule_ready_p
              && ! (*current_sched_info->can_schedule_ready_p) (insn))
@@ -3202,14 +3214,20 @@ schedule_block (basic_block *target_bb)
 
          /* Update counters, etc in the scheduler's front end.  */
          (*current_sched_info->begin_schedule_ready) (insn);
-         VEC_safe_push (rtx, heap, scheduled_insns, insn);
+         VEC_safe_push (rtx, heap, scheduled_insns, insn);
          last_scheduled_insn = insn;
 
-         if (memcmp (curr_state, temp_state, dfa_state_size) != 0)
-            {
-              cycle_issued_insns++;
-              memcpy (curr_state, temp_state, dfa_state_size);
-            }
+         if (recog_memoized (insn) >= 0)
+           {
+             cost = state_transition (curr_state, insn);
+             if (!flag_sched_pressure)
+               gcc_assert (cost < 0);
+             cycle_issued_insns++;
+             asm_p = false;
+           }
+         else
+           asm_p = (GET_CODE (PATTERN (insn)) == ASM_INPUT
+                    || asm_noperands (PATTERN (insn)) >= 0);
 
          if (targetm.sched.variable_issue)
            can_issue_more =
@@ -3230,6 +3248,9 @@ schedule_block (basic_block *target_bb)
 
          first_cycle_insn_p = false;
 
+         if (ready.n_ready > 0)
+            prune_ready_list (temp_state, false);
+
          /* 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.  */
@@ -3241,7 +3262,7 @@ schedule_block (basic_block *target_bb)
          if (ready.n_ready && DEBUG_INSN_P (ready_element (&ready, 0))
              && (*current_sched_info->schedule_more_p) ())
            {
-             while (ready.n_ready && DEBUG_INSN_P (ready_element (&ready, 0)))
+             while (ready.n_ready && DEBUG_INSN_P (ready_element (&ready, 0)))
                {
                  insn = ready_remove_first (&ready);
                  gcc_assert (DEBUG_INSN_P (insn));

Reply via email to