Try to separate region-specific code from generic parts in the scheuler.

From-SVN: r37973
This commit is contained in:
Bernd Schmidt 2000-12-03 12:53:49 +00:00 committed by Bernd Schmidt
parent 881bc7db37
commit 1708fd40bb
4 changed files with 529 additions and 322 deletions

View File

@ -1,3 +1,30 @@
2000-12-03 Bernd Schmidt <bernds@redhat.co.uk>
* sched-int.h: New file.
* Makefile.in (haifa-sched.o): Depend on it.
* haifa-sched.c: Include it.
(no_real_insns_p): New function.
(current_sched_info): New static variable.
(__inline, HAIFA_INLINE): Moved to sched-int.h.
(get_block_head_tail): Minor cleanup.
(init_ready_list, can_schedule_ready_p, new_ready, schedule_more_p,
rgn_print_insn, rgn_rank): New functions, broken out of
rank_for_schedule, schedule_insn and schedule_block, where they
are now called through function pointers in current_sched_info.
(queue_insn, schedule_insn, queue_to_ready, debug_ready_list,
print_insn): To display uid and block number, call the print_insn
function pointer in current_schedule_info.
(region_sched_info): New static variable.
(sched_target_n_insns, sched_n_insns, target_n_insns): New global
variables, moved out of schedule_block.
(schedule_block): Return void. All callers changed.
Move some of the setup code into schedule_region. Get head/tail
from current_sched_info, and update it when done.
(schedule_region): Slightly rearranged, some code moved here from
schedule_block. Call no_real_insns_p to avoid doing work for a
block that consists only of notes and labels.
(schedule_insns): Initialize current_sched_info.
2000-12-03 Neil Booth <neilb@earthling.net>
* cppmacro.c (funlike_invocation_p): Re-disable macros enabled

View File

@ -1452,7 +1452,7 @@ alias.o : alias.c $(CONFIG_H) system.h $(RTL_H) flags.h hard-reg-set.h \
regmove.o : regmove.c $(CONFIG_H) system.h $(RTL_H) insn-config.h \
$(RECOG_H) output.h $(REGS_H) hard-reg-set.h flags.h function.h \
$(EXPR_H) insn-flags.h $(BASIC_BLOCK_H) toplev.h
haifa-sched.o : haifa-sched.c $(CONFIG_H) system.h $(RTL_H) \
haifa-sched.o : haifa-sched.c $(CONFIG_H) system.h $(RTL_H) sched-int.h \
$(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h function.h \
$(INSN_ATTR_H) toplev.h $(RECOG_H) except.h
final.o : final.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h intl.h \

View File

@ -170,6 +170,7 @@ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "except.h"
#include "toplev.h"
#include "recog.h"
#include "sched-int.h"
extern char *reg_known_equiv_p;
extern rtx *reg_known_value;
@ -523,7 +524,7 @@ static void swap_sort PARAMS ((rtx *, int));
static void queue_insn PARAMS ((rtx, int));
static void schedule_insn PARAMS ((rtx, struct ready_list *, int));
static void find_insn_reg_weight PARAMS ((int));
static int schedule_block PARAMS ((int, int));
static void schedule_block PARAMS ((int, int));
static char *safe_concat PARAMS ((char *, char *, const char *));
static int insn_issue_delay PARAMS ((rtx));
static void adjust_priority PARAMS ((rtx));
@ -789,6 +790,7 @@ static void rm_redundant_line_notes PARAMS ((void));
static void rm_other_notes PARAMS ((rtx, rtx));
static rtx reemit_notes PARAMS ((rtx, rtx));
static int no_real_insns_p PARAMS ((rtx, rtx));
static void get_block_head_tail PARAMS ((int, rtx *, rtx *));
static void get_bb_head_tail PARAMS ((int, rtx *, rtx *));
@ -829,6 +831,9 @@ static void propagate_deps PARAMS ((int, struct deps *, int));
#endif /* INSN_SCHEDULING */
/* Point to state used for the current scheduling pass. */
struct sched_info *current_sched_info;
#define SIZE_FOR_MODE(X) (GET_MODE_SIZE (GET_MODE (X)))
/* Add ELEM wrapped in an INSN_LIST with reg note kind DEP_TYPE to the
@ -1137,13 +1142,6 @@ schedule_insns (dump_file)
{
}
#else
#ifndef __GNUC__
#define __inline
#endif
#ifndef HAIFA_INLINE
#define HAIFA_INLINE __inline
#endif
/* Computation of memory dependencies. */
@ -4170,7 +4168,7 @@ rank_for_schedule (x, y)
rtx tmp2 = *(const rtx *) x;
rtx link;
int tmp_class, tmp2_class, depend_count1, depend_count2;
int val, priority_val, spec_val, prob_val, weight_val;
int val, priority_val, weight_val, info_val;
/* Prefer insn with higher priority. */
priority_val = INSN_PRIORITY (tmp2) - INSN_PRIORITY (tmp);
@ -4182,24 +4180,9 @@ rank_for_schedule (x, y)
(weight_val = INSN_REG_WEIGHT (tmp) - INSN_REG_WEIGHT (tmp2)))
return (weight_val);
/* Some comparison make sense in interblock scheduling only. */
if (INSN_BB (tmp) != INSN_BB (tmp2))
{
/* Prefer an inblock motion on an interblock motion. */
if ((INSN_BB (tmp2) == target_bb) && (INSN_BB (tmp) != target_bb))
return 1;
if ((INSN_BB (tmp) == target_bb) && (INSN_BB (tmp2) != target_bb))
return -1;
/* Prefer a useful motion on a speculative one. */
if ((spec_val = IS_SPECULATIVE_INSN (tmp) - IS_SPECULATIVE_INSN (tmp2)))
return (spec_val);
/* Prefer a more probable (speculative) insn. */
prob_val = INSN_PROBABILITY (tmp2) - INSN_PROBABILITY (tmp);
if (prob_val)
return (prob_val);
}
info_val = (*current_sched_info->rank) (tmp, tmp2);
if (info_val)
return info_val;
/* Compare insns based on their relation to the last-scheduled-insn. */
if (last_scheduled_insn)
@ -4284,10 +4267,8 @@ queue_insn (insn, n_cycles)
if (sched_verbose >= 2)
{
fprintf (sched_dump, ";;\t\tReady-->Q: insn %d: ", INSN_UID (insn));
if (INSN_BB (insn) != target_bb)
fprintf (sched_dump, "(b%d) ", BLOCK_NUM (insn));
fprintf (sched_dump, ";;\t\tReady-->Q: insn %s: ",
(*current_sched_info->print_insn) (insn, 0));
fprintf (sched_dump, "queued for %d cycles.\n", n_cycles);
}
@ -4420,24 +4401,13 @@ schedule_insn (insn, ready, clock)
{
int effective_cost = INSN_TICK (next) - clock;
/* For speculative insns, before inserting to ready/queue,
check live, exception-free, and issue-delay. */
if (INSN_BB (next) != target_bb
&& (!IS_VALID (INSN_BB (next))
|| CANT_MOVE (next)
|| (IS_SPECULATIVE_INSN (next)
&& (insn_issue_delay (next) > 3
|| !check_live (next, INSN_BB (next))
|| !is_exception_free (next, INSN_BB (next), target_bb)))))
if (! (*current_sched_info->new_ready) (next))
continue;
if (sched_verbose >= 2)
{
fprintf (sched_dump, ";;\t\tdependences resolved: insn %d ",
INSN_UID (next));
if (current_nr_blocks > 1 && INSN_BB (next) != target_bb)
fprintf (sched_dump, "/b%d ", BLOCK_NUM (next));
fprintf (sched_dump, ";;\t\tdependences resolved: insn %s ",
(*current_sched_info->print_insn) (next, 0));
if (effective_cost < 1)
fprintf (sched_dump, "into ready\n");
@ -4549,13 +4519,9 @@ get_block_head_tail (b, headp, tailp)
rtx *headp;
rtx *tailp;
{
rtx head;
rtx tail;
/* HEAD and TAIL delimit the basic block being scheduled. */
head = BLOCK_HEAD (b);
tail = BLOCK_END (b);
rtx head = BLOCK_HEAD (b);
rtx tail = BLOCK_END (b);
/* Don't include any notes or labels at the beginning of the
basic block, or notes at the ends of basic blocks. */
@ -4584,6 +4550,21 @@ get_bb_head_tail (bb, headp, tailp)
get_block_head_tail (BB_TO_BLOCK (bb), headp, tailp);
}
/* Return nonzero if there are no real insns in the range [ HEAD, TAIL ]. */
static int
no_real_insns_p (head, tail)
rtx head, tail;
{
while (head != NEXT_INSN (tail))
{
if (GET_CODE (head) != NOTE && GET_CODE (head) != CODE_LABEL)
return 0;
head = NEXT_INSN (head);
}
return 1;
}
/* Delete line notes from bb. Save them so they can be later restored
(in restore_line_notes ()). */
@ -4878,10 +4859,8 @@ queue_to_ready (ready)
q_size -= 1;
if (sched_verbose >= 2)
fprintf (sched_dump, ";;\t\tQ-->Ready: insn %d: ", INSN_UID (insn));
if (sched_verbose >= 2 && INSN_BB (insn) != target_bb)
fprintf (sched_dump, "(b%d) ", BLOCK_NUM (insn));
fprintf (sched_dump, ";;\t\tQ-->Ready: insn %s: ",
(*current_sched_info->print_insn) (insn, 0));
ready_add (ready, insn);
if (sched_verbose >= 2)
@ -4905,11 +4884,8 @@ queue_to_ready (ready)
q_size -= 1;
if (sched_verbose >= 2)
fprintf (sched_dump, ";;\t\tQ-->Ready: insn %d: ",
INSN_UID (insn));
if (sched_verbose >= 2 && INSN_BB (insn) != target_bb)
fprintf (sched_dump, "(b%d) ", BLOCK_NUM (insn));
fprintf (sched_dump, ";;\t\tQ-->Ready: insn %s: ",
(*current_sched_info->print_insn) (insn, 0));
ready_add (ready, insn);
if (sched_verbose >= 2)
@ -4943,11 +4919,7 @@ debug_ready_list (ready)
p = ready_lastpos (ready);
for (i = 0; i < ready->n_ready; i++)
{
fprintf (sched_dump, " %d", INSN_UID (p[i]));
if (current_nr_blocks > 1 && INSN_BB (p[i]) != target_bb)
fprintf (sched_dump, "/b%d", BLOCK_NUM (p[i]));
}
fprintf (sched_dump, " %s", (*current_sched_info->print_insn) (p[i], 0));
fprintf (sched_dump, "\n");
}
@ -5655,16 +5627,16 @@ print_insn (buf, x, verbose)
case INSN:
print_pattern (t, PATTERN (x), verbose);
if (verbose)
sprintf (buf, "b%d: i% 4d: %s", INSN_BB (x),
INSN_UID (x), t);
sprintf (buf, "%s: %s", (*current_sched_info->print_insn) (x, 1),
t);
else
sprintf (buf, "%-4d %s", INSN_UID (x), t);
break;
case JUMP_INSN:
print_pattern (t, PATTERN (x), verbose);
if (verbose)
sprintf (buf, "b%d: i% 4d: jump %s", INSN_BB (x),
INSN_UID (x), t);
sprintf (buf, "%s: jump %s", (*current_sched_info->print_insn) (x, 1),
t);
else
sprintf (buf, "%-4d %s", INSN_UID (x), t);
break;
@ -5678,8 +5650,7 @@ print_insn (buf, x, verbose)
else
strcpy (t, "call <...>");
if (verbose)
sprintf (buf, "b%d: i% 4d: %s", INSN_BB (insn),
INSN_UID (insn), t);
sprintf (buf, "%s: %s", (*current_sched_info->print_insn) (x, 1), t);
else
sprintf (buf, "%-4d %s", INSN_UID (insn), t);
break;
@ -5819,6 +5790,292 @@ visualize_stall_cycles (b, stalls)
sprintf (visual_tbl + strlen (visual_tbl), "\n");
}
/* The number of insns from the current block scheduled so far. */
static int sched_target_n_insns;
/* The number of insns from the current block to be scheduled in total. */
static int target_n_insns;
/* The number of insns from the entire region scheduled so far. */
static int sched_n_insns;
/* Implementations of the sched_info functions for region scheduling. */
static void init_ready_list PARAMS ((struct ready_list *));
static int can_schedule_ready_p PARAMS ((rtx));
static int new_ready PARAMS ((rtx));
static int schedule_more_p PARAMS ((void));
static const char *rgn_print_insn PARAMS ((rtx, int));
static int rgn_rank PARAMS ((rtx, rtx));
/* Return nonzero if there are more insns that should be scheduled. */
static int
schedule_more_p ()
{
return sched_target_n_insns < target_n_insns;
}
/* Add all insns that are initially ready to the ready list READY. Called
once before scheduling a set of insns. */
static void
init_ready_list (ready)
struct ready_list *ready;
{
rtx prev_head = current_sched_info->prev_head;
rtx next_tail = current_sched_info->next_tail;
int bb_src;
rtx insn;
target_n_insns = 0;
sched_target_n_insns = 0;
sched_n_insns = 0;
/* Print debugging information. */
if (sched_verbose >= 5)
debug_dependencies ();
/* Prepare current target block info. */
if (current_nr_blocks > 1)
{
candidate_table = (candidate *) xmalloc (current_nr_blocks
* sizeof (candidate));
bblst_last = 0;
/* bblst_table holds split blocks and update blocks for each block after
the current one in the region. split blocks and update blocks are
the TO blocks of region edges, so there can be at most rgn_nr_edges
of them. */
bblst_size = (current_nr_blocks - target_bb) * rgn_nr_edges;
bblst_table = (int *) xmalloc (bblst_size * sizeof (int));
bitlst_table_last = 0;
bitlst_table_size = rgn_nr_edges;
bitlst_table = (int *) xmalloc (rgn_nr_edges * sizeof (int));
compute_trg_info (target_bb);
}
/* Initialize ready list with all 'ready' insns in target block.
Count number of insns in the target block being scheduled. */
for (insn = NEXT_INSN (prev_head); insn != next_tail; insn = NEXT_INSN (insn))
{
rtx next;
if (! INSN_P (insn))
continue;
next = NEXT_INSN (insn);
if (INSN_DEP_COUNT (insn) == 0
&& (SCHED_GROUP_P (next) == 0 || ! INSN_P (next)))
ready_add (ready, insn);
if (!(SCHED_GROUP_P (insn)))
target_n_insns++;
}
/* Add to ready list all 'ready' insns in valid source blocks.
For speculative insns, check-live, exception-free, and
issue-delay. */
for (bb_src = target_bb + 1; bb_src < current_nr_blocks; bb_src++)
if (IS_VALID (bb_src))
{
rtx src_head;
rtx src_next_tail;
rtx tail, head;
get_bb_head_tail (bb_src, &head, &tail);
src_next_tail = NEXT_INSN (tail);
src_head = head;
for (insn = src_head; insn != src_next_tail; insn = NEXT_INSN (insn))
{
if (! INSN_P (insn))
continue;
if (!CANT_MOVE (insn)
&& (!IS_SPECULATIVE_INSN (insn)
|| (insn_issue_delay (insn) <= 3
&& check_live (insn, bb_src)
&& is_exception_free (insn, bb_src, target_bb))))
{
rtx next;
/* Note that we havn't squirrled away the notes for
blocks other than the current. So if this is a
speculative insn, NEXT might otherwise be a note. */
next = next_nonnote_insn (insn);
if (INSN_DEP_COUNT (insn) == 0
&& (! next
|| SCHED_GROUP_P (next) == 0
|| ! INSN_P (next)))
ready_add (ready, insn);
}
}
}
}
/* Called after taking INSN from the ready list. Returns nonzero if this
insn can be scheduled, nonzero if we should silently discard it. */
static int
can_schedule_ready_p (insn)
rtx insn;
{
/* An interblock motion? */
if (INSN_BB (insn) != target_bb)
{
rtx temp;
basic_block b1;
if (IS_SPECULATIVE_INSN (insn))
{
if (!check_live (insn, INSN_BB (insn)))
return 0;
update_live (insn, INSN_BB (insn));
/* For speculative load, mark insns fed by it. */
if (IS_LOAD_INSN (insn) || FED_BY_SPEC_LOAD (insn))
set_spec_fed (insn);
nr_spec++;
}
nr_inter++;
/* Find the beginning of the scheduling group. */
/* ??? Ought to update basic block here, but later bits of
schedule_block assumes the original insn block is
still intact. */
temp = insn;
while (SCHED_GROUP_P (temp))
temp = PREV_INSN (temp);
/* Update source block boundaries. */
b1 = BLOCK_FOR_INSN (temp);
if (temp == b1->head && insn == b1->end)
{
/* We moved all the insns in the basic block.
Emit a note after the last insn and update the
begin/end boundaries to point to the note. */
rtx note = emit_note_after (NOTE_INSN_DELETED, insn);
b1->head = note;
b1->end = note;
}
else if (insn == b1->end)
{
/* We took insns from the end of the basic block,
so update the end of block boundary so that it
points to the first insn we did not move. */
b1->end = PREV_INSN (temp);
}
else if (temp == b1->head)
{
/* We took insns from the start of the basic block,
so update the start of block boundary so that
it points to the first insn we did not move. */
b1->head = NEXT_INSN (insn);
}
}
else
{
/* In block motion. */
sched_target_n_insns++;
}
sched_n_insns++;
return 1;
}
/* Called after INSN has all its dependencies resolved. Return nonzero
if it should be moved to the ready list or the queue, or zero if we
should silently discard it. */
static int
new_ready (next)
rtx next;
{
/* For speculative insns, before inserting to ready/queue,
check live, exception-free, and issue-delay. */
if (INSN_BB (next) != target_bb
&& (!IS_VALID (INSN_BB (next))
|| CANT_MOVE (next)
|| (IS_SPECULATIVE_INSN (next)
&& (insn_issue_delay (next) > 3
|| !check_live (next, INSN_BB (next))
|| !is_exception_free (next, INSN_BB (next), target_bb)))))
return 0;
return 1;
}
/* Return a string that contains the insn uid and optionally anything else
necessary to identify this insn in an output. It's valid to use a
static buffer for this. The ALIGNED parameter should cause the string
to be formatted so that multiple output lines will line up nicely. */
static const char *
rgn_print_insn (insn, aligned)
rtx insn;
int aligned;
{
static char tmp[80];
if (aligned)
sprintf (tmp, "b%3d: i%4d", INSN_BB (insn), INSN_UID (insn));
else
{
sprintf (tmp, "%d", INSN_UID (insn));
if (current_nr_blocks > 1 && INSN_BB (insn) != target_bb)
sprintf (tmp, "/b%d ", INSN_BB (insn));
}
return tmp;
}
/* Compare priority of two insns. Return a positive number if the second
insn is to be preferred for scheduling, and a negative one if the first
is to be preferred. Zero if they are equally good. */
static int
rgn_rank (insn1, insn2)
rtx insn1, insn2;
{
/* Some comparison make sense in interblock scheduling only. */
if (INSN_BB (insn1) != INSN_BB (insn2))
{
int spec_val, prob_val;
/* Prefer an inblock motion on an interblock motion. */
if ((INSN_BB (insn2) == target_bb) && (INSN_BB (insn1) != target_bb))
return 1;
if ((INSN_BB (insn1) == target_bb) && (INSN_BB (insn2) != target_bb))
return -1;
/* Prefer a useful motion on a speculative one. */
spec_val = IS_SPECULATIVE_INSN (insn1) - IS_SPECULATIVE_INSN (insn2);
if (spec_val)
return spec_val;
/* Prefer a more probable (speculative) insn. */
prob_val = INSN_PROBABILITY (insn2) - INSN_PROBABILITY (insn1);
if (prob_val)
return prob_val;
}
return 0;
}
/* Used in schedule_insns to initialize current_sched_info for scheduling
regions (or single basic blocks). */
static struct sched_info region_sched_info =
{
init_ready_list,
can_schedule_ready_p,
schedule_more_p,
new_ready,
rgn_rank,
rgn_print_insn,
NULL, NULL,
NULL, NULL,
0
};
/* move_insn1: Remove INSN from insn chain, and link it after LAST insn. */
static rtx
@ -5950,40 +6207,25 @@ group_leader (insn)
}
/* Use forward list scheduling to rearrange insns of block BB in region RGN,
possibly bringing insns from subsequent blocks in the same region.
Return number of insns scheduled. */
possibly bringing insns from subsequent blocks in the same region. */
static int
static void
schedule_block (bb, rgn_n_insns)
int bb;
int rgn_n_insns;
{
/* Local variables. */
rtx insn, last;
rtx last;
struct ready_list ready;
int can_issue_more;
/* Flow block of this bb. */
int b = BB_TO_BLOCK (bb);
/* target_n_insns == number of insns in b before scheduling starts.
sched_target_n_insns == how many of b's insns were scheduled.
sched_n_insns == how many insns were scheduled in b. */
int target_n_insns = 0;
int sched_target_n_insns = 0;
int sched_n_insns = 0;
#define NEED_NOTHING 0
#define NEED_HEAD 1
#define NEED_TAIL 2
int new_needs;
/* Head/tail info for this block. */
rtx prev_head;
rtx next_tail;
rtx head;
rtx tail;
int bb_src;
rtx prev_head = current_sched_info->prev_head;
rtx next_tail = current_sched_info->next_tail;
rtx head = NEXT_INSN (prev_head);
rtx tail = PREV_INSN (next_tail);
/* We used to have code to avoid getting parameters moved from hard
argument registers into pseudos.
@ -5991,42 +6233,9 @@ schedule_block (bb, rgn_n_insns)
However, it was removed when it proved to be of marginal benefit
and caused problems because schedule_block and compute_forward_dependences
had different notions of what the "head" insn was. */
get_bb_head_tail (bb, &head, &tail);
/* rm_other_notes only removes notes which are _inside_ the
block---that is, it won't remove notes before the first real insn
or after the last real insn of the block. So if the first insn
has a REG_SAVE_NOTE which would otherwise be emitted before the
insn, it is redundant with the note before the start of the
block, and so we have to take it out.
FIXME: Probably the same thing should be done with REG_SAVE_NOTEs
referencing NOTE_INSN_SETJMP at the end of the block. */
if (INSN_P (head))
{
rtx note;
for (note = REG_NOTES (head); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_SAVE_NOTE)
{
if (INTVAL (XEXP (note, 0)) != NOTE_INSN_SETJMP)
{
remove_note (head, note);
note = XEXP (note, 1);
remove_note (head, note);
}
else
note = XEXP (note, 1);
}
}
next_tail = NEXT_INSN (tail);
prev_head = PREV_INSN (head);
/* If the only insn left is a NOTE or a CODE_LABEL, then there is no need
to schedule this block. */
if (head == tail && (! INSN_P (head)))
return (sched_n_insns);
abort ();
/* Debug info. */
if (sched_verbose)
@ -6043,35 +6252,6 @@ schedule_block (bb, rgn_n_insns)
init_block_visualization ();
}
/* Remove remaining note insns from the block, save them in
note_list. These notes are restored at the end of
schedule_block (). */
note_list = 0;
rm_other_notes (head, tail);
target_bb = bb;
/* Prepare current target block info. */
if (current_nr_blocks > 1)
{
candidate_table = (candidate *) xmalloc (current_nr_blocks
* sizeof (candidate));
bblst_last = 0;
/* bblst_table holds split blocks and update blocks for each block after
the current one in the region. split blocks and update blocks are
the TO blocks of region edges, so there can be at most rgn_nr_edges
of them. */
bblst_size = (current_nr_blocks - bb) * rgn_nr_edges;
bblst_table = (int *) xmalloc (bblst_size * sizeof (int));
bitlst_table_last = 0;
bitlst_table_size = rgn_nr_edges;
bitlst_table = (int *) xmalloc (rgn_nr_edges * sizeof (int));
compute_trg_info (bb);
}
clear_units ();
/* Allocate the ready list. */
@ -6080,69 +6260,7 @@ schedule_block (bb, rgn_n_insns)
ready.vec = (rtx *) xmalloc (ready.veclen * sizeof (rtx));
ready.n_ready = 0;
/* Print debugging information. */
if (sched_verbose >= 5)
debug_dependencies ();
/* Initialize ready list with all 'ready' insns in target block.
Count number of insns in the target block being scheduled. */
for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
{
rtx next;
if (! INSN_P (insn))
continue;
next = NEXT_INSN (insn);
if (INSN_DEP_COUNT (insn) == 0
&& (SCHED_GROUP_P (next) == 0 || ! INSN_P (next)))
ready_add (&ready, insn);
if (!(SCHED_GROUP_P (insn)))
target_n_insns++;
}
/* Add to ready list all 'ready' insns in valid source blocks.
For speculative insns, check-live, exception-free, and
issue-delay. */
for (bb_src = bb + 1; bb_src < current_nr_blocks; bb_src++)
if (IS_VALID (bb_src))
{
rtx src_head;
rtx src_next_tail;
rtx tail, head;
get_bb_head_tail (bb_src, &head, &tail);
src_next_tail = NEXT_INSN (tail);
src_head = head;
if (head == tail && (! INSN_P (head)))
continue;
for (insn = src_head; insn != src_next_tail; insn = NEXT_INSN (insn))
{
if (! INSN_P (insn))
continue;
if (!CANT_MOVE (insn)
&& (!IS_SPECULATIVE_INSN (insn)
|| (insn_issue_delay (insn) <= 3
&& check_live (insn, bb_src)
&& is_exception_free (insn, bb_src, target_bb))))
{
rtx next;
/* Note that we havn't squirrled away the notes for
blocks other than the current. So if this is a
speculative insn, NEXT might otherwise be a note. */
next = next_nonnote_insn (insn);
if (INSN_DEP_COUNT (insn) == 0
&& (! next
|| SCHED_GROUP_P (next) == 0
|| ! INSN_P (next)))
ready_add (&ready, insn);
}
}
}
(*current_sched_info->init_ready_list) (&ready);
#ifdef MD_SCHED_INIT
MD_SCHED_INIT (sched_dump, sched_verbose);
@ -6151,7 +6269,8 @@ schedule_block (bb, rgn_n_insns)
/* No insns scheduled in this block yet. */
last_scheduled_insn = 0;
/* Q_SIZE is the total number of insns in the queue. */
/* Initialize INSN_QUEUE. Q_SIZE is the total number of insns in the
queue. */
q_ptr = 0;
q_size = 0;
last_clock_var = 0;
@ -6163,14 +6282,8 @@ schedule_block (bb, rgn_n_insns)
/* We start inserting insns after PREV_HEAD. */
last = prev_head;
/* Initialize INSN_QUEUE, LIST and NEW_NEEDS. */
new_needs = (NEXT_INSN (prev_head) == BLOCK_HEAD (b)
? NEED_HEAD : NEED_NOTHING);
if (PREV_INSN (next_tail) == BLOCK_END (b))
new_needs |= NEED_TAIL;
/* Loop until all the insns in BB are scheduled. */
while (sched_target_n_insns < target_n_insns)
while ((*current_sched_info->schedule_more_p) ())
{
clock_var++;
@ -6220,70 +6333,11 @@ schedule_block (bb, rgn_n_insns)
continue;
}
/* An interblock motion? */
if (INSN_BB (insn) != target_bb)
{
rtx temp;
basic_block b1;
if (IS_SPECULATIVE_INSN (insn))
{
if (!check_live (insn, INSN_BB (insn)))
continue;
update_live (insn, INSN_BB (insn));
/* For speculative load, mark insns fed by it. */
if (IS_LOAD_INSN (insn) || FED_BY_SPEC_LOAD (insn))
set_spec_fed (insn);
nr_spec++;
}
nr_inter++;
/* Find the beginning of the scheduling group. */
/* ??? Ought to update basic block here, but later bits of
schedule_block assumes the original insn block is
still intact. */
temp = insn;
while (SCHED_GROUP_P (temp))
temp = PREV_INSN (temp);
/* Update source block boundaries. */
b1 = BLOCK_FOR_INSN (temp);
if (temp == b1->head && insn == b1->end)
{
/* We moved all the insns in the basic block.
Emit a note after the last insn and update the
begin/end boundaries to point to the note. */
rtx note = emit_note_after (NOTE_INSN_DELETED, insn);
b1->head = note;
b1->end = note;
}
else if (insn == b1->end)
{
/* We took insns from the end of the basic block,
so update the end of block boundary so that it
points to the first insn we did not move. */
b1->end = PREV_INSN (temp);
}
else if (temp == b1->head)
{
/* We took insns from the start of the basic block,
so update the start of block boundary so that
it points to the first insn we did not move. */
b1->head = NEXT_INSN (insn);
}
}
else
{
/* In block motion. */
sched_target_n_insns++;
}
if (! (*current_sched_info->can_schedule_ready_p) (insn))
goto next;
last_scheduled_insn = insn;
last = move_insn (insn, last);
sched_n_insns++;
#ifdef MD_SCHED_VARIABLE_ISSUE
MD_SCHED_VARIABLE_ISSUE (sched_dump, sched_verbose, insn,
@ -6294,6 +6348,7 @@ schedule_block (bb, 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;
@ -6314,8 +6369,7 @@ schedule_block (bb, rgn_n_insns)
/* Sanity check -- queue must be empty now. Meaningless if region has
multiple bbs. */
if (current_nr_blocks > 1)
if (!flag_schedule_interblock && q_size != 0)
if (current_sched_info->queue_must_finish_empty && q_size != 0)
abort ();
/* Update head/tail boundaries. */
@ -6341,32 +6395,21 @@ schedule_block (bb, rgn_n_insns)
head = note_head;
}
/* Update target block boundaries. */
if (new_needs & NEED_HEAD)
BLOCK_HEAD (b) = head;
if (new_needs & NEED_TAIL)
BLOCK_END (b) = tail;
/* Debugging. */
if (sched_verbose)
{
fprintf (sched_dump, ";; total time = %d\n;; new basic block head = %d\n",
clock_var, INSN_UID (BLOCK_HEAD (b)));
fprintf (sched_dump, ";; new basic block end = %d\n\n",
INSN_UID (BLOCK_END (b)));
fprintf (sched_dump, ";; total time = %d\n;; new head = %d\n",
clock_var, INSN_UID (head));
fprintf (sched_dump, ";; new tail = %d\n\n",
INSN_UID (tail));
}
/* Clean up. */
if (current_nr_blocks > 1)
{
free (candidate_table);
free (bblst_table);
free (bitlst_table);
}
current_sched_info->head = head;
current_sched_info->tail = tail;
free (ready.vec);
return (sched_n_insns);
return 1;
}
/* Print the bit-set of registers, S, callable from debugger. */
@ -6869,7 +6912,6 @@ set_priorities (bb)
n_insn = 0;
for (insn = tail; insn != prev_head; insn = PREV_INSN (insn))
{
if (GET_CODE (insn) == NOTE)
continue;
@ -6921,17 +6963,9 @@ schedule_region (rgn)
compute_forward_dependences (head, tail);
}
/* Delete line notes and set priorities. */
/* Set priorities. */
for (bb = 0; bb < current_nr_blocks; bb++)
{
if (write_symbols != NO_DEBUG)
{
save_line_notes (bb);
rm_line_notes (bb);
}
rgn_n_insns += set_priorities (bb);
}
rgn_n_insns += set_priorities (bb);
/* Compute interblock info: probabilities, split-edges, dominators, etc. */
if (current_nr_blocks > 1)
@ -6979,7 +7013,79 @@ schedule_region (rgn)
/* Now we can schedule all blocks. */
for (bb = 0; bb < current_nr_blocks; bb++)
sched_rgn_n_insns += schedule_block (bb, rgn_n_insns);
{
rtx head, tail;
int b = BB_TO_BLOCK (bb);
get_block_head_tail (b, &head, &tail);
if (no_real_insns_p (head, tail))
continue;
current_sched_info->prev_head = PREV_INSN (head);
current_sched_info->next_tail = NEXT_INSN (tail);
if (write_symbols != NO_DEBUG)
{
save_line_notes (bb);
rm_line_notes (bb);
}
/* rm_other_notes only removes notes which are _inside_ the
block---that is, it won't remove notes before the first real insn
or after the last real insn of the block. So if the first insn
has a REG_SAVE_NOTE which would otherwise be emitted before the
insn, it is redundant with the note before the start of the
block, and so we have to take it out.
FIXME: Probably the same thing should be done with REG_SAVE_NOTEs
referencing NOTE_INSN_SETJMP at the end of the block. */
if (INSN_P (head))
{
rtx note;
for (note = REG_NOTES (head); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_SAVE_NOTE)
{
if (INTVAL (XEXP (note, 0)) != NOTE_INSN_SETJMP)
{
remove_note (head, note);
note = XEXP (note, 1);
remove_note (head, note);
}
else
note = XEXP (note, 1);
}
}
/* Remove remaining note insns from the block, save them in
note_list. These notes are restored at the end of
schedule_block (). */
note_list = 0;
rm_other_notes (head, tail);
target_bb = bb;
current_sched_info->queue_must_finish_empty
= current_nr_blocks > 1 && !flag_schedule_interblock;
schedule_block (bb, rgn_n_insns);
sched_rgn_n_insns += sched_n_insns;
/* Update target block boundaries. */
if (head == BLOCK_HEAD (b))
BLOCK_HEAD (b) = current_sched_info->head;
if (tail == BLOCK_END (b))
BLOCK_END (b) = current_sched_info->tail;
/* Clean up. */
if (current_nr_blocks > 1)
{
free (candidate_table);
free (bblst_table);
free (bitlst_table);
}
}
/* Sanity check: verify that all region insns were scheduled. */
if (sched_rgn_n_insns != rgn_n_insns)
@ -7240,6 +7346,8 @@ schedule_insns (dump_file)
init_regions ();
current_sched_info = &region_sched_info;
/* Schedule every region in the subroutine. */
for (rgn = 0; rgn < nr_regions; rgn++)
schedule_region (rgn);

