sched-int.h (struct haifa_insn_data): New fields: resolved_deps, inter_tick, queue_index.

2006-03-16  Maxim Kuvyrkov <mkuvyrkov@ispras.ru>

        * sched-int.h (struct haifa_insn_data): New fields: resolved_deps,
	inter_tick, queue_index.
	(struct sched_info): Change signature of init_ready_list field.
	Adjust all initializations.
	(RESOLVED_DEPS): New access macro.
	(ready_add): Remove prototype.
	(try_ready): Add prototype.
	* sched-rgn.c (init_ready_list): Use try_ready.
	(schedule_region): Initialize
	current_sched_info->{sched_max_insns_priority, queue_must_finish_empty}.
	* sched-ebb.c (new_ready): Remove.  Adjust ebb_sched_info.
	(init_ready_list): Use try_ready.
	(schedule_ebb): Initialize current_sched_info->sched_max_insns_priority.
	* lists.c (remove_list_elem): Remove `static'.
	(remove_free_INSN_LIST_elem): New function.
	* rtl.h (remove_list_elem, remove_free_INSN_LIST_elem): Add prototypes.
	* haifa-sched.c (INTER_TICK, QUEUE_INDEX): New macros.
	(INVALID_TICK, MIN_TICK, QUEUE_SCHEDULED, QUEUE_NOWHERE, QUEUE_READY):
	New constants.
	(readyp): New variable.
	(queue_remove, ready_remove_insn, fix_inter_tick, fix_tick_ready,
	change_queue_index, resolve_dep): New static functions.
	(try_ready): New function.  Adjust callers in sched-rgn.c and
	sched-ebb.c to use it instead of ready_add.
	(clock_var): Move at the begining of file.
	(rank_for_schedule): Fix typo.
	(queue_insn): Add assertion.  Handle QUEUE_INDEX.
	(ready_lastpos): Enforce assertion.
	(ready_add): Make it static.  Handle QUEUE_INDEX.  Add new argument,
	update all callers.
	(ready_remove_first, ready_remove): Handle QUEUE_INDEX.
	(schedule_insn): Rewrite to use try_ready and resolve_dep.
	(queue_to_ready): Use free_INSN_LIST_list.
	(early_queue_to_ready): Fix typo.
	(schedule_block): Init readyp.  Move init_ready_list call after the
	initialization of clock_var.  Fix error in rejecting insn by
	targetm.sched.dfa_new_cycle.  Add call to fix_inter_tick.  Remove code
	that previously	corrected INSN_TICKs.  Add code for handling
	QUEUE_INDEX.
	(set_priorities): Fix typo.
	(sched_init): Initialize INSN_TICK, INTER_TICK and QUEUE_INDEX.
	Clarify comment and code that keeps current_sched_info->next_tail
	non-null.

From-SVN: r112127
This commit is contained in:
Maxim Kuvyrkov 2006-03-16 05:23:21 +00:00 committed by Maxim Kuvyrkov
parent d08eefb9d2
commit 63f54b1abd
7 changed files with 500 additions and 162 deletions

View File

@ -1,3 +1,49 @@
2006-03-16 Maxim Kuvyrkov <mkuvyrkov@ispras.ru>
* sched-int.h (struct haifa_insn_data): New fields: resolved_deps,
inter_tick, queue_index.
(struct sched_info): Change signature of init_ready_list field.
Adjust all initializations.
(RESOLVED_DEPS): New access macro.
(ready_add): Remove prototype.
(try_ready): Add prototype.
* sched-rgn.c (init_ready_list): Use try_ready.
(schedule_region): Initialize
current_sched_info->{sched_max_insns_priority, queue_must_finish_empty}.
* sched-ebb.c (new_ready): Remove. Adjust ebb_sched_info.
(init_ready_list): Use try_ready.
(schedule_ebb): Initialize current_sched_info->sched_max_insns_priority.
* lists.c (remove_list_elem): Remove `static'.
(remove_free_INSN_LIST_elem): New function.
* rtl.h (remove_list_elem, remove_free_INSN_LIST_elem): Add prototypes.
* haifa-sched.c (INTER_TICK, QUEUE_INDEX): New macros.
(INVALID_TICK, MIN_TICK, QUEUE_SCHEDULED, QUEUE_NOWHERE, QUEUE_READY):
New constants.
(readyp): New variable.
(queue_remove, ready_remove_insn, fix_inter_tick, fix_tick_ready,
change_queue_index, resolve_dep): New static functions.
(try_ready): New function. Adjust callers in sched-rgn.c and
sched-ebb.c to use it instead of ready_add.
(clock_var): Move at the begining of file.
(rank_for_schedule): Fix typo.
(queue_insn): Add assertion. Handle QUEUE_INDEX.
(ready_lastpos): Enforce assertion.
(ready_add): Make it static. Handle QUEUE_INDEX. Add new argument,
update all callers.
(ready_remove_first, ready_remove): Handle QUEUE_INDEX.
(schedule_insn): Rewrite to use try_ready and resolve_dep.
(queue_to_ready): Use free_INSN_LIST_list.
(early_queue_to_ready): Fix typo.
(schedule_block): Init readyp. Move init_ready_list call after the
initialization of clock_var. Fix error in rejecting insn by
targetm.sched.dfa_new_cycle. Add call to fix_inter_tick. Remove code
that previously corrected INSN_TICKs. Add code for handling
QUEUE_INDEX.
(set_priorities): Fix typo.
(sched_init): Initialize INSN_TICK, INTER_TICK and QUEUE_INDEX.
Clarify comment and code that keeps current_sched_info->next_tail
non-null.
2006-03-16 Maxim Kuvyrkov <mkuvyrkov@ispras.ru>
* sched-rgn.c (extend_rgns): New static function.

