diff options
author | Maxim Kuvyrkov <mkuvyrkov@ispras.ru> | 2006-03-16 05:23:21 +0000 |
---|---|---|
committer | Maxim Kuvyrkov <mkuvyrkov@gcc.gnu.org> | 2006-03-16 05:23:21 +0000 |
commit | 63f54b1abd832e2c6f7938aac2e2c455b23c91b7 (patch) | |
tree | 2406ed9805b60255cb95efc06c870414886a802d /gcc | |
parent | d08eefb9d2cb72e7168d3b790111d6c07ce87a8a (diff) | |
download | gcc-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')
-rw-r--r-- | gcc/ChangeLog | 46 | ||||
-rw-r--r-- | gcc/haifa-sched.c | 524 | ||||
-rw-r--r-- | gcc/lists.c | 10 | ||||
-rw-r--r-- | gcc/rtl.h | 2 | ||||
-rw-r--r-- | gcc/sched-ebb.c | 21 | ||||
-rw-r--r-- | gcc/sched-int.h | 16 | ||||
-rw-r--r-- | gcc/sched-rgn.c | 43 |
7 files changed, 500 insertions, 162 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0b105a722b7..826ea2784b7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,51 @@ 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. (find_rgns): Use it. (gather_region_statistics, print_region_statistics): New static 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 */ diff --git a/gcc/lists.c b/gcc/lists.c index 70f2ee89e01..c9df54a779c 100644 --- a/gcc/lists.c +++ b/gcc/lists.c @@ -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" diff --git a/gcc/rtl.h b/gcc/rtl.h index aa90617fa7a..1ee04fc9382 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -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 */ diff --git a/gcc/sched-ebb.c b/gcc/sched-ebb.c index 2fa454df238..0b2e1bf193d 100644 --- a/gcc/sched-ebb.c +++ b/gcc/sched-ebb.c @@ -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); diff --git a/gcc/sched-int.h b/gcc/sched-int.h index 15f1a3d71d7..17c7f7bfb1e 100644 --- a/gcc/sched-int.h +++ b/gcc/sched-int.h @@ -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 */ diff --git a/gcc/sched-rgn.c b/gcc/sched-rgn.c index 0ee5be81d39..314d72851db 100644 --- a/gcc/sched-rgn.c +++ b/gcc/sched-rgn.c @@ -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; |