OSDN Git Service

2011-01-14 Tobias Burnus <burnus@net-b.de>
[pf3gnuchains/gcc-fork.git] / gcc / haifa-sched.c
index 1865d45..bd3b84c 100644 (file)
@@ -129,7 +129,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "diagnostic-core.h"
-#include "toplev.h"
 #include "rtl.h"
 #include "tm_p.h"
 #include "hard-reg-set.h"
@@ -167,25 +166,12 @@ int issue_rate;
    N=3: rtl at abort point, control-flow, regions info.
    N=5: dependences info.  */
 
-static int sched_verbose_param = 0;
 int sched_verbose = 0;
 
 /* Debugging file.  All printouts are sent to dump, which is always set,
    either to stderr, or to the dump listing file (-dRS).  */
 FILE *sched_dump = 0;
 
-/* fix_sched_param() is called from toplev.c upon detection
-   of the -fsched-verbose=N option.  */
-
-void
-fix_sched_param (const char *param, const char *val)
-{
-  if (!strcmp (param, "verbose"))
-    sched_verbose_param = atoi (val);
-  else
-    warning (0, "fix_sched_param: unknown param: %s", param);
-}
-
 /* This is a placeholder for the scheduler parameters common
    to all schedulers.  */
 struct common_sched_info_def *common_sched_info;
@@ -199,10 +185,6 @@ struct common_sched_info_def *common_sched_info;
 /* The minimal value of the INSN_TICK of an instruction.  */
 #define MIN_TICK (-max_insn_queue_index)
 
-/* Issue points are used to distinguish between instructions in max_issue ().
-   For now, all instructions are equally good.  */
-#define ISSUE_POINTS(INSN) 1
-
 /* List of important notes we must keep around.  This is a pointer to the
    last element in the list.  */
 rtx note_list;
@@ -532,6 +514,7 @@ static void extend_h_i_d (void);
 
 static void ready_add (struct ready_list *, rtx, bool);
 static rtx ready_remove_first (struct ready_list *);
+static rtx ready_remove_first_dispatch (struct ready_list *ready);
 
 static void queue_to_ready (struct ready_list *);
 static int early_queue_to_ready (state_t, struct ready_list *);
@@ -543,8 +526,6 @@ static void debug_ready_list (struct ready_list *);
 static rtx ready_remove (struct ready_list *, int);
 static void ready_remove_insn (rtx);
 
-static int choose_ready (struct ready_list *, rtx *);
-
 static void fix_inter_tick (rtx, rtx);
 static int fix_tick_ready (rtx);
 static void change_queue_index (rtx, int);
@@ -714,7 +695,7 @@ setup_ref_regs (rtx x)
 static void
 initiate_bb_reg_pressure_info (basic_block bb)
 {
-  unsigned int i;
+  unsigned int i ATTRIBUTE_UNUSED;
   rtx insn;
 
   if (current_nr_blocks > 1)
@@ -2393,6 +2374,12 @@ insn_finishes_cycle_p (rtx insn)
   return false;
 }
 
+/* Define type for target data used in multipass scheduling.  */
+#ifndef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DATA_T
+# define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DATA_T int
+#endif
+typedef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DATA_T first_cycle_multipass_data_t;
+
 /* The following structure describe an entry of the stack of choices.  */
 struct choice_entry
 {
@@ -2404,6 +2391,8 @@ struct choice_entry
   int n;
   /* State after issuing the insn.  */
   state_t state;
+  /* Target-specific data.  */
+  first_cycle_multipass_data_t target_data;
 };
 
 /* The following array is used to implement a stack of choices used in
@@ -2443,8 +2432,7 @@ static int cached_issue_rate = 0;
    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.  MAX_POINTS is the sum of points
-   of all instructions in READY.  The function stops immediately,
+   insns are already issued in this try.  The function stops immediately,
    if it reached the such a solution, that all instruction can be issued.
    INDEX will contain index of the best insn in READY.  The following
    function is used only for first cycle multipass scheduling.
@@ -2455,9 +2443,9 @@ static int cached_issue_rate = 0;
    CLOBBERs, etc must be filtered elsewhere.  */
 int
 max_issue (struct ready_list *ready, int privileged_n, state_t state,
-          int *index)
+          bool first_cycle_insn_p, int *index)
 {
-  int n, i, all, n_ready, best, delay, tries_num, max_points;
+  int n, i, all, n_ready, best, delay, tries_num;
   int more_issue;
   struct choice_entry *top;
   rtx insn;
@@ -2476,25 +2464,8 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
     }
 
   /* Init max_points.  */