View File

@ -187,6 +187,13 @@ struct haifa_insn_data *h_i_d;
#define LINE_NOTE(INSN) (h_i_d[INSN_UID (INSN)].line_note)
#define INSN_TICK(INSN) (h_i_d[INSN_UID (INSN)].tick)
#define INTER_TICK(INSN) (h_i_d[INSN_UID (INSN)].inter_tick)
/* If INSN_TICK of an instruction is equal to INVALID_TICK,
then it should be recalculated from scratch. */
#define INVALID_TICK (-(max_insn_queue_index + 1))
/* The minimal value of the INSN_TICK of an instruction. */
#define MIN_TICK (-max_insn_queue_index)
/* Vector indexed by basic block number giving the starting line-number
for each basic block. */
@ -236,7 +243,7 @@ static rtx note_list;
/* Implement a circular buffer to delay instructions until sufficient
time has passed. For the new pipeline description interface,
MAX_INSN_QUEUE_INDEX is a power of two minus one which is larger
MAX_INSN_QUEUE_INDEX is a power of two minus one which is not less
than maximal time of instruction execution computed by genattr.c on
the base maximal time of functional unit reservations and getting a
result. This is the longest time an insn may be queued. */
@ -247,6 +254,17 @@ static int q_size = 0;
#define NEXT_Q(X) (((X)+1) & max_insn_queue_index)
#define NEXT_Q_AFTER(X, C) (((X)+C) & max_insn_queue_index)
#define QUEUE_SCHEDULED (-3)
#define QUEUE_NOWHERE (-2)
#define QUEUE_READY (-1)
/* QUEUE_SCHEDULED - INSN is scheduled.
QUEUE_NOWHERE - INSN isn't scheduled yet and is neither in
queue or ready list.
QUEUE_READY - INSN is in ready list.
N >= 0 - INSN queued for X [where NEXT_Q_AFTER (q_ptr, X) == N] cycles. */
#define QUEUE_INDEX(INSN) (h_i_d[INSN_UID (INSN)].queue_index)
/* The following variable value refers for all current and future
reservations of the processor units. */
state_t curr_state;
@ -275,6 +293,12 @@ struct ready_list
int n_ready;
};
/* The pointer to the ready list. */
static struct ready_list *readyp;
/* Scheduling clock. */
static int clock_var;
static int may_trap_exp (rtx, int);
/* Nonzero iff the address is comprised from at most 1 register. */
@ -442,7 +466,7 @@ static int priority (rtx);
static int rank_for_schedule (const void *, const void *);
static void swap_sort (rtx *, int);
static void queue_insn (rtx, int);
static int schedule_insn (rtx, struct ready_list *, int);
static int schedule_insn (rtx);
static int find_set_reg_weight (rtx);
static void find_insn_reg_weight (int);
static void adjust_priority (rtx);
@ -476,6 +500,7 @@ static rtx unlink_line_notes (rtx, rtx);
static rtx reemit_notes (rtx, rtx);
static rtx *ready_lastpos (struct ready_list *);
static void ready_add (struct ready_list *, rtx, bool);
static void ready_sort (struct ready_list *);
static rtx ready_remove_first (struct ready_list *);
@ -491,10 +516,16 @@ static rtx move_insn (rtx, rtx);
on the first cycle. */
static rtx ready_element (struct ready_list *, int);
static rtx ready_remove (struct ready_list *, int);
static void ready_remove_insn (rtx);
static int max_issue (struct ready_list *, int *);
static rtx choose_ready (struct ready_list *);
static void fix_inter_tick (rtx, rtx);
static int fix_tick_ready (rtx);
static void change_queue_index (rtx, int);
static void resolve_dep (rtx, rtx);
#endif /* INSN_SCHEDULING */
/* Point to state used for the current scheduling pass. */
@ -663,7 +694,7 @@ rank_for_schedule (const void *x, const void *y)
return info_val;
/* Compare insns based on their relation to the last-scheduled-insn. */
if (last_scheduled_insn)
if (INSN_P (last_scheduled_insn))
{
/* Classify the instructions into three classes:
1) Data dependent on last schedule insn.
@ -736,6 +767,9 @@ queue_insn (rtx insn, int n_cycles)
{
int next_q = NEXT_Q_AFTER (q_ptr, n_cycles);
rtx link = alloc_INSN_LIST (insn, insn_queue[next_q]);
gcc_assert (n_cycles <= max_insn_queue_index);
insn_queue[next_q] = link;
q_size += 1;
@ -746,6 +780,18 @@ queue_insn (rtx insn, int n_cycles)
fprintf (sched_dump, "queued for %d cycles.\n", n_cycles);
}
QUEUE_INDEX (insn) = next_q;
}
/* Remove INSN from queue. */
static void
queue_remove (rtx insn)
{
gcc_assert (QUEUE_INDEX (insn) >= 0);
remove_free_INSN_LIST_elem (insn, &insn_queue[QUEUE_INDEX (insn)]);
q_size--;
QUEUE_INDEX (insn) = QUEUE_NOWHERE;
}
/* Return a pointer to the bottom of the ready list, i.e. the insn
@ -754,25 +800,45 @@ queue_insn (rtx insn, int n_cycles)
HAIFA_INLINE static rtx *
ready_lastpos (struct ready_list *ready)
{
gcc_assert (ready->n_ready);
gcc_assert (ready->n_ready >= 1);
return ready->vec + ready->first - ready->n_ready + 1;
}
/* Add an element INSN to the ready list so that it ends up with the lowest
priority. */
/* Add an element INSN to the ready list so that it ends up with the
lowest/highest priority dependending on FIRST_P. */
HAIFA_INLINE void
ready_add (struct ready_list *ready, rtx insn)
HAIFA_INLINE static void
ready_add (struct ready_list *ready, rtx insn, bool first_p)
{
if (ready->first == ready->n_ready)
if (!first_p)
{
memmove (ready->vec + ready->veclen - ready->n_ready,
ready_lastpos (ready),
ready->n_ready * sizeof (rtx));
ready->first = ready->veclen - 1;
if (ready->first == ready->n_ready)
{
memmove (ready->vec + ready->veclen - ready->n_ready,
ready_lastpos (ready),
ready->n_ready * sizeof (rtx));
ready->first = ready->veclen - 1;
}
ready->vec[ready->first - ready->n_ready] = insn;
}
ready->vec[ready->first - ready->n_ready] = insn;
else
{
if (ready->first == ready->veclen - 1)
{
if (ready->n_ready)
/* ready_lastpos() fails when called with (ready->n_ready == 0). */
memmove (ready->vec + ready->veclen - ready->n_ready - 1,
ready_lastpos (ready),
ready->n_ready * sizeof (rtx));
ready->first = ready->veclen - 2;
}
ready->vec[++(ready->first)] = insn;
}
ready->n_ready++;
gcc_assert (QUEUE_INDEX (insn) != QUEUE_READY);
QUEUE_INDEX (insn) = QUEUE_READY;
}
/* Remove the element with the highest priority from the ready list and
@ -789,6 +855,10 @@ ready_remove_first (struct ready_list *ready)
/* If the queue becomes empty, reset it. */
if (ready->n_ready == 0)
ready->first = ready->veclen - 1;
gcc_assert (QUEUE_INDEX (t) == QUEUE_READY);
QUEUE_INDEX (t) = QUEUE_NOWHERE;
return t;
}
@ -825,9 +895,24 @@ ready_remove (struct ready_list *ready, int index)
ready->n_ready--;
for (i = index; i < ready->n_ready; i++)
ready->vec[ready->first - i] = ready->vec[ready->first - i - 1];
QUEUE_INDEX (t) = QUEUE_NOWHERE;
return t;
}
/* Remove INSN from the ready list. */
static void
ready_remove_insn (rtx insn)
{
int i;
for (i = 0; i < readyp->n_ready; i++)
if (ready_element (readyp, i) == insn)
{
ready_remove (readyp, i);
return;
}
gcc_unreachable ();
}
/* Sort the ready list READY by ascending priority, using the SCHED_SORT
macro. */
@ -883,11 +968,10 @@ static int last_clock_var;
zero for insns in a schedule group). */
static int
schedule_insn (rtx insn, struct ready_list *ready, int clock)
schedule_insn (rtx insn)
{
rtx link;
int advance = 0;
int premature_issue = 0;
if (sched_verbose >= 1)
{
@ -895,7 +979,7 @@ schedule_insn (rtx insn, struct ready_list *ready, int clock)
print_insn (buf, insn, 0);
buf[40] = 0;
fprintf (sched_dump, ";;\t%3i--> %-40s:", clock, buf);
fprintf (sched_dump, ";;\t%3i--> %-40s:", clock_var, buf);
if (recog_memoized (insn) < 0)
fprintf (sched_dump, "nothing");
@ -904,52 +988,44 @@ schedule_insn (rtx insn, struct ready_list *ready, int clock)
fputc ('\n', sched_dump);
}
if (INSN_TICK (insn) > clock)
{
/* 'insn' has been prematurely moved from the queue to the
ready list. */
premature_issue = INSN_TICK (insn) - clock;
}
/* Scheduling instruction should have all its dependencies resolved and
should have been removed from the ready list. */
gcc_assert (INSN_DEP_COUNT (insn) == 0);
gcc_assert (!LOG_LINKS (insn));
gcc_assert (QUEUE_INDEX (insn) == QUEUE_NOWHERE);
for (link = INSN_DEPEND (insn); link != 0; link = XEXP (link, 1))
QUEUE_INDEX (insn) = QUEUE_SCHEDULED;
/* Now we can free RESOLVED_DEPS list. */
if (current_sched_info->flags & USE_DEPS_LIST)
free_DEPS_LIST_list (&RESOLVED_DEPS (insn));
else
free_INSN_LIST_list (&RESOLVED_DEPS (insn));
gcc_assert (INSN_TICK (insn) >= MIN_TICK);
if (INSN_TICK (insn) > clock_var)
/* INSN has been prematurely moved from the queue to the ready list.
This is possible only if following flag is set. */
gcc_assert (flag_sched_stalled_insns);
/* ??? Probably, if INSN is scheduled prematurely, we should leave
INSN_TICK untouched. This is a machine-dependent issue, actually. */
INSN_TICK (insn) = clock_var;
/* Update dependent instructions. */
for (link = INSN_DEPEND (insn); link; link = XEXP (link, 1))
{
int effective_cost;
rtx next = XEXP (link, 0);
int cost = insn_cost (insn, link, next);
INSN_TICK (next) = MAX (INSN_TICK (next), clock + cost + premature_issue);
resolve_dep (next, insn);
if ((INSN_DEP_COUNT (next) -= 1) == 0)
{
int effective_cost = INSN_TICK (next) - clock;
if (! (*current_sched_info->new_ready) (next))
continue;
if (sched_verbose >= 2)
{
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");
else
fprintf (sched_dump, "into queue with cost=%d\n",
effective_cost);
}
/* Adjust the priority of NEXT and either put it on the ready
list or queue it. */
adjust_priority (next);
if (effective_cost < 1)
ready_add (ready, next);
else
{
queue_insn (next, effective_cost);
if (SCHED_GROUP_P (next) && advance < effective_cost)
advance = effective_cost;
}
}
effective_cost = try_ready (next);
if (effective_cost >= 0
&& SCHED_GROUP_P (next)
&& advance < effective_cost)
advance = effective_cost;
}
/* Annotate the instruction with issue information -- TImode
@ -962,9 +1038,10 @@ schedule_insn (rtx insn, struct ready_list *ready, int clock)
&& GET_CODE (PATTERN (insn)) != CLOBBER)
{
if (reload_completed)
PUT_MODE (insn, clock > last_clock_var ? TImode : VOIDmode);
last_clock_var = clock;
PUT_MODE (insn, clock_var > last_clock_var ? TImode : VOIDmode);
last_clock_var = clock_var;
}
return advance;
}
@ -1354,9 +1431,6 @@ find_insn_reg_weight (int b)
}
}
/* Scheduling clock, modified in schedule_block() and queue_to_ready (). */
static int clock_var;
/* Move insns that became ready to fire from queue to ready list. */
static void
@ -1378,11 +1452,11 @@ queue_to_ready (struct ready_list *ready)
fprintf (sched_dump, ";;\t\tQ-->Ready: insn %s: ",
(*current_sched_info->print_insn) (insn, 0));
ready_add (ready, insn);
ready_add (ready, insn, false);
if (sched_verbose >= 2)
fprintf (sched_dump, "moving to ready without stalls\n");
}
insn_queue[q_ptr] = 0;
free_INSN_LIST_list (&insn_queue[q_ptr]);
/* If there are no ready insns, stall until one is ready and add all
of the pending insns at that point to the ready list. */
@ -1403,11 +1477,11 @@ queue_to_ready (struct ready_list *ready)
fprintf (sched_dump, ";;\t\tQ-->Ready: insn %s: ",
(*current_sched_info->print_insn) (insn, 0));
ready_add (ready, insn);
ready_add (ready, insn, false);
if (sched_verbose >= 2)
fprintf (sched_dump, "moving to ready with %d stalls\n", stalls);
}
insn_queue[NEXT_Q_AFTER (q_ptr, stalls)] = 0;
free_INSN_LIST_list (&insn_queue[NEXT_Q_AFTER (q_ptr, stalls)]);
advance_one_cycle ();
@ -1542,7 +1616,7 @@ early_queue_to_ready (state_t state, struct ready_list *ready)
{
/* move from Q to R */
q_size -= 1;
ready_add (ready, insn);
ready_add (ready, insn, false);
if (prev_link)
XEXP (prev_link, 1) = next_link;
@ -1557,7 +1631,8 @@ early_queue_to_ready (state_t state, struct ready_list *ready)
insns_removed++;
if (insns_removed == flag_sched_stalled_insns)
/* Remove only one insn from Q at a time. */
/* Remove no more than flag_sched_stalled_insns insns
from Q at a time. */
return insns_removed;
}
}
@ -1872,6 +1947,7 @@ schedule_block (int b, int rgn_n_insns)
state_reset (curr_state);
/* Allocate the ready list. */
readyp = &ready;
ready.veclen = rgn_n_insns + 1 + issue_rate;
ready.first = ready.veclen - 1;
ready.vec = XNEWVEC (rtx, ready.veclen);
@ -1884,8 +1960,6 @@ schedule_block (int b, int rgn_n_insns)
for (i = 0; i <= rgn_n_insns; i++)
choice_stack[i].state = xmalloc (dfa_state_size);
(*current_sched_info->init_ready_list) (&ready);
if (targetm.sched.md_init)
targetm.sched.md_init (sched_dump, sched_verbose, ready.veclen);
@ -1899,10 +1973,16 @@ schedule_block (int b, int rgn_n_insns)
insn_queue = alloca ((max_insn_queue_index + 1) * sizeof (rtx));
memset (insn_queue, 0, (max_insn_queue_index + 1) * sizeof (rtx));
last_clock_var = -1;
/* Start just before the beginning of time. */
clock_var = -1;
/* We need queue and ready lists and clock_var be initialized
in try_ready () (which is called through init_ready_list ()). */
(*current_sched_info->init_ready_list) ();
last_clock_var = -1;
advance = 0;
sort_p = TRUE;
@ -2002,9 +2082,20 @@ schedule_block (int b, int rgn_n_insns)
&& targetm.sched.dfa_new_cycle (sched_dump, sched_verbose,
insn, last_clock_var,
clock_var, &sort_p))
/* SORT_P is used by the target to override sorting
of the ready list. This is needed when the target
has modified its internal structures expecting that
the insn will be issued next. As we need the insn
to have the highest priority (so it will be returned by
the ready_remove_first call above), we invoke
ready_add (&ready, insn, true).
But, still, there is one issue: INSN can be later
discarded by scheduler's front end through
current_sched_info->can_schedule_ready_p, hence, won't
be issued next. */
{
ready_add (&ready, insn);
break;
ready_add (&ready, insn, true);
break;
}
sort_p = TRUE;
@ -2051,8 +2142,10 @@ schedule_block (int b, int rgn_n_insns)
last_scheduled_insn = move_insn (insn, last_scheduled_insn);
if (memcmp (curr_state, temp_state, dfa_state_size) != 0)
cycle_issued_insns++;
memcpy (curr_state, temp_state, dfa_state_size);
{
cycle_issued_insns++;
memcpy (curr_state, temp_state, dfa_state_size);
}
if (targetm.sched.variable_issue)
can_issue_more =
@ -2064,7 +2157,7 @@ schedule_block (int b, int rgn_n_insns)
&& GET_CODE (PATTERN (insn)) != CLOBBER)
can_issue_more--;
advance = schedule_insn (insn, &ready, clock_var);
advance = schedule_insn (insn);
/* After issuing an asm insn we should start a new cycle. */
if (advance == 0 && asm_p)
@ -2094,9 +2187,6 @@ schedule_block (int b, int rgn_n_insns)
}
}
if (targetm.sched.md_finish)
targetm.sched.md_finish (sched_dump, sched_verbose);
/* Debug info. */
if (sched_verbose)
{
@ -2104,17 +2194,24 @@ schedule_block (int b, int rgn_n_insns)
debug_ready_list (&ready);
}
/* Sanity check -- queue must be empty now. Meaningless if region has
multiple bbs. */
gcc_assert (!current_sched_info->queue_must_finish_empty || !q_size);
/* Update head/tail boundaries. */
head = NEXT_INSN (prev_head);
tail = last_scheduled_insn;
if (!reload_completed)
if (current_sched_info->queue_must_finish_empty)
/* Sanity check -- queue must be empty now. Meaningless if region has
multiple bbs. */
gcc_assert (!q_size && !ready.n_ready);
else
{
rtx insn, link, next;
/* We must maintain QUEUE_INDEX between blocks in region. */
for (i = ready.n_ready - 1; i >= 0; i--)
QUEUE_INDEX (ready_element (&ready, i)) = QUEUE_NOWHERE;
if (q_size)
for (i = 0; i <= max_insn_queue_index; i++)
{
rtx link;
for (link = insn_queue[i]; link; link = XEXP (link, 1))
QUEUE_INDEX (XEXP (link, 0)) = QUEUE_NOWHERE;
free_INSN_LIST_list (&insn_queue[i]);
}
/* INSN_TICK (minimum clock tick at which the insn becomes
ready) may be not correct for the insn in the subsequent
@ -2122,17 +2219,16 @@ schedule_block (int b, int rgn_n_insns)
`clock_var' or modify INSN_TICK. It is better to keep
clock_var value equal to 0 at the start of a basic block.
Therefore we modify INSN_TICK here. */
for (insn = head; insn != tail; insn = NEXT_INSN (insn))
if (INSN_P (insn))
{
for (link = INSN_DEPEND (insn); link != 0; link = XEXP (link, 1))
{
next = XEXP (link, 0);
INSN_TICK (next) -= clock_var;
}
}
fix_inter_tick (NEXT_INSN (prev_head), last_scheduled_insn);
}
if (targetm.sched.md_finish)
targetm.sched.md_finish (sched_dump, sched_verbose);
/* Update head/tail boundaries. */
head = NEXT_INSN (prev_head);
tail = last_scheduled_insn;
/* Restore-other-notes: NOTE_LIST is the end of a chain of notes
previously found among the insns. Insert them at the beginning
of the insns. */
@ -2183,16 +2279,15 @@ set_priorities (rtx head, rtx tail)
current_sched_info->sched_max_insns_priority;
rtx prev_head;
prev_head = PREV_INSN (head);
if (head == tail && (! INSN_P (head)))
return 0;
n_insn = 0;
sched_max_insns_priority = 0;
prev_head = PREV_INSN (head);
for (insn = tail; insn != prev_head; insn = PREV_INSN (insn))
{
if (NOTE_P (insn))
if (!INSN_P (insn))
continue;
n_insn++;
@ -2202,9 +2297,8 @@ set_priorities (rtx head, rtx tail)
sched_max_insns_priority =
MAX (sched_max_insns_priority, INSN_PRIORITY (insn));
}
sched_max_insns_priority += 1;
current_sched_info->sched_max_insns_priority =
sched_max_insns_priority;
current_sched_info->sched_max_insns_priority = sched_max_insns_priority;
return n_insn;
}
@ -2253,7 +2347,12 @@ sched_init (void)
h_i_d = XCNEWVEC (struct haifa_insn_data, old_max_uid);
for (i = 0; i < old_max_uid; i++)
h_i_d [i].cost = -1;
{
h_i_d[i].cost = -1;
h_i_d[i].queue_index = QUEUE_NOWHERE;
h_i_d[i].tick = INVALID_TICK;
h_i_d[i].inter_tick = INVALID_TICK;
}
if (targetm.sched.init_dfa_pre_cycle_insn)
targetm.sched.init_dfa_pre_cycle_insn ();
@ -2320,8 +2419,7 @@ sched_init (void)
}
}
/* ??? Add a NOTE after the last insn of the last basic block. It is not
known why this is done. */
/* The following is done to keep current_sched_info->next_tail non null. */
insn = BB_END (EXIT_BLOCK_PTR->prev_bb);
if (NEXT_INSN (insn) == 0
@ -2330,9 +2428,9 @@ sched_init (void)
/* Don't emit a NOTE if it would end up before a BARRIER. */
&& !BARRIER_P (NEXT_INSN (insn))))
{
emit_note_after (NOTE_INSN_DELETED, BB_END (EXIT_BLOCK_PTR->prev_bb));
emit_note_after (NOTE_INSN_DELETED, insn);
/* Make insn to appear outside BB. */
BB_END (EXIT_BLOCK_PTR->prev_bb) = PREV_INSN (BB_END (EXIT_BLOCK_PTR->prev_bb));
BB_END (EXIT_BLOCK_PTR->prev_bb) = insn;
}
/* Compute INSN_REG_WEIGHT for all blocks. We must do this before
@ -2362,4 +2460,208 @@ sched_finish (void)
current_sched_info = NULL;
}
/* Fix INSN_TICKs of the instructions in the current block as well as
INSN_TICKs of their dependants.
HEAD and TAIL are the begin and the end of the current scheduled block. */
static void
fix_inter_tick (rtx head, rtx tail)
{
/* Set of instructions with corrected INSN_TICK. */
bitmap_head processed;
int next_clock = clock_var + 1;
bitmap_initialize (&processed, 0);
/* Iterates over scheduled instructions and fix their INSN_TICKs and
INSN_TICKs of dependent instructions, so that INSN_TICKs are consistent
across different blocks. */
for (tail = NEXT_INSN (tail); head != tail; head = NEXT_INSN (head))
{
if (INSN_P (head))
{
int tick;
rtx link;
tick = INSN_TICK (head);
gcc_assert (tick >= MIN_TICK);
/* Fix INSN_TICK of instruction from just scheduled block. */
if (!bitmap_bit_p (&processed, INSN_LUID (head)))
{
bitmap_set_bit (&processed, INSN_LUID (head));
tick -= next_clock;
if (tick < MIN_TICK)
tick = MIN_TICK;
INSN_TICK (head) = tick;
}
for (link = INSN_DEPEND (head); link; link = XEXP (link, 1))
{
rtx next;
next = XEXP (link, 0);
tick = INSN_TICK (next);
if (tick != INVALID_TICK
/* If NEXT has its INSN_TICK calculated, fix it.
If not - it will be properly calculated from
scratch later in fix_tick_ready. */
&& !bitmap_bit_p (&processed, INSN_LUID (next)))
{
bitmap_set_bit (&processed, INSN_LUID (next));
tick -= next_clock;
if (tick < MIN_TICK)
tick = MIN_TICK;
if (tick > INTER_TICK (next))
INTER_TICK (next) = tick;
else
tick = INTER_TICK (next);
INSN_TICK (next) = tick;
}
}
}
}
bitmap_clear (&processed);
}
/* Check if NEXT is ready to be added to the ready or queue list.
If "yes", add it to the proper list.
Returns:
-1 - is not ready yet,
0 - added to the ready list,
0 < N - queued for N cycles. */
int
try_ready (rtx next)
{
if (LOG_LINKS (next)
|| (current_sched_info->new_ready
&& !current_sched_info->new_ready (next)))
{
gcc_assert (QUEUE_INDEX (next) == QUEUE_NOWHERE);
return -1;
}
if (sched_verbose >= 2)
fprintf (sched_dump, ";;\t\tdependencies resolved: insn %s\n",
(*current_sched_info->print_insn) (next, 0));
adjust_priority (next);
return fix_tick_ready (next);
}
/* Calculate INSN_TICK of NEXT and add it to either ready or queue list. */
static int
fix_tick_ready (rtx next)
{
rtx link;
int tick, delay;
link = RESOLVED_DEPS (next);
if (link)
{
int full_p;
tick = INSN_TICK (next);
/* if tick is note equals to INVALID_TICK, then update
INSN_TICK of NEXT with the most recent resolved dependence
cost. Overwise, recalculate from scratch. */
full_p = tick == INVALID_TICK;
do
{
rtx pro;
int tick1;
pro = XEXP (link, 0);
gcc_assert (INSN_TICK (pro) >= MIN_TICK);
/* We should specify FORWARD link to insn_cost,
but are giving a BACKWARD one.
This is ok, because only REG_NOTE_KIND of link is used.
May be substitute LINK with REG_NOTE_KIND? */
tick1 = INSN_TICK (pro) + insn_cost (pro, link, next);
if (tick1 > tick)
tick = tick1;
}
while ((link = XEXP (link, 1)) && full_p);
}
else
tick = -1;
INSN_TICK (next) = tick;
delay = tick - clock_var;
if (delay <= 0)
delay = QUEUE_READY;
change_queue_index (next, delay);
return delay;
}
/* Move NEXT to the proper queue list with (DELAY >= 1),
or add it to the ready list (DELAY == QUEUE_READY),
or remove it from ready and queue lists at all (DELAY == QUEUE_NOWHERE). */
static void
change_queue_index (rtx next, int delay)
{
int i = QUEUE_INDEX (next);
gcc_assert (QUEUE_NOWHERE <= delay && delay <= max_insn_queue_index
&& delay != 0);
gcc_assert (i != QUEUE_SCHEDULED);
if ((delay > 0 && NEXT_Q_AFTER (q_ptr, delay) == i)
|| (delay < 0 && delay == i))
/* We have nothing to do. */
return;
/* Remove NEXT from whereever it is now. */
if (i == QUEUE_READY)
ready_remove_insn (next);
else if (i >= 0)
queue_remove (next);
/* Add it to the proper place. */
if (delay == QUEUE_READY)
ready_add (readyp, next, false);
else if (delay >= 1)
queue_insn (next, delay);
if (sched_verbose >= 2)
{
fprintf (sched_dump, ";;\t\ttick updated: insn %s",
(*current_sched_info->print_insn) (next, 0));
if (delay == QUEUE_READY)
fprintf (sched_dump, " into ready\n");
else if (delay >= 1)
fprintf (sched_dump, " into queue with cost=%d\n", delay);
else
fprintf (sched_dump, " removed from ready or queue lists\n");
}
}
/* INSN is being scheduled. Resolve the dependence between INSN and NEXT. */
static void
resolve_dep (rtx next, rtx insn)
{
rtx dep;
INSN_DEP_COUNT (next)--;
dep = remove_list_elem (insn, &LOG_LINKS (next));
XEXP (dep, 1) = RESOLVED_DEPS (next);
RESOLVED_DEPS (next) = dep;
gcc_assert ((INSN_DEP_COUNT (next) != 0 || !LOG_LINKS (next))
&& (LOG_LINKS (next) || INSN_DEP_COUNT (next) == 0));
}
#endif /* INSN_SCHEDULING */

