More scheduler infrastructure.
From-SVN: r38381
This commit is contained in:
parent
288c2c9e63
commit
79c2ffde68
10 changed files with 156 additions and 55 deletions
|
@ -1,5 +1,36 @@
|
|||
2000-12-19 Bernd Schmidt <bernds@redhat.co.uk>
|
||||
|
||||
* haifa-sched.c (rm_line_notes): Arguments are now head and tail,
|
||||
not block number. All callers and prototype changed.
|
||||
(set_priorities): Likewise.
|
||||
(save_line_notes): Add head and tail arguments; all callers and
|
||||
prototype changed.
|
||||
(restore_line_notes): Likewise. Don't crash on insns generated
|
||||
during scheduling.
|
||||
(schedule_block): Don't use BLOCK_HEAD/BLOCK_END macros.
|
||||
Call MD_SCHED_INIT with additional argument.
|
||||
When starting a new cycle, emit cycle_display insns if available.
|
||||
Don't stop scheduling when encountering a JUMP_INSN, but add another
|
||||
call to schedule_more_p in the inner loop.
|
||||
Call MD_SCHED_REORDER2 after scheduling an insn.
|
||||
Call MD_SCHED_FINISH once all insns are scheduled.
|
||||
(sched_init): Compensate for the fact that get_block_head_tail
|
||||
doesn't include leading notes.
|
||||
* sched-deps.c (free_deps): Free vectors here.
|
||||
* sched-rgn.c (compute_block_backward_dependencies): Not here.
|
||||
(last_was_jump): New static variable.
|
||||
(schedule_more_p): Test it.
|
||||
(init_ready_list): Initialize it.
|
||||
(can_schedule_ready_p): Set it if we have a JUMP_INSN.
|
||||
|
||||
* config/i386/i386.h (MD_SCHED_INIT): Add new arg.
|
||||
* config/m32r/m32r.h (MD_SCHED_INIT): Add new arg.
|
||||
* config/sparc/sparc.h (MD_SCHED_INIT): Add new arg.
|
||||
|
||||
* md.texi (cycle_display): Document.
|
||||
* tm.texi (MD_SCHED_INIT): Document new arg.
|
||||
(MD_SCHED_FINISH, MD_SCHED_REORDER2): Document.
|
||||
|
||||
* flow.c (ior_reg_cond, nand_reg_cond, not_reg_cond): Rewrite
|
||||
to use different representation. All callers changed.
|
||||
(and_reg_cond): Renamed from nand_reg_cond; caller changed.
|
||||
|
|
|
@ -2462,7 +2462,7 @@ while (0)
|
|||
#define ISSUE_RATE \
|
||||
ix86_issue_rate ()
|
||||
|
||||
#define MD_SCHED_INIT(DUMP, SCHED_VERBOSE) \
|
||||
#define MD_SCHED_INIT(DUMP, SCHED_VERBOSE, MAX_READY) \
|
||||
ix86_sched_init (DUMP, SCHED_VERBOSE)
|
||||
|
||||
#define MD_SCHED_REORDER(DUMP, SCHED_VERBOSE, READY, N_READY, CLOCK, CIM) \
|
||||
|
|
|
@ -1554,7 +1554,8 @@ do { \
|
|||
extern int m32r_sched_odd_word_p;
|
||||
|
||||
/* Hook to run before scheduling a block of insns. */
|
||||
#define MD_SCHED_INIT(STREAM, VERBOSE) m32r_sched_init (STREAM, VERBOSE)
|
||||
#define MD_SCHED_INIT(STREAM, VERBOSE, MAX_READY) \
|
||||
m32r_sched_init (STREAM, VERBOSE)
|
||||
|
||||
/* Hook to reorder the list of ready instructions. */
|
||||
#define MD_SCHED_REORDER(STREAM, VERBOSE, READY, N_READY, CLOCK, CIM) \
|
||||
|
|
|
@ -2897,7 +2897,7 @@ do { \
|
|||
#define ADJUST_COST(INSN,LINK,DEP,COST) \
|
||||
(COST) = sparc_adjust_cost(INSN, LINK, DEP, COST)
|
||||
|
||||
#define MD_SCHED_INIT(DUMP, SCHED_VERBOSE) \
|
||||
#define MD_SCHED_INIT(DUMP, SCHED_VERBOSE, MAX_READY) \
|
||||
if (sparc_cpu == PROCESSOR_ULTRASPARC) \
|
||||
ultrasparc_sched_init (DUMP, SCHED_VERBOSE)
|
||||
|
||||
|
|
|
@ -1163,23 +1163,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 +1197,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 +1215,30 @@ 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 block B 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)
|
||||
restore_line_notes (b, head, tail)
|
||||
int b;
|
||||
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 +1260,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 +1339,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
|
||||
|
@ -1662,7 +1660,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");
|
||||
|
@ -1682,7 +1680,7 @@ schedule_block (b, rgn_n_insns)
|
|||
(*current_sched_info->init_ready_list) (&ready);
|
||||
|
||||
#ifdef MD_SCHED_INIT
|
||||
MD_SCHED_INIT (sched_dump, sched_verbose);
|
||||
MD_SCHED_INIT (sched_dump, sched_verbose, ready.veclen);
|
||||
#endif
|
||||
|
||||
/* No insns scheduled in this block yet. */
|
||||
|
@ -1712,6 +1710,11 @@ schedule_block (b, rgn_n_insns)
|
|||
list. */
|
||||
queue_to_ready (&ready);
|
||||
|
||||
#ifdef HAVE_cycle_display
|
||||
if (HAVE_cycle_display)
|
||||
last = emit_insn_after (gen_cycle_display (GEN_INT (clock_var)), last);
|
||||
#endif
|
||||
|
||||
if (ready.n_ready == 0)
|
||||
abort ();
|
||||
|
||||
|
@ -1740,7 +1743,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);
|
||||
|
@ -1768,9 +1773,14 @@ schedule_block (b, rgn_n_insns)
|
|||
schedule_insn (insn, &ready, clock_var);
|
||||
|
||||
next:
|
||||
/* Close this block after scheduling its jump. */
|
||||
if (GET_CODE (last_scheduled_insn) == JUMP_INSN)
|
||||
break;
|
||||
#ifdef MD_SCHED_REORDER2
|
||||
/* Sort the ready list based on priority. */
|
||||
if (ready.n_ready > 0)
|
||||
ready_sort (&ready);
|
||||
MD_SCHED_REORDER2 (sched_dump, sched_verbose,
|
||||
ready.n_ready ? ready_lastpos (&ready) : NULL,
|
||||
ready.n_ready, clock_var, can_issue_more);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Debug info. */
|
||||
|
@ -1778,6 +1788,10 @@ schedule_block (b, rgn_n_insns)
|
|||
visualize_scheduled_insns (clock_var);
|
||||
}
|
||||
|
||||
#ifdef MD_SCHED_FINISH
|
||||
MD_SCHED_FINISH (sched_dump, sched_verbose);
|
||||
#endif
|
||||
|
||||
/* Debug info. */
|
||||
if (sched_verbose)
|
||||
{
|
||||
|
@ -1833,17 +1847,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)))
|
||||
|
@ -1936,12 +1947,23 @@ 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. */
|
||||
|
|
|
@ -2858,6 +2858,14 @@ A typical @code{conditional_trap} pattern looks like
|
|||
"@dots{}")
|
||||
@end smallexample
|
||||
|
||||
@cindex @code{cycle_display} instruction pattern
|
||||
@item @samp{cycle_display}
|
||||
|
||||
This pattern, if present, will be emitted by the instruction scheduler at
|
||||
the beginning of each new clock cycle. This can be used for annotating the
|
||||
assembler output with cycle counts. Operand 0 is a @code{const_int} that
|
||||
holds the clock cycle.
|
||||
|
||||
@end table
|
||||
|
||||
@node Pattern Ordering
|
||||
|
|
|
@ -1327,6 +1327,9 @@ free_deps (deps)
|
|||
if (deps->reg_last_uses[i])
|
||||
free_INSN_LIST_list (&deps->reg_last_uses[i]);
|
||||
}
|
||||
free (deps->reg_last_clobbers);
|
||||
free (deps->reg_last_sets);
|
||||
free (deps->reg_last_uses);
|
||||
}
|
||||
|
||||
/* If it is profitable to use them, initialize caches for tracking
|
||||
|
|
|
@ -252,14 +252,14 @@ extern void free_dependency_caches PARAMS ((void));
|
|||
extern void get_block_head_tail PARAMS ((int, rtx *, rtx *));
|
||||
extern int no_real_insns_p PARAMS ((rtx, rtx));
|
||||
|
||||
extern void rm_line_notes PARAMS ((int));
|
||||
extern void save_line_notes PARAMS ((int));
|
||||
extern void restore_line_notes PARAMS ((int));
|
||||
extern void rm_line_notes PARAMS ((rtx, rtx));
|
||||
extern void save_line_notes PARAMS ((int, rtx, rtx));
|
||||
extern void restore_line_notes PARAMS ((int, rtx, rtx));
|
||||
extern void rm_redundant_line_notes PARAMS ((void));
|
||||
extern void rm_other_notes PARAMS ((rtx, rtx));
|
||||
|
||||
extern int insn_issue_delay PARAMS ((rtx));
|
||||
extern int set_priorities PARAMS ((int));
|
||||
extern int set_priorities PARAMS ((rtx, rtx));
|
||||
|
||||
extern void schedule_block PARAMS ((int, int));
|
||||
extern void sched_init PARAMS ((FILE *));
|
||||
|
|
|
@ -2032,6 +2032,8 @@ static int sched_target_n_insns;
|
|||
static int target_n_insns;
|
||||
/* The number of insns from the entire region scheduled so far. */
|
||||
static int sched_n_insns;
|
||||
/* Nonzero if the last scheduled insn was a jump. */
|
||||
static int last_was_jump;
|
||||
|
||||
/* Implementations of the sched_info functions for region scheduling. */
|
||||
static void init_ready_list PARAMS ((struct ready_list *));
|
||||
|
@ -2046,7 +2048,7 @@ static int rgn_rank PARAMS ((rtx, rtx));
|
|||
static int
|
||||
schedule_more_p ()
|
||||
{
|
||||
return sched_target_n_insns < target_n_insns;
|
||||
return ! last_was_jump && sched_target_n_insns < target_n_insns;
|
||||
}
|
||||
|
||||
/* Add all insns that are initially ready to the ready list READY. Called
|
||||
|
@ -2064,6 +2066,7 @@ init_ready_list (ready)
|
|||
target_n_insns = 0;
|
||||
sched_target_n_insns = 0;
|
||||
sched_n_insns = 0;
|
||||
last_was_jump = 0;
|
||||
|
||||
/* Print debugging information. */
|
||||
if (sched_verbose >= 5)
|
||||
|
@ -2155,6 +2158,9 @@ static int
|
|||
can_schedule_ready_p (insn)
|
||||
rtx insn;
|
||||
{
|
||||
if (GET_CODE (insn) == JUMP_INSN)
|
||||
last_was_jump = 1;
|
||||
|
||||
/* An interblock motion? */
|
||||
if (INSN_BB (insn) != target_bb)
|
||||
{
|
||||
|
@ -2589,10 +2595,9 @@ compute_block_backward_dependences (bb)
|
|||
/* Free up the INSN_LISTs. */
|
||||
free_deps (&tmp_deps);
|
||||
|
||||
/* Assert that we won't need bb_reg_last_* for this block anymore. */
|
||||
free (bb_deps[bb].reg_last_uses);
|
||||
free (bb_deps[bb].reg_last_sets);
|
||||
free (bb_deps[bb].reg_last_clobbers);
|
||||
/* Assert that we won't need bb_reg_last_* for this block anymore.
|
||||
The vectors we're zeroing out have just been freed by the call to
|
||||
free_deps. */
|
||||
bb_deps[bb].reg_last_uses = 0;
|
||||
bb_deps[bb].reg_last_sets = 0;
|
||||
bb_deps[bb].reg_last_clobbers = 0;
|
||||
|
@ -2726,7 +2731,12 @@ schedule_region (rgn)
|
|||
|
||||
/* Set priorities. */
|
||||
for (bb = 0; bb < current_nr_blocks; bb++)
|
||||
rgn_n_insns += set_priorities (BB_TO_BLOCK (bb));
|
||||
{
|
||||
rtx head, tail;
|
||||
get_block_head_tail (BB_TO_BLOCK (bb), &head, &tail);
|
||||
|
||||
rgn_n_insns += set_priorities (head, tail);
|
||||
}
|
||||
|
||||
/* Compute interblock info: probabilities, split-edges, dominators, etc. */
|
||||
if (current_nr_blocks > 1)
|
||||
|
@ -2788,8 +2798,8 @@ schedule_region (rgn)
|
|||
|
||||
if (write_symbols != NO_DEBUG)
|
||||
{
|
||||
save_line_notes (b);
|
||||
rm_line_notes (b);
|
||||
save_line_notes (b, head, tail);
|
||||
rm_line_notes (head, tail);
|
||||
}
|
||||
|
||||
/* rm_other_notes only removes notes which are _inside_ the
|
||||
|
@ -2855,7 +2865,11 @@ schedule_region (rgn)
|
|||
if (write_symbols != NO_DEBUG)
|
||||
{
|
||||
for (bb = 0; bb < current_nr_blocks; bb++)
|
||||
restore_line_notes (BB_TO_BLOCK (bb));
|
||||
{
|
||||
rtx head, tail;
|
||||
get_block_head_tail (BB_TO_BLOCK (bb), &head, &tail);
|
||||
restore_line_notes (BB_TO_BLOCK (bb), head, tail);
|
||||
}
|
||||
}
|
||||
|
||||
/* Done with this region. */
|
||||
|
|
26
gcc/tm.texi
26
gcc/tm.texi
|
@ -8134,11 +8134,22 @@ A C expression that returns how many instructions can be issued at the
|
|||
same time if the machine is a superscalar machine.
|
||||
|
||||
@findex MD_SCHED_INIT
|
||||
@item MD_SCHED_INIT (@var{file}, @var{verbose})
|
||||
@item MD_SCHED_INIT (@var{file}, @var{verbose}, @var{max_ready})
|
||||
A C statement which is executed by the scheduler at the
|
||||
beginning of each block of instructions that are to be scheduled.
|
||||
@var{file} is either a null pointer, or a stdio stream to write any
|
||||
debug output to. @var{verbose} is the verbose level provided by
|
||||
@samp{-fsched-verbose-}@var{n}. @var{max_ready} is the maximum number
|
||||
of insns in the current scheduling region that can be live at the same
|
||||
time. This can be used to allocate scratch space if it is needed.
|
||||
|
||||
@findex MD_SCHED_FINISH
|
||||
@item MD_SCHED_FINISH (@var{file}, @var{verbose})
|
||||
A C statement which is executed by the scheduler at the end of each block
|
||||
of instructions that are to be scheduled. It can be used to perform
|
||||
cleanup of any actions done by the other scheduling macros.
|
||||
@var{file} is either a null pointer, or a stdio stream to write any
|
||||
debug output to. @var{verbose} is the verbose level provided by
|
||||
@samp{-fsched-verbose-}@var{n}.
|
||||
|
||||
@findex MD_SCHED_REORDER
|
||||
|
@ -8155,7 +8166,18 @@ scheduler reads the ready list in reverse order, starting with
|
|||
@var{ready}[@var{n_ready}-1] and going to @var{ready}[0]. @var{clock}
|
||||
is the timer tick of the scheduler. @var{can_issue_more} is an output
|
||||
parameter that is set to the number of insns that can issue this clock;
|
||||
normally this is just @code{issue_rate}.
|
||||
normally this is just @code{issue_rate}. See also @samp{MD_SCHED_REORDER2}.
|
||||
|
||||
@findex MD_SCHED_REORDER2
|
||||
@item MD_SCHED_REORDER2 (@var{file}, @var{verbose}, @var{ready}, @var{n_ready}, @var{clock}, @var{can_issue_more})
|
||||
Like @samp{MD_SCHED_REORDER}, but called at a different time. While the
|
||||
@samp{MD_SCHED_REORDER} macro is called whenever the scheduler starts a
|
||||
new cycle, this macro is used immediately after @samp{MD_SCHED_VARIABLE_ISSUE}
|
||||
is called; it can reorder the ready list and set @var{can_issue_more} to
|
||||
determine whether there are more insns to be scheduled in the same cycle.
|
||||
Defining this macro can be useful if there are frequent situations where
|
||||
scheduling one insn causes other insns to become ready in the same cycle,
|
||||
these other insns can then be taken into account properly.
|
||||
|
||||
@findex MD_SCHED_VARIABLE_ISSUE
|
||||
@item MD_SCHED_VARIABLE_ISSUE (@var{file}, @var{verbose}, @var{insn}, @var{more})
|
||||
|
|
Loading…
Add table
Reference in a new issue