This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the EGCS project.
haifa clocking change
- To: gcc-patches@egcs.cygnus.com
- Subject: haifa clocking change
- From: Richard Henderson <rth@cygnus.com>
- Date: Tue, 20 Jul 1999 18:22:21 -0700
This is something that I experimented with back at the end of March
or so, and is needed by one of Jan's pentium scheduling changes.
First, by basing freedom on 0 rather than 1, we get to describe
when instructions can really dual issue and when they can't.
Second, MD_SCHED_REORDER is given enough information to decide if for
some reason we can't issue *any* instructions this cycle, despite having
free instructions on the ready list. This comes up on pentium where
paired instructions issue and retire in lock-step. Thus if a long(er)
latency instruction pairs with a short latency instruction, no new
insn can issue to the short pipe before the long insn completes.
Third, there was a redundant sort before the loop. Removing it
kills some ugliness in the sparc backend.
r~
* haifa-sched.c (insn_cost): FREE implies cost 0 and vice versa.
(adjust_priority): Always call ADJUST_PRIORITY.
(schedule_insn): Only put insns into the ready at cost 0.
(schedule_block): Remove redundant initial sort. Give clock_var
and can_issue_more to MD_SCHED_REORDER. Requeue if hazard cost
is not 0.
* tm.texi (MD_SCHED_REORDER): Update docs.
* sparc.h (MD_SCHED_REORDER): Update. Set CAN_ISSUE_MORE.
* sparc.c (ultra_reorder_called_this_block): Delete.
(ultrasparc_sched_init): Don't set it.
(ultrasparc_sched_reorder): Don't check it.
Index: tm.texi
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/tm.texi,v
retrieving revision 1.78
diff -c -p -d -r1.78 tm.texi
*** tm.texi 1999/06/18 01:03:36 1.78
--- tm.texi 1999/07/21 01:10:10
*************** debug output to. @var{verbose} is the v
*** 7656,7662 ****
@samp{-fsched-verbose-}@var{n}.
@findex MD_SCHED_REORDER
! @item MD_SCHED_REORDER (@var{file}, @var{verbose}, @var{ready}, @var{n_ready})
A C statement which is executed by the @samp{Haifa} scheduler after it
has scheduled the ready list to allow the machine description to reorder
it (for example to combine two small instructions together on
--- 7656,7663 ----
@samp{-fsched-verbose-}@var{n}.
@findex MD_SCHED_REORDER
! @item MD_SCHED_REORDER (@var{file}, @var{verbose}, @var{ready}, @var{n_ready},
! @var{clock}, @var{can_issue_more})
A C statement which is executed by the @samp{Haifa} scheduler after it
has scheduled the ready list to allow the machine description to reorder
it (for example to combine two small instructions together on
*************** provided by @samp{-fsched-verbose-}@var{
*** 7666,7672 ****
the ready list of instructions that are ready to be scheduled.
@var{n_ready} is the number of elements in the ready list. The
scheduler reads the ready list in reverse order, starting with
! @var{ready}[@var{n_ready}-1] and going to @var{ready}[0].
@findex MD_SCHED_VARIABLE_ISSUE
@item MD_SCHED_VARIABLE_ISSUE (@var{file}, @var{verbose}, @var{insn}, @var{more})
--- 7667,7676 ----
the ready list of instructions that are ready to be scheduled.
@var{n_ready} is the number of elements in the ready list. The
scheduler reads the ready list in reverse order, starting with
! @var{ready}[@var{n_ready}-1] and going to @var{ready}[0]. @var{clock}
! is the timer tick of the scheduler. @var{can_issue_more} is an output
! parameter that is set to the number of insns that can issue this clock;
! normally this is just @code{issue_rate}.
@findex MD_SCHED_VARIABLE_ISSUE
@item MD_SCHED_VARIABLE_ISSUE (@var{file}, @var{verbose}, @var{insn}, @var{more})
Index: haifa-sched.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/haifa-sched.c,v
retrieving revision 1.89
diff -c -p -d -r1.89 haifa-sched.c
*** haifa-sched.c 1999/06/20 17:29:49 1.89
--- haifa-sched.c 1999/07/21 01:10:11
*************** insn_cost (insn, link, used)
*** 3147,3161 ****
and LINK_COST_ZERO. */
if (LINK_COST_FREE (link))
! cost = 1;
#ifdef ADJUST_COST
else if (!LINK_COST_ZERO (link))
{
int ncost = cost;
ADJUST_COST (used, link, insn, ncost);
! if (ncost <= 1)
! LINK_COST_FREE (link) = ncost = 1;
if (cost == ncost)
LINK_COST_ZERO (link) = 1;
cost = ncost;
--- 3147,3164 ----
and LINK_COST_ZERO. */
if (LINK_COST_FREE (link))
! cost = 0;
#ifdef ADJUST_COST
else if (!LINK_COST_ZERO (link))
{
int ncost = cost;
ADJUST_COST (used, link, insn, ncost);
! if (ncost < 1)
! {
! LINK_COST_FREE (link) = 1;
! ncost = 0;
! }
if (cost == ncost)
LINK_COST_ZERO (link) = 1;
cost = ncost;
*************** adjust_priority (prev)
*** 4362,4371 ****
}
break;
}
#ifdef ADJUST_PRIORITY
! ADJUST_PRIORITY (prev);
#endif
- }
}
/* Clock at which the previous instruction was issued. */
--- 4365,4377 ----
}
break;
}
+ }
+
+ /* That said, a target might have it's own reasons for adjusting
+ priority after reload. */
#ifdef ADJUST_PRIORITY
! ADJUST_PRIORITY (prev);
#endif
}
/* Clock at which the previous instruction was issued. */
*************** schedule_insn (insn, ready, n_ready, clo
*** 4439,4445 ****
if (current_nr_blocks > 1 && INSN_BB (next) != target_bb)
fprintf (dump, "/b%d ", INSN_BLOCK (next));
! if (effective_cost <= 1)
fprintf (dump, "into ready\n");
else
fprintf (dump, "into queue with cost=%d\n", effective_cost);
--- 4445,4451 ----
if (current_nr_blocks > 1 && INSN_BB (next) != target_bb)
fprintf (dump, "/b%d ", INSN_BLOCK (next));
! if (effective_cost < 1)
fprintf (dump, "into ready\n");
else
fprintf (dump, "into queue with cost=%d\n", effective_cost);
*************** schedule_insn (insn, ready, n_ready, clo
*** 4448,4454 ****
/* Adjust the priority of NEXT and either put it on the ready
list or queue it. */
adjust_priority (next);
! if (effective_cost <= 1)
ready[n_ready++] = next;
else
queue_insn (next, effective_cost);
--- 4454,4460 ----
/* Adjust the priority of NEXT and either put it on the ready
list or queue it. */
adjust_priority (next);
! if (effective_cost < 1)
ready[n_ready++] = next;
else
queue_insn (next, effective_cost);
*************** schedule_block (bb, rgn_n_insns)
*** 6675,6681 ****
/* Local variables. */
rtx insn, last;
rtx *ready;
- int i;
int n_ready = 0;
int can_issue_more;
--- 6681,6686 ----
*************** schedule_block (bb, rgn_n_insns)
*** 6857,6881 ****
/* no insns scheduled in this block yet */
last_scheduled_insn = 0;
- /* Sort the ready list */
- SCHED_SORT (ready, n_ready);
- #ifdef MD_SCHED_REORDER
- MD_SCHED_REORDER (dump, sched_verbose, ready, n_ready);
- #endif
-
- if (sched_verbose >= 2)
- {
- fprintf (dump, ";;\t\tReady list initially: ");
- debug_ready_list (ready, n_ready);
- }
-
/* Q_SIZE is the total number of insns in the queue. */
q_ptr = 0;
q_size = 0;
- clock_var = 0;
last_clock_var = 0;
bzero ((char *) insn_queue, sizeof (insn_queue));
/* We start inserting insns after PREV_HEAD. */
last = prev_head;
--- 6862,6876 ----
/* no insns scheduled in this block yet */
last_scheduled_insn = 0;
/* Q_SIZE is the total number of insns in the queue. */
q_ptr = 0;
q_size = 0;
last_clock_var = 0;
bzero ((char *) insn_queue, sizeof (insn_queue));
+ /* Start just before the beginning of time. */
+ clock_var = -1;
+
/* We start inserting insns after PREV_HEAD. */
last = prev_head;
*************** schedule_block (bb, rgn_n_insns)
*** 6907,6916 ****
debug_ready_list (ready, n_ready);
}
! /* Sort the ready list. */
SCHED_SORT (ready, n_ready);
#ifdef MD_SCHED_REORDER
! MD_SCHED_REORDER (dump, sched_verbose, ready, n_ready);
#endif
if (sched_verbose)
--- 6902,6917 ----
debug_ready_list (ready, n_ready);
}
! /* Sort the ready list based on priority. */
SCHED_SORT (ready, n_ready);
+
+ /* Allow the target to reorder the list, typically for
+ better instruction bundling. */
#ifdef MD_SCHED_REORDER
! MD_SCHED_REORDER (dump, sched_verbose, ready, n_ready, clock_var,
! can_issue_more);
! #else
! can_issue_more = issue_rate;
#endif
if (sched_verbose)
*************** schedule_block (bb, rgn_n_insns)
*** 6919,7028 ****
debug_ready_list (ready, n_ready);
}
! /* Issue insns from ready list.
! It is important to count down from n_ready, because n_ready may change
! as insns are issued. */
! can_issue_more = issue_rate;
! for (i = n_ready - 1; i >= 0 && can_issue_more; i--)
{
! rtx insn = ready[i];
int cost = actual_hazard (insn_unit (insn), insn, clock_var, 0);
! if (cost > 1)
{
queue_insn (insn, cost);
! ready[i] = ready[--n_ready]; /* remove insn from ready list */
}
- else if (cost == 0)
- {
- /* an interblock motion? */
- if (INSN_BB (insn) != target_bb)
- {
- rtx temp;
! if (IS_SPECULATIVE_INSN (insn))
! {
! if (!check_live (insn, INSN_BB (insn)))
! {
! /* speculative motion, live check failed, remove
! insn from ready list */
! ready[i] = ready[--n_ready];
! continue;
! }
! update_live (insn, INSN_BB (insn));
! /* for speculative load, mark insns fed by it. */
! if (IS_LOAD_INSN (insn) || FED_BY_SPEC_LOAD (insn))
! set_spec_fed (insn);
! nr_spec++;
! }
! nr_inter++;
! temp = insn;
! while (SCHED_GROUP_P (temp))
! temp = PREV_INSN (temp);
! /* Update source block boundaries. */
! b1 = INSN_BLOCK (temp);
! if (temp == BLOCK_HEAD (b1)
! && insn == BLOCK_END (b1))
! {
! /* We moved all the insns in the basic block.
! Emit a note after the last insn and update the
! begin/end boundaries to point to the note. */
! emit_note_after (NOTE_INSN_DELETED, insn);
! BLOCK_END (b1) = NEXT_INSN (insn);
! BLOCK_HEAD (b1) = NEXT_INSN (insn);
! }
! else if (insn == BLOCK_END (b1))
! {
! /* We took insns from the end of the basic block,
! so update the end of block boundary so that it
! points to the first insn we did not move. */
! BLOCK_END (b1) = PREV_INSN (temp);
! }
! else if (temp == BLOCK_HEAD (b1))
! {
! /* We took insns from the start of the basic block,
! so update the start of block boundary so that
! it points to the first insn we did not move. */
! BLOCK_HEAD (b1) = NEXT_INSN (insn);
! }
}
! else
{
! /* in block motion */
! sched_target_n_insns++;
}
! last_scheduled_insn = insn;
! last = move_insn (insn, last);
! sched_n_insns++;
#ifdef MD_SCHED_VARIABLE_ISSUE
! MD_SCHED_VARIABLE_ISSUE (dump, sched_verbose, insn, can_issue_more);
#else
! can_issue_more--;
#endif
-
- n_ready = schedule_insn (insn, ready, n_ready, clock_var);
! /* remove insn from ready list */
! ready[i] = ready[--n_ready];
! /* close this block after scheduling its jump */
! if (GET_CODE (last_scheduled_insn) == JUMP_INSN)
! break;
! }
}
! /* debug info */
if (sched_verbose)
! {
! visualize_scheduled_insns (b, clock_var);
! }
}
/* debug info */
--- 6920,7015 ----
debug_ready_list (ready, n_ready);
}
! /* Issue insns from ready list. */
! while (n_ready != 0 && can_issue_more)
{
! /* Select and remove the insn from the ready list. */
! rtx insn = ready[--n_ready];
int cost = actual_hazard (insn_unit (insn), insn, clock_var, 0);
! if (cost >= 1)
{
queue_insn (insn, cost);
! continue;
}
! /* An interblock motion? */
! if (INSN_BB (insn) != target_bb)
! {
! rtx temp;
! if (IS_SPECULATIVE_INSN (insn))
! {
! if (!check_live (insn, INSN_BB (insn)))
! continue;
! update_live (insn, INSN_BB (insn));
! /* For speculative load, mark insns fed by it. */
! if (IS_LOAD_INSN (insn) || FED_BY_SPEC_LOAD (insn))
! set_spec_fed (insn);
! nr_spec++;
! }
! nr_inter++;
! temp = insn;
! while (SCHED_GROUP_P (temp))
! temp = PREV_INSN (temp);
! /* Update source block boundaries. */
! b1 = INSN_BLOCK (temp);
! if (temp == BLOCK_HEAD (b1)
! && insn == BLOCK_END (b1))
! {
! /* We moved all the insns in the basic block.
! Emit a note after the last insn and update the
! begin/end boundaries to point to the note. */
! emit_note_after (NOTE_INSN_DELETED, insn);
! BLOCK_END (b1) = NEXT_INSN (insn);
! BLOCK_HEAD (b1) = NEXT_INSN (insn);
}
! else if (insn == BLOCK_END (b1))
{
! /* We took insns from the end of the basic block,
! so update the end of block boundary so that it
! points to the first insn we did not move. */
! BLOCK_END (b1) = PREV_INSN (temp);
! }
! else if (temp == BLOCK_HEAD (b1))
! {
! /* We took insns from the start of the basic block,
! so update the start of block boundary so that
! it points to the first insn we did not move. */
! BLOCK_HEAD (b1) = NEXT_INSN (insn);
}
+ }
+ else
+ {
+ /* In block motion. */
+ sched_target_n_insns++;
+ }
! last_scheduled_insn = insn;
! last = move_insn (insn, last);
! sched_n_insns++;
#ifdef MD_SCHED_VARIABLE_ISSUE
! MD_SCHED_VARIABLE_ISSUE (dump, sched_verbose, insn,
! can_issue_more);
#else
! can_issue_more--;
#endif
! n_ready = schedule_insn (insn, ready, n_ready, clock_var);
! /* Close this block after scheduling its jump. */
! if (GET_CODE (last_scheduled_insn) == JUMP_INSN)
! break;
}
! /* Debug info. */
if (sched_verbose)
! visualize_scheduled_insns (b, clock_var);
}
/* debug info */
Index: config/sparc/sparc.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/sparc/sparc.c,v
retrieving revision 1.70
diff -c -p -d -r1.70 sparc.c
*** sparc.c 1999/06/21 17:47:40 1.70
--- sparc.c 1999/07/21 01:10:11
*************** ultra_flush_pipeline ()
*** 6879,6886 ****
ultra_pipe.free_slot_mask = 0xf;
}
- static int ultra_reorder_called_this_block;
-
/* Init our data structures for this current block. */
void
ultrasparc_sched_init (dump, sched_verbose)
--- 6879,6884 ----
*************** ultrasparc_sched_init (dump, sched_verbo
*** 6890,6896 ****
bzero ((char *) ultra_pipe_hist, sizeof ultra_pipe_hist);
ultra_cur_hist = 0;
ultra_cycles_elapsed = 0;
- ultra_reorder_called_this_block = 0;
ultra_pipe.free_slot_mask = 0xf;
}
--- 6888,6893 ----
*************** ultrasparc_sched_reorder (dump, sched_ve
*** 6979,6992 ****
{
struct ultrasparc_pipeline_state *up = &ultra_pipe;
int i, this_insn;
-
- /* We get called once unnecessarily per block of insns
- scheduled. */
- if (ultra_reorder_called_this_block == 0)
- {
- ultra_reorder_called_this_block = 1;
- return;
- }
if (sched_verbose)
{
--- 6976,6981 ----
Index: config/sparc/sparc.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/sparc/sparc.h,v
retrieving revision 1.67
diff -c -p -d -r1.67 sparc.h
*** sparc.h 1999/06/21 17:47:41 1.67
--- sparc.h 1999/07/21 01:10:11
*************** extern int ultrasparc_variable_issue ();
*** 2702,2722 ****
if (sparc_cpu == PROCESSOR_ULTRASPARC) \
ultrasparc_sched_init (DUMP, SCHED_VERBOSE)
! #define MD_SCHED_REORDER(DUMP, SCHED_VERBOSE, READY, N_READY) \
if (sparc_cpu == PROCESSOR_ULTRASPARC) \
! ultrasparc_sched_reorder (DUMP, SCHED_VERBOSE, READY, N_READY)
#define MD_SCHED_VARIABLE_ISSUE(DUMP, SCHED_VERBOSE, INSN, CAN_ISSUE_MORE) \
! if (sparc_cpu == PROCESSOR_ULTRASPARC) \
! (CAN_ISSUE_MORE) = ultrasparc_variable_issue (INSN); \
! else \
! (CAN_ISSUE_MORE)--
/* Conditional branches with empty delay slots have a length of two. */
#define ADJUST_INSN_LENGTH(INSN, LENGTH) \
if (GET_CODE (INSN) == CALL_INSN \
|| (GET_CODE (INSN) == JUMP_INSN && ! simplejump_p (insn))) \
! LENGTH += 1; else
/* Control the assembler format that we output. */
--- 2702,2729 ----
if (sparc_cpu == PROCESSOR_ULTRASPARC) \
ultrasparc_sched_init (DUMP, SCHED_VERBOSE)
! #define MD_SCHED_REORDER(DUMP, SCHED_VERBOSE, READY, N_READY, CLOCK, CIM) \
! do { \
if (sparc_cpu == PROCESSOR_ULTRASPARC) \
! ultrasparc_sched_reorder (DUMP, SCHED_VERBOSE, READY, N_READY); \
! CIM = issue_rate; \
! } while (0)
#define MD_SCHED_VARIABLE_ISSUE(DUMP, SCHED_VERBOSE, INSN, CAN_ISSUE_MORE) \
! do { \
! if (sparc_cpu == PROCESSOR_ULTRASPARC) \
! (CAN_ISSUE_MORE) = ultrasparc_variable_issue (INSN); \
! else \
! (CAN_ISSUE_MORE)--; \
! } while (0)
/* Conditional branches with empty delay slots have a length of two. */
#define ADJUST_INSN_LENGTH(INSN, LENGTH) \
+ do { \
if (GET_CODE (INSN) == CALL_INSN \
|| (GET_CODE (INSN) == JUMP_INSN && ! simplejump_p (insn))) \
! LENGTH += 1; \
! } while (0)
/* Control the assembler format that we output. */