summaryrefslogtreecommitdiff
path: root/gcc/haifa-sched.c
diff options
context:
space:
mode:
authorMaxim Kuvyrkov <mkuvyrkov@ispras.ru>2006-03-16 05:23:21 +0000
committerMaxim Kuvyrkov <mkuvyrkov@gcc.gnu.org>2006-03-16 05:23:21 +0000
commit63f54b1abd832e2c6f7938aac2e2c455b23c91b7 (patch)
tree2406ed9805b60255cb95efc06c870414886a802d /gcc/haifa-sched.c
parentd08eefb9d2cb72e7168d3b790111d6c07ce87a8a (diff)
downloadgcc-63f54b1abd832e2c6f7938aac2e2c455b23c91b7.tar.gz
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
Diffstat (limited to 'gcc/haifa-sched.c')
-rw-r--r--gcc/haifa-sched.c524
1 files changed, 413 insertions, 111 deletions
diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c
index 89e1a18bd51..75300b5f17d 100644
--- a/gcc/haifa-sched.c
+++ b/gcc/haifa-sched.c
@@ -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);
-
- if ((INSN_DEP_COUNT (next) -= 1) == 0)
- {
- int effective_cost = INSN_TICK (next) - clock;
+ resolve_dep (next, insn);
- 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 */