View File

@ -98,7 +98,7 @@ remove_list_node (rtx *listp)
/* Removes corresponding to ELEM node from the list pointed to by LISTP.
Returns that node. */
static rtx
rtx
remove_list_elem (rtx elem, rtx *listp)
{
rtx node;
@ -241,4 +241,12 @@ remove_free_DEPS_LIST_elem (rtx elem, rtx *listp)
free_DEPS_LIST_node (remove_list_elem (elem, listp));
}
/* Remove and free corresponding to ELEM node in the INSN_LIST pointed to
by LISTP. */
void
remove_free_INSN_LIST_elem (rtx elem, rtx *listp)
{
free_INSN_LIST_node (remove_list_elem (elem, listp));
}
#include "gt-lists.h"

View File

@ -1756,6 +1756,8 @@ rtx alloc_EXPR_LIST (int, rtx, rtx);
void free_DEPS_LIST_list (rtx *);
rtx alloc_DEPS_LIST (rtx, rtx, HOST_WIDE_INT);
void remove_free_DEPS_LIST_elem (rtx, rtx *);
void remove_free_INSN_LIST_elem (rtx, rtx *);
rtx remove_list_elem (rtx, rtx *);
/* regclass.c */

View File

@ -49,9 +49,8 @@ static int target_n_insns;
static int sched_n_insns;
/* Implementations of the sched_info functions for region scheduling. */
static void init_ready_list (struct ready_list *);
static void init_ready_list (void);
static int can_schedule_ready_p (rtx);
static int new_ready (rtx);
static int schedule_more_p (void);
static const char *ebb_print_insn (rtx, int);
static int rank (rtx, rtx);
@ -76,7 +75,7 @@ schedule_more_p (void)
once before scheduling a set of insns. */
static void
init_ready_list (struct ready_list *ready)
init_ready_list (void)
{
rtx prev_head = current_sched_info->prev_head;
rtx next_tail = current_sched_info->next_tail;
@ -95,8 +94,7 @@ init_ready_list (struct ready_list *ready)
Count number of insns in the target block being scheduled. */
for (insn = NEXT_INSN (prev_head); insn != next_tail; insn = NEXT_INSN (insn))
{
if (INSN_DEP_COUNT (insn) == 0)
ready_add (ready, insn);
try_ready (insn);
target_n_insns++;
}
}
@ -111,15 +109,6 @@ can_schedule_ready_p (rtx insn ATTRIBUTE_UNUSED)
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 (rtx next ATTRIBUTE_UNUSED)
{
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
@ -197,7 +186,7 @@ static struct sched_info ebb_sched_info =
init_ready_list,
can_schedule_ready_p,
schedule_more_p,
new_ready,
NULL,
rank,
ebb_print_insn,
contributes_to_priority,
@ -524,7 +513,9 @@ schedule_ebb (rtx head, rtx tail)
targetm.sched.dependencies_evaluation_hook (head, tail);
/* Set priorities. */
current_sched_info->sched_max_insns_priority = 0;
n_insns = set_priorities (head, tail);
current_sched_info->sched_max_insns_priority++;
current_sched_info->prev_head = PREV_INSN (head);
current_sched_info->next_tail = NEXT_INSN (tail);

View File

@ -142,7 +142,7 @@ 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) (struct ready_list *);
void (*init_ready_list) (void);
/* 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) (rtx);
@ -203,6 +203,10 @@ struct haifa_insn_data
it represents forward dependencies. */
rtx depend;
/* A list of scheduled producers of the instruction. Links are being moved
from LOG_LINKS to RESOLVED_DEPS during scheduling. */
rtx resolved_deps;
/* The line number note in effect for each insn. For line number
notes, this indicates whether the note may be reused. */
rtx line_note;
@ -225,6 +229,13 @@ struct haifa_insn_data
used to note timing constraints for the insns in the pending list. */
int tick;
/* INTER_TICK is used to adjust INSN_TICKs of instructions from the
subsequent blocks in a region. */
int inter_tick;
/* See comment on QUEUE_INDEX macro in haifa-sched.c. */
int queue_index;
short cost;
/* This weight is an estimation of the insn's contribution to
@ -252,6 +263,7 @@ extern struct haifa_insn_data *h_i_d;
/* Accessor macros for h_i_d. There are more in haifa-sched.c and
sched-rgn.c. */
#define INSN_DEPEND(INSN) (h_i_d[INSN_UID (INSN)].depend)
#define RESOLVED_DEPS(INSN) (h_i_d[INSN_UID (INSN)].resolved_deps)
#define INSN_LUID(INSN) (h_i_d[INSN_UID (INSN)].luid)
#define CANT_MOVE(insn) (h_i_d[INSN_UID (insn)].cant_move)
#define INSN_DEP_COUNT(INSN) (h_i_d[INSN_UID (INSN)].dep_count)
@ -513,6 +525,6 @@ extern void schedule_block (int, int);
extern void sched_init (void);
extern void sched_finish (void);
extern void ready_add (struct ready_list *, rtx);
extern int try_ready (rtx);
#endif /* GCC_SCHED_INT_H */