-  max_points = 0;
   more_issue = issue_rate - cycle_issued_insns;
-
-  /* ??? We used to assert here that we never issue more insns than issue_rate.
-     However, some targets (e.g. MIPS/SB1) claim lower issue rate than can be
-     achieved to get better performance.  Until these targets are fixed to use
-     scheduler hooks to manipulate insns priority instead, the assert should
-     be disabled.
-
-     gcc_assert (more_issue >= 0);  */
-
-  for (i = 0; i < n_ready; i++)
-    if (!ready_try [i])
-      {
-       if (more_issue-- > 0)
-         max_points += ISSUE_POINTS (ready_element (ready, i));
-       else
-         break;
-      }
+  gcc_assert (more_issue >= 0);
 
   /* The number of the issued insns in the best solution.  */
   best = 0;
@@ -2505,6 +2476,10 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
   memcpy (top->state, state, dfa_state_size);
   top->rest = dfa_lookahead;
   top->n = 0;
+  if (targetm.sched.first_cycle_multipass_begin)
+    targetm.sched.first_cycle_multipass_begin (&top->target_data,
+                                              ready_try, n_ready,
+                                              first_cycle_insn_p);
 
   /* Count the number of the insns to search among.  */
   for (all = i = 0; i < n_ready; i++)
@@ -2519,12 +2494,17 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
       if (/* If we've reached a dead end or searched enough of what we have
             been asked...  */
          top->rest == 0
-         /* Or have nothing else to try.  */
-         || i >= n_ready)
+         /* or have nothing else to try...  */
+         || i >= n_ready
+         /* or should not issue more.  */
+         || top->n >= more_issue)
        {
          /* ??? (... || i == n_ready).  */
          gcc_assert (i <= n_ready);
 
+         /* We should not issue more than issue_rate instructions.  */
+         gcc_assert (top->n <= more_issue);
+
          if (top == choice_stack)
            break;
 
@@ -2547,7 +2527,7 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
                  /* This is the index of the insn issued first in this
                     solution.  */
                  *index = choice_stack [1].index;
-                 if (top->n == max_points || best == all)
+                 if (top->n == more_issue || best == all)
                    break;
                }
            }
@@ -2558,6 +2538,11 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
 
          /* Backtrack.  */
          ready_try [i] = 0;
+
+         if (targetm.sched.first_cycle_multipass_backtrack)
+           targetm.sched.first_cycle_multipass_backtrack (&top->target_data,
+                                                          ready_try, n_ready);
+
          top--;
          memcpy (state, top->state, dfa_state_size);
        }
@@ -2580,7 +2565,7 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
 
              n = top->n;
              if (memcmp (top->state, state, dfa_state_size) != 0)
-               n += ISSUE_POINTS (insn);
+               n++;
 
              /* Advance to the next choice_entry.  */
              top++;
@@ -2589,8 +2574,15 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
              top->index = i;
              top->n = n;
              memcpy (top->state, state, dfa_state_size);
-
              ready_try [i] = 1;
+
+             if (targetm.sched.first_cycle_multipass_issue)
+               targetm.sched.first_cycle_multipass_issue (&top->target_data,
+                                                          ready_try, n_ready,
+                                                          insn,
+                                                          &((top - 1)
+                                                            ->target_data));
+
              i = -1;
            }
        }
@@ -2599,6 +2591,11 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
       i++;
     }
 
+  if (targetm.sched.first_cycle_multipass_end)
+    targetm.sched.first_cycle_multipass_end (best != 0
+                                            ? &choice_stack[1].target_data
+                                            : NULL);
+
   /* Restore the original state of the DFA.  */
   memcpy (state, choice_stack->state, dfa_state_size);
 
@@ -2613,7 +2610,8 @@ max_issue (struct ready_list *ready, int privileged_n, state_t state,
    0 if INSN_PTR is set to point to the desirable insn,
    1 if choose_ready () should be restarted without advancing the cycle.  */
 static int
-choose_ready (struct ready_list *ready, rtx *insn_ptr)
+choose_ready (struct ready_list *ready, bool first_cycle_insn_p,
+             rtx *insn_ptr)
 {
   int lookahead;
 
@@ -2642,7 +2640,11 @@ choose_ready (struct ready_list *ready, rtx *insn_ptr)
   if (lookahead <= 0 || SCHED_GROUP_P (ready_element (ready, 0))
       || DEBUG_INSN_P (ready_element (ready, 0)))
     {
-      *insn_ptr = ready_remove_first (ready);
+      if (targetm.sched.dispatch (NULL_RTX, IS_DISPATCH_ON))
+       *insn_ptr = ready_remove_first_dispatch (ready);
+      else
+       *insn_ptr = ready_remove_first (ready);
+
       return 0;
     }
   else
@@ -2722,14 +2724,12 @@ choose_ready (struct ready_list *ready, rtx *insn_ptr)
          {
            insn = ready_element (ready, i);
 
-#ifdef ENABLE_CHECKING
            /* If this insn is recognizable we should have already
               recognized it earlier.
               ??? Not very clear where this is supposed to be done.
               See dep_cost_1.  */
-           gcc_assert (INSN_CODE (insn) >= 0
-                       || recog_memoized (insn) < 0);
-#endif
+           gcc_checking_assert (INSN_CODE (insn) >= 0
+                                || recog_memoized (insn) < 0);
 
            ready_try [i]
              = (/* INSN_CODE check can be omitted here as it is also done later
@@ -2740,7 +2740,7 @@ choose_ready (struct ready_list *ready, rtx *insn_ptr)
                     (insn)));
          }
 
-      if (max_issue (ready, 1, curr_state, &index) == 0)
+      if (max_issue (ready, 1, curr_state, first_cycle_insn_p, &index) == 0)
        {
          *insn_ptr = ready_remove_first (ready);
          if (sched_verbose >= 4)
@@ -2768,7 +2768,8 @@ choose_ready (struct ready_list *ready, rtx *insn_ptr)
 void
 schedule_block (basic_block *target_bb)
 {
-  int i, first_cycle_insn_p;
+  int i;
+  bool 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;
@@ -2974,7 +2975,7 @@ schedule_block (basic_block *target_bb)
       else
        can_issue_more = issue_rate;
 
-      first_cycle_insn_p = 1;
+      first_cycle_insn_p = true;
       cycle_issued_insns = 0;
       for (;;)
        {
@@ -3017,7 +3018,7 @@ schedule_block (basic_block *target_bb)
              int res;
 
              insn = NULL_RTX;
-             res = choose_ready (&ready, &insn);
+             res = choose_ready (&ready, first_cycle_insn_p, &insn);
 
              if (res < 0)
                /* Finish cycle.  */
@@ -3140,6 +3141,10 @@ schedule_block (basic_block *target_bb)
                                                       last_scheduled_insn);
 
          move_insn (insn, last_scheduled_insn, current_sched_info->next_tail);
+
+         if (targetm.sched.dispatch (NULL_RTX, IS_DISPATCH_ON))
+           targetm.sched.dispatch_do (insn, ADD_TO_DISPATCH_WINDOW);
+
          reemit_notes (insn);
          last_scheduled_insn = insn;
 
@@ -3166,7 +3171,7 @@ schedule_block (basic_block *target_bb)
          if (advance != 0)
            break;
 
-         first_cycle_insn_p = 0;
+         first_cycle_insn_p = false;
 
          /* Sort the ready list based on priority.  This must be
             redone here, as schedule_insn may have readied additional
@@ -3364,8 +3369,12 @@ sched_init (void)
   flag_schedule_speculative_load = 0;
 #endif
 
+  if (targetm.sched.dispatch (NULL_RTX, IS_DISPATCH_ON))
+    targetm.sched.dispatch_do (NULL_RTX, DISPATCH_INIT);
+
   sched_pressure_p = (flag_sched_pressure && ! reload_completed
                      && common_sched_info->sched_pass_id == SCHED_RGN_PASS);
+
   if (sched_pressure_p)
     ira_setup_eliminable_regset ();
 
@@ -3958,7 +3967,13 @@ sched_extend_ready_list (int new_sched_ready_n_insns)
                             new_sched_ready_n_insns + 1);
 
   for (; i <= new_sched_ready_n_insns; i++)
-    choice_stack[i].state = xmalloc (dfa_state_size);
+    {
+      choice_stack[i].state = xmalloc (dfa_state_size);
+
+      if (targetm.sched.first_cycle_multipass_init)
+       targetm.sched.first_cycle_multipass_init (&(choice_stack[i]
+                                                   .target_data));
+    }
 
   sched_ready_n_insns = new_sched_ready_n_insns;
 }
@@ -3977,7 +3992,13 @@ sched_finish_ready_list (void)
   ready_try = NULL;
 
   for (i = 0; i <= sched_ready_n_insns; i++)
-    free (choice_stack [i].state);
+    {
+      if (targetm.sched.first_cycle_multipass_fini)
+       targetm.sched.first_cycle_multipass_fini (&(choice_stack[i]
+                                                   .target_data));
+
+      free (choice_stack [i].state);
+    }
   free (choice_stack);
   choice_stack = NULL;
 
@@ -4234,10 +4255,9 @@ xrecalloc (void *p, size_t new_nmemb, size_t old_nmemb, size_t size)
 /* Helper function.
    Find fallthru edge from PRED.  */
 edge
-find_fallthru_edge (basic_block pred)
+find_fallthru_edge_from (basic_block pred)
 {
   edge e;
-  edge_iterator ei;
   basic_block succ;
 
   succ = pred->next_bb;
@@ -4245,21 +4265,23 @@ find_fallthru_edge (basic_block pred)
 
   if (EDGE_COUNT (pred->succs) <= EDGE_COUNT (succ->preds))
     {
-      FOR_EACH_EDGE (e, ei, pred->succs)
-       if (e->flags & EDGE_FALLTHRU)
-         {
-           gcc_assert (e->dest == succ);
-           return e;
-         }
+      e = find_fallthru_edge (pred->succs);
+
+      if (e)
+       {
+         gcc_assert (e->dest == succ);
+         return e;
+       }
     }
   else
     {
-      FOR_EACH_EDGE (e, ei, succ->preds)
-       if (e->flags & EDGE_FALLTHRU)
-         {
-           gcc_assert (e->src == pred);
-           return e;
-         }
+      e = find_fallthru_edge (succ->preds);
+
+      if (e)
+       {
+         gcc_assert (e->src == pred);
+         return e;
+       }
     }
 
   return NULL;
@@ -4301,7 +4323,7 @@ init_before_recovery (basic_block *before_recovery_ptr)
   edge e;
 
   last = EXIT_BLOCK_PTR->prev_bb;
-  e = find_fallthru_edge (last);
+  e = find_fallthru_edge_from (last);
 
   if (e)
     {
@@ -4445,6 +4467,8 @@ sched_create_recovery_edges (basic_block first_bb, basic_block rec,
     edge_flags = 0;
 
   make_single_succ_edge (rec, second_bb, edge_flags);
+  if (dom_info_available_p (CDI_DOMINATORS))
+    set_immediate_dominator (CDI_DOMINATORS, rec, first_bb);
 }
 
 /* This function creates recovery code for INSN.  If MUTATE_P is nonzero,
@@ -5093,7 +5117,7 @@ calc_priorities (rtx_vec_t roots)
   int i;
   rtx insn;
 
-  for (i = 0; VEC_iterate (rtx, roots, i, insn); i++)
+  FOR_EACH_VEC_ELT (rtx, roots, i, insn)
     priority (insn);
 }
 
@@ -5321,7 +5345,7 @@ sched_scan (const struct sched_scan_info_def *ssi,
          unsigned i;
          basic_block x;
 
-         for (i = 0; VEC_iterate (basic_block, bbs, i, x); i++)
+         FOR_EACH_VEC_ELT (basic_block, bbs, i, x)
            init_bb (x);
        }
 
@@ -5336,7 +5360,7 @@ sched_scan (const struct sched_scan_info_def *ssi,
       unsigned i;
       basic_block x;
 
-      for (i = 0; VEC_iterate (basic_block, bbs, i, x); i++)
+      FOR_EACH_VEC_ELT (basic_block, bbs, i, x)
        init_insns_in_bb (x);
     }
 
@@ -5348,7 +5372,7 @@ sched_scan (const struct sched_scan_info_def *ssi,
       unsigned i;
       rtx x;
 
-      for (i = 0; VEC_iterate (rtx, insns, i, x); i++)
+      FOR_EACH_VEC_ELT (rtx, insns, i, x)
        init_insn (x);
     }
 
@@ -5478,7 +5502,7 @@ haifa_finish_h_i_d (void)
   haifa_insn_data_t data;
   struct reg_use_data *use, *next;
 
-  for (i = 0; VEC_iterate (haifa_insn_data_def, h_i_d, i, data); i++)
+  FOR_EACH_VEC_ELT (haifa_insn_data_def, h_i_d, i, data)
     {
       if (data->reg_pressure != NULL)
        free (data->reg_pressure);
@@ -5557,4 +5581,73 @@ sched_emit_insn (rtx pat)
   return insn;
 }
 
+/* This function returns a candidate satisfying dispatch constraints from
+   the ready list.  */
+
+static rtx
+ready_remove_first_dispatch (struct ready_list *ready)
+{
+  int i;
+  rtx insn = ready_element (ready, 0);
+
+  if (ready->n_ready == 1
+      || INSN_CODE (insn) < 0
+      || !INSN_P (insn)
+      || !active_insn_p (insn)
+      || targetm.sched.dispatch (insn, FITS_DISPATCH_WINDOW))
+    return ready_remove_first (ready);
+
+  for (i = 1; i < ready->n_ready; i++)
+    {
+      insn = ready_element (ready, i);
+
+      if (INSN_CODE (insn) < 0
+         || !INSN_P (insn)
+         || !active_insn_p (insn))
+       continue;
+
+      if (targetm.sched.dispatch (insn, FITS_DISPATCH_WINDOW))
+       {
+         /* Return ith element of ready.  */
+         insn = ready_remove (ready, i);
+         return insn;
+       }
+    }
+
+  if (targetm.sched.dispatch (NULL_RTX, DISPATCH_VIOLATION))
+    return ready_remove_first (ready);
+
+  for (i = 1; i < ready->n_ready; i++)
+    {
+      insn = ready_element (ready, i);
+
+      if (INSN_CODE (insn) < 0
+         || !INSN_P (insn)
+         || !active_insn_p (insn))
+       continue;
+
+      /* Return i-th element of ready.  */
+      if (targetm.sched.dispatch (insn, IS_CMP))
+       return ready_remove (ready, i);
+    }
+
+  return ready_remove_first (ready);
+}
+
+/* Get number of ready insn in the ready list.  */
+
+int
+number_in_ready (void)
+{
+  return ready.n_ready;
+}
+
+/* Get number of ready's in the ready list.  */
+
+rtx
+get_ready_element (int i)
+{
+  return ready_element (&ready, i);
+}
+
 #endif /* INSN_SCHEDULING */