/* 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,
#include "toplev.h"
#include "recog.h"
#include "sched-int.h"
+#include "target.h"
#ifdef INSN_SCHEDULING
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.
insn_unit (insn)
rtx insn;
{
- register int unit = INSN_UNIT (insn);
+ int unit = INSN_UNIT (insn);
if (unit == 0)
{
insn_cost (insn, link, used)
rtx insn, link, used;
{
- register int cost = INSN_COST (insn);
+ int cost = INSN_COST (insn);
if (cost == 0)
{
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;
LINK_COST_ZERO (link) = 1;
cost = ncost;
}
-#endif
+
return cost;
}
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
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
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. */
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
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))
{
}
}
-/* 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
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
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
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
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++)
{
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
{
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);
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");
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;
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 ();
/* 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)
{
}
/* 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);
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. */
visualize_scheduled_insns (clock_var);
}
+ if (targetm.sched.md_finish)
+ (*targetm.sched.md_finish) (sched_dump, sched_verbose);
+
/* Debug info. */
if (sched_verbose)
{
/* 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)))
? 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. */
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 ();
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. */