OSDN Git Service

2002-01-16 H.J. Lu <hjl@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / haifa-sched.c
index 2d8376e..7b9a2e8 100644 (file)
@@ -1,24 +1,24 @@
 /* Instruction scheduling pass.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2001 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by,
    and currently maintained by, Jim Wilson (wilson@cygnus.com)
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
-later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to the Free
-the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 02111-1307, USA.  */
 
 /* Instruction scheduling pass.  This file, along with sched-deps.c,
@@ -148,6 +148,7 @@ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "toplev.h"
 #include "recog.h"
 #include "sched-int.h"
+#include "target.h"
 
 #ifdef INSN_SCHEDULING
 
@@ -157,10 +158,6 @@ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 static int issue_rate;
 
-#ifndef ISSUE_RATE
-#define ISSUE_RATE 1
-#endif
-
 /* sched-verbose controls the amount of debugging output the
    scheduler prints.  It is controlled by -fsched-verbose=N:
    N>0 and no -DSR : the output is directed to stderr.
@@ -363,7 +360,7 @@ HAIFA_INLINE int
 insn_unit (insn)
      rtx insn;
 {
-  register int unit = INSN_UNIT (insn);
+  int unit = INSN_UNIT (insn);
 
   if (unit == 0)
     {
@@ -649,7 +646,7 @@ HAIFA_INLINE int
 insn_cost (insn, link, used)
      rtx insn, link, used;
 {
-  register int cost = INSN_COST (insn);
+  int cost = INSN_COST (insn);
 
   if (cost == 0)
     {
@@ -693,12 +690,10 @@ insn_cost (insn, link, used)
 
   if (LINK_COST_FREE (link))
     cost = 0;
-#ifdef ADJUST_COST
-  else if (!LINK_COST_ZERO (link))
+  else if (!LINK_COST_ZERO (link) && targetm.sched.adjust_cost)
     {
-      int ncost = cost;
+      int ncost = (*targetm.sched.adjust_cost) (used, link, insn, cost);
 
-      ADJUST_COST (used, link, insn, ncost);
       if (ncost < 1)
        {
          LINK_COST_FREE (link) = 1;
@@ -708,7 +703,7 @@ insn_cost (insn, link, used)
        LINK_COST_ZERO (link) = 1;
       cost = ncost;
     }
-#endif
+
   return cost;
 }
 
@@ -718,38 +713,43 @@ static int
 priority (insn)
      rtx insn;
 {
-  int this_priority;
   rtx link;
 
   if (! INSN_P (insn))
     return 0;
 
-  if ((this_priority = INSN_PRIORITY (insn)) == 0)
+  if (! INSN_PRIORITY_KNOWN (insn))
     {
+      int this_priority = 0;
+
       if (INSN_DEPEND (insn) == 0)
        this_priority = insn_cost (insn, 0, 0);
       else
-       for (link = INSN_DEPEND (insn); link; link = XEXP (link, 1))
-         {
-           rtx next;
-           int next_priority;
+       {
+         for (link = INSN_DEPEND (insn); link; link = XEXP (link, 1))
+           {
+             rtx next;
+             int next_priority;
 
-           if (RTX_INTEGRATED_P (link))
-             continue;
+             if (RTX_INTEGRATED_P (link))
+               continue;
 
-           next = XEXP (link, 0);
+             next = XEXP (link, 0);
 
-           /* Critical path is meaningful in block boundaries only.  */
-           if (BLOCK_NUM (next) != BLOCK_NUM (insn))
-             continue;
+             /* Critical path is meaningful in block boundaries only.  */
+             if (! (*current_sched_info->contributes_to_priority) (next, insn))
+               continue;
 
-           next_priority = insn_cost (insn, link, next) + priority (next);
-           if (next_priority > this_priority)
-             this_priority = next_priority;
-         }
+             next_priority = insn_cost (insn, link, next) + priority (next);
+             if (next_priority > this_priority)
+               this_priority = next_priority;
+           }
+       }
       INSN_PRIORITY (insn) = this_priority;
+      INSN_PRIORITY_KNOWN (insn) = 1;
     }
-  return this_priority;
+
+  return INSN_PRIORITY (insn);
 }
 \f
 /* Macros and functions for keeping the priority queue sorted, and
@@ -947,7 +947,7 @@ ready_sort (ready)
 
 HAIFA_INLINE static void
 adjust_priority (prev)
-     rtx prev ATTRIBUTE_UNUSED;
+     rtx prev;
 {
   /* ??? There used to be code here to try and estimate how an insn
      affected register lifetimes, but it did it by looking at REG_DEAD
@@ -956,9 +956,9 @@ adjust_priority (prev)
 
      Revisit when we have a machine model to work with and not before.  */
 