72
gcc/sched-int.h Normal file
View File

@ -0,0 +1,72 @@
/* Instruction scheduling pass. This file contains definitions used
internally in the scheduler.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
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.
GNU CC 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
02111-1307, USA. */
/* Forward declaration. */
struct ready_list;
/* This structure holds some state of the current scheduling pass, and
contains some function pointers that abstract out some of the non-generic
functionality from functions such as schedule_block or schedule_insn.
There is one global variable, current_sched_info, which points to the
sched_info structure currently in use. */
struct sched_info
{
/* Add all insns that are initially ready to the ready list. Called once
before scheduling a set of insns. */
void (*init_ready_list) PARAMS ((struct ready_list *));
/* Called after taking an insn from the ready list. Returns nonzero if
this insn can be scheduled, nonzero if we should silently discard it. */
int (*can_schedule_ready_p) PARAMS ((rtx));
/* Return nonzero if there are more insns that should be scheduled. */
int (*schedule_more_p) PARAMS ((void));
/* Called after an insn has all its dependencies resolved. Return nonzero
if it should be moved to the ready list or the queue, or zero if we
should silently discard it. */
int (*new_ready) PARAMS ((rtx));
/* Compare priority of two insns. Return a positive number if the second
insn is to be preferred for scheduling, and a negative one if the first
is to be preferred. Zero if they are equally good. */
int (*rank) PARAMS ((rtx, rtx));
/* Return a string that contains the insn uid and optionally anything else
necessary to identify this insn in an output. It's valid to use a
static buffer for this. The ALIGNED parameter should cause the string
to be formatted so that multiple output lines will line up nicely. */
const char *(*print_insn) PARAMS ((rtx, int));
/* The boundaries of the set of insns to be scheduled. */
rtx prev_head, next_tail;
/* Filled in after the schedule is finished; the first and last scheduled
insns. */
rtx head, tail;
/* If nonzero, enables an additional sanity check in schedule_block. */
int queue_must_finish_empty;
};
#ifndef __GNUC__
#define __inline
#endif
#ifndef HAIFA_INLINE
#define HAIFA_INLINE __inline
#endif