View File

@ -1884,7 +1884,7 @@ static int sched_n_insns;
static int last_was_jump;
/* Implementations of the sched_info functions for region scheduling. */
static void init_ready_list (struct ready_list *);
static void init_ready_list (void);
static int can_schedule_ready_p (rtx);
static int new_ready (rtx);
static int schedule_more_p (void);
@ -1905,7 +1905,7 @@ schedule_more_p (void)
once before scheduling a set of insns. */
static void
init_ready_list (struct ready_list *ready)
init_ready_list (void)
{
rtx prev_head = current_sched_info->prev_head;
rtx next_tail = current_sched_info->next_tail;
@ -1943,15 +1943,8 @@ init_ready_list (struct ready_list *ready)
/* 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))
{
if (INSN_DEP_COUNT (insn) == 0)
{
ready_add (ready, insn);
if (targetm.sched.adjust_priority)
INSN_PRIORITY (insn) =
targetm.sched.adjust_priority (insn, INSN_PRIORITY (insn));
}
{
try_ready (insn);
target_n_insns++;
}
@ -1970,26 +1963,8 @@ init_ready_list (struct ready_list *ready)
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)
|| ((recog_memoized (insn) < 0
|| min_insn_conflict_delay (curr_state,
insn, insn) <= 3)
&& check_live (insn, bb_src)
&& is_exception_free (insn, bb_src, target_bb))))
if (INSN_DEP_COUNT (insn) == 0)
{
ready_add (ready, insn);
if (targetm.sched.adjust_priority)
INSN_PRIORITY (insn) =
targetm.sched.adjust_priority (insn, INSN_PRIORITY (insn));
}
}
if (INSN_P (insn))
try_ready (insn);
}
}
@ -2638,6 +2613,7 @@ schedule_region (int rgn)
}
/* Set priorities. */
current_sched_info->sched_max_insns_priority = 0;
for (bb = 0; bb < current_nr_blocks; bb++)
{
rtx head, tail;
@ -2645,6 +2621,7 @@ schedule_region (int rgn)
rgn_n_insns += set_priorities (head, tail);
}
current_sched_info->sched_max_insns_priority++;
/* Compute interblock info: probabilities, split-edges, dominators, etc. */
if (current_nr_blocks > 1)
@ -2727,8 +2704,8 @@ schedule_region (int rgn)
target_bb = bb;
current_sched_info->queue_must_finish_empty
= current_nr_blocks > 1 && !flag_schedule_interblock;
gcc_assert (flag_schedule_interblock || current_nr_blocks == 1);
current_sched_info->queue_must_finish_empty = current_nr_blocks == 1;
schedule_block (b, rgn_n_insns);
sched_rgn_n_insns += sched_n_insns;