-#ifdef ADJUST_PRIORITY
-  ADJUST_PRIORITY (prev);
-#endif
+  if (targetm.sched.adjust_priority)
+    INSN_PRIORITY (prev) =
+      (*targetm.sched.adjust_priority) (prev, INSN_PRIORITY (prev));
 }
 
 /* Clock at which the previous instruction was issued.  */
@@ -1066,8 +1066,7 @@ unlink_other_notes (insn, tail)
        PREV_INSN (next) = prev;
 
       /* See sched_analyze to see how these are handled.  */
-      if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_SETJMP
-         && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG
+      if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG
          && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END
          && NOTE_LINE_NUMBER (insn) != NOTE_INSN_RANGE_BEG
          && NOTE_LINE_NUMBER (insn) != NOTE_INSN_RANGE_END
@@ -1163,23 +1162,17 @@ no_real_insns_p (head, tail)
   return 1;
 }
 
-/* Delete line notes from bb. Save them so they can be later restored
-   (in restore_line_notes ()).  */
+/* Delete line notes from one block. Save them so they can be later restored
+   (in restore_line_notes).  HEAD and TAIL are the boundaries of the
+   block in which notes should be processed.  */
 
 void
-rm_line_notes (b)
-     int b;
+rm_line_notes (head, tail)
+     rtx head, tail;
 {
   rtx next_tail;
-  rtx tail;
-  rtx head;
   rtx insn;
 
-  get_block_head_tail (b, &head, &tail);
-
-  if (head == tail && (! INSN_P (head)))
-    return;
-
   next_tail = NEXT_INSN (tail);
   for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
     {
@@ -1203,13 +1196,14 @@ rm_line_notes (b)
     }
 }
 
-/* Save line number notes for each insn in block B.  */
+/* Save line number notes for each insn in block B.  HEAD and TAIL are
+   the boundaries of the block in which notes should be processed.*/
 
 void
-save_line_notes (b)
+save_line_notes (b, head, tail)
      int b;
+     rtx head, tail;
 {
-  rtx head, tail;
   rtx next_tail;
 
   /* We must use the true line number for the first insn in the block
@@ -1220,28 +1214,29 @@ save_line_notes (b)
   rtx line = line_note_head[b];
   rtx insn;
 
-  get_block_head_tail (b, &head, &tail);
   next_tail = NEXT_INSN (tail);
 
-  for (insn = BLOCK_HEAD (b); insn != next_tail; insn = NEXT_INSN (insn))
+  for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
     if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
       line = insn;
     else
       LINE_NOTE (insn) = line;
 }
 
-/* After block B was scheduled, insert line notes into the insns list.  */
+/* After a block was scheduled, insert line notes into the insns list.
+   HEAD and TAIL are the boundaries of the block in which notes should
+   be processed.*/
 
 void
-restore_line_notes (b)
-     int b;
+restore_line_notes (head, tail)
+     rtx head, tail;
 {
   rtx line, note, prev, new;
   int added_notes = 0;
-  rtx head, next_tail, insn;
+  rtx next_tail, insn;
 
-  head = BLOCK_HEAD (b);
-  next_tail = NEXT_INSN (BLOCK_END (b));
+  head = head;
+  next_tail = NEXT_INSN (tail);
 
   /* Determine the current line-number.  We want to know the current
      line number of the first insn of the block here, in case it is
@@ -1263,6 +1258,7 @@ restore_line_notes (b)
      by real instructions all end up at the same address.  I can find no
      use for line number notes before other notes, so none are emitted.  */
     else if (GET_CODE (insn) != NOTE
+            && INSN_UID (insn) < old_max_uid
             && (note = LINE_NOTE (insn)) != 0
             && note != line
             && (line == 0
@@ -1341,7 +1337,7 @@ rm_redundant_line_notes ()
     fprintf (sched_dump, ";; deleted %d line-number notes\n", notes);
 }
 
-/* Delete notes between head and tail and put them in the chain
+/* Delete notes between HEAD and TAIL and put them in the chain
    of notes ended by NOTE_LIST.  */
 
 void
@@ -1466,7 +1462,7 @@ queue_to_ready (ready)
      of the pending insns at that point to the ready list.  */
   if (ready->n_ready == 0)
     {
-      register int stalls;
+      int stalls;
 
       for (stalls = 1; stalls < INSN_QUEUE_SIZE; stalls++)
        {
@@ -1535,7 +1531,7 @@ move_insn1 (insn, last)
   return insn;
 }
 
-/* Search INSN for REG_SAVE_NOTE note pairs for NOTE_INSN_SETJMP,
+/* Search INSN for REG_SAVE_NOTE note pairs for
    NOTE_INSN_{LOOP,EHREGION}_{BEG,END}; and convert them back into
    NOTEs.  The REG_SAVE_NOTE note following first one is contains the
    saved value for NOTE_BLOCK_NUMBER which is useful for
@@ -1556,15 +1552,8 @@ reemit_notes (insn, last)
        {
          enum insn_note note_type = INTVAL (XEXP (note, 0));
 
-         if (note_type == NOTE_INSN_SETJMP)
-           {
-             retval = emit_note_after (NOTE_INSN_SETJMP, insn);
-             CONST_CALL_P (retval) = CONST_CALL_P (note);
-             remove_note (insn, note);
-             note = XEXP (note, 1);
-           }
-         else if (note_type == NOTE_INSN_RANGE_BEG
-                   || note_type == NOTE_INSN_RANGE_END)
+         if (note_type == NOTE_INSN_RANGE_BEG
+              || note_type == NOTE_INSN_RANGE_END)
            {
              last = emit_note_before (note_type, last);
              remove_note (insn, note);
@@ -1662,7 +1651,7 @@ schedule_block (b, rgn_n_insns)
       fprintf (sched_dump, ";;   ======================================================\n");
       fprintf (sched_dump,
               ";;   -- basic block %d from %d to %d -- %s reload\n",
-              b, INSN_UID (BLOCK_HEAD (b)), INSN_UID (BLOCK_END (b)),
+              b, INSN_UID (head), INSN_UID (tail),
               (reload_completed ? "after" : "before"));
       fprintf (sched_dump, ";;   ======================================================\n");
       fprintf (sched_dump, "\n");
@@ -1674,16 +1663,15 @@ schedule_block (b, rgn_n_insns)
   clear_units ();
 
   /* Allocate the ready list.  */
-  ready.veclen = rgn_n_insns + 1 + ISSUE_RATE;
+  ready.veclen = rgn_n_insns + 1 + issue_rate;
   ready.first = ready.veclen - 1;
   ready.vec = (rtx *) xmalloc (ready.veclen * sizeof (rtx));
   ready.n_ready = 0;
 
   (*current_sched_info->init_ready_list) (&ready);
 
-#ifdef MD_SCHED_INIT
-  MD_SCHED_INIT (sched_dump, sched_verbose);
-#endif
+  if (targetm.sched.md_init)
+    (*targetm.sched.md_init) (sched_dump, sched_verbose, ready.veclen);
 
   /* No insns scheduled in this block yet.  */
   last_scheduled_insn = 0;
@@ -1712,6 +1700,9 @@ schedule_block (b, rgn_n_insns)
          list.  */
       queue_to_ready (&ready);
 
+      if (sched_verbose && targetm.sched.cycle_display)
+       last = (*targetm.sched.cycle_display) (clock_var, last);
+
       if (ready.n_ready == 0)
        abort ();
 
@@ -1726,12 +1717,13 @@ schedule_block (b, rgn_n_insns)
 
       /* Allow the target to reorder the list, typically for
         better instruction bundling.  */
-#ifdef MD_SCHED_REORDER
-      MD_SCHED_REORDER (sched_dump, sched_verbose, ready_lastpos (&ready),
-                       ready.n_ready, clock_var, can_issue_more);
-#else
-      can_issue_more = issue_rate;
-#endif
+      if (targetm.sched.reorder)
+       can_issue_more =
+         (*targetm.sched.reorder) (sched_dump, sched_verbose,
+                                   ready_lastpos (&ready),
+                                   &ready.n_ready, clock_var);
+      else
+       can_issue_more = issue_rate;
 
       if (sched_verbose)
        {
@@ -1740,7 +1732,9 @@ schedule_block (b, rgn_n_insns)
        }
 
       /* Issue insns from ready list.  */
-      while (ready.n_ready != 0 && can_issue_more)
+      while (ready.n_ready != 0
+            && can_issue_more
+            && (*current_sched_info->schedule_more_p) ())
        {
          /* Select and remove the insn from the ready list.  */
          rtx insn = ready_remove_first (&ready);
@@ -1758,19 +1752,27 @@ schedule_block (b, rgn_n_insns)
          last_scheduled_insn = insn;
          last = move_insn (insn, last);
 
-#ifdef MD_SCHED_VARIABLE_ISSUE
-         MD_SCHED_VARIABLE_ISSUE (sched_dump, sched_verbose, insn,
-                                  can_issue_more);
-#else
-         can_issue_more--;
-#endif
+         if (targetm.sched.variable_issue)
+           can_issue_more =
+             (*targetm.sched.variable_issue) (sched_dump, sched_verbose,
+                                              insn, can_issue_more);
+         else
+           can_issue_more--;
 
          schedule_insn (insn, &ready, clock_var);
 
        next:
-         /* Close this block after scheduling its jump.  */
-         if (GET_CODE (last_scheduled_insn) == JUMP_INSN)
-           break;
+         if (targetm.sched.reorder2)
+           {
+             /* 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,
+                                          ready.n_ready
+                                          ? ready_lastpos (&ready) : NULL,
+                                          &ready.n_ready, clock_var);
+           }
        }
 
       /* Debug info.  */
@@ -1778,6 +1780,9 @@ schedule_block (b, rgn_n_insns)
        visualize_scheduled_insns (clock_var);
     }
 
+  if (targetm.sched.md_finish)
+    (*targetm.sched.md_finish) (sched_dump, sched_verbose);
+
   /* Debug info.  */
   if (sched_verbose)
     {
@@ -1833,17 +1838,14 @@ schedule_block (b, rgn_n_insns)
 /* Set_priorities: compute priority of each insn in the block.  */
 
 int
-set_priorities (b)
-     int b;
+set_priorities (head, tail)
+     rtx head, tail;
 {
   rtx insn;
   int n_insn;
 
-  rtx tail;
   rtx prev_head;
-  rtx head;
 
-  get_block_head_tail (b, &head, &tail);
   prev_head = PREV_INSN (head);
 
   if (head == tail && (! INSN_P (head)))
@@ -1888,9 +1890,10 @@ sched_init (dump_file)
                ? stderr : dump_file);
 
   /* Initialize issue_rate.  */
-  issue_rate = ISSUE_RATE;
-
-  split_all_insns (1);
+  if (targetm.sched.issue_rate)
+    issue_rate = (*targetm.sched.issue_rate) ();
+  else
+    issue_rate = 1;
 
   /* We use LUID 0 for the fake insn (UID 0) which holds dependencies for
      pseudos which do not cross calls.  */
@@ -1936,15 +1939,26 @@ sched_init (dump_file)
          determine the correct line number for the first insn of the block.  */
 
       for (b = 0; b < n_basic_blocks; b++)
-       for (line = BLOCK_HEAD (b); line; line = PREV_INSN (line))
-         if (GET_CODE (line) == NOTE && NOTE_LINE_NUMBER (line) > 0)
+       {
+         for (line = BLOCK_HEAD (b); line; line = PREV_INSN (line))
+           if (GET_CODE (line) == NOTE && NOTE_LINE_NUMBER (line) > 0)
+             {
+               line_note_head[b] = line;
+               break;
+             }
+         /* Do a forward search as well, since we won't get to see the first
+            notes in a basic block.  */
+         for (line = BLOCK_HEAD (b); line; line = NEXT_INSN (line))
            {
-             line_note_head[b] = line;
-             break;
+             if (INSN_P (line))
+               break;
+             if (GET_CODE (line) == NOTE && NOTE_LINE_NUMBER (line) > 0)
+               line_note_head[b] = line;
            }
+       }
     }
 
-  /* Find units used in this fuction, for visualization.  */
+  /* Find units used in this function, for visualization.  */
   if (sched_verbose)
     init_target_units ();
 
@@ -1955,11 +1969,13 @@ sched_init (dump_file)
   if (NEXT_INSN (insn) == 0
       || (GET_CODE (insn) != NOTE
          && GET_CODE (insn) != CODE_LABEL
-         /* Don't emit a NOTE if it would end up between an unconditional
-            jump and a BARRIER.  */
-         && !(GET_CODE (insn) == JUMP_INSN
-              && GET_CODE (NEXT_INSN (insn)) == BARRIER)))
-    emit_note_after (NOTE_INSN_DELETED, BLOCK_END (n_basic_blocks - 1));
+         /* Don't emit a NOTE if it would end up before a BARRIER.  */
+         && GET_CODE (NEXT_INSN (insn)) != BARRIER))
+    {
+      emit_note_after (NOTE_INSN_DELETED, BLOCK_END (n_basic_blocks - 1));
+      /* Make insn to appear outside BB.  */
+      BLOCK_END (n_basic_blocks - 1) = PREV_INSN (BLOCK_END (n_basic_blocks - 1));
+    }
 
   /* Compute INSN_REG_WEIGHT for all blocks.  We must do this before
      removing death notes.  */