diff options
Diffstat (limited to 'contrib/gcc/haifa-sched.c')
-rw-r--r-- | contrib/gcc/haifa-sched.c | 890 |
1 files changed, 630 insertions, 260 deletions
diff --git a/contrib/gcc/haifa-sched.c b/contrib/gcc/haifa-sched.c index 5c9ab50..2710132 100644 --- a/contrib/gcc/haifa-sched.c +++ b/contrib/gcc/haifa-sched.c @@ -1,6 +1,6 @@ /* Instruction scheduling pass. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by, and currently maintained by, Jim Wilson (wilson@cygnus.com) @@ -123,8 +123,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA This pass must update information that subsequent passes expect to be correct. Namely: reg_n_refs, reg_n_sets, reg_n_deaths, - reg_n_calls_crossed, and reg_live_length. Also, BLOCK_HEAD, - BLOCK_END. + reg_n_calls_crossed, and reg_live_length. Also, BB_HEAD, BB_END. The information in the line number notes is carefully retained by this pass. Notes that refer to the starting and ending of @@ -134,6 +133,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include "toplev.h" #include "rtl.h" #include "tm_p.h" @@ -187,8 +188,7 @@ static int old_max_uid; of the -fsched-verbose=N option. */ void -fix_sched_param (param, val) - const char *param, *val; +fix_sched_param (const char *param, const char *val) { if (!strcmp (param, "verbose")) sched_verbose_param = atoi (val); @@ -303,24 +303,186 @@ struct ready_list int n_ready; }; +static int may_trap_exp (rtx, int); + +/* Nonzero iff the address is comprised from at most 1 register. */ +#define CONST_BASED_ADDRESS_P(x) \ + (GET_CODE (x) == REG \ + || ((GET_CODE (x) == PLUS || GET_CODE (x) == MINUS \ + || (GET_CODE (x) == LO_SUM)) \ + && (CONSTANT_P (XEXP (x, 0)) \ + || CONSTANT_P (XEXP (x, 1))))) + +/* Returns a class that insn with GET_DEST(insn)=x may belong to, + as found by analyzing insn's expression. */ + +static int +may_trap_exp (rtx x, int is_store) +{ + enum rtx_code code; + + if (x == 0) + return TRAP_FREE; + code = GET_CODE (x); + if (is_store) + { + if (code == MEM && may_trap_p (x)) + return TRAP_RISKY; + else + return TRAP_FREE; + } + if (code == MEM) + { + /* The insn uses memory: a volatile load. */ + if (MEM_VOLATILE_P (x)) + return IRISKY; + /* An exception-free load. */ + if (!may_trap_p (x)) + return IFREE; + /* A load with 1 base register, to be further checked. */ + if (CONST_BASED_ADDRESS_P (XEXP (x, 0))) + return PFREE_CANDIDATE; + /* No info on the load, to be further checked. */ + return PRISKY_CANDIDATE; + } + else + { + const char *fmt; + int i, insn_class = TRAP_FREE; + + /* Neither store nor load, check if it may cause a trap. */ + if (may_trap_p (x)) + return TRAP_RISKY; + /* Recursive step: walk the insn... */ + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + { + int tmp_class = may_trap_exp (XEXP (x, i), is_store); + insn_class = WORST_CLASS (insn_class, tmp_class); + } + else if (fmt[i] == 'E') + { + int j; + for (j = 0; j < XVECLEN (x, i); j++) + { + int tmp_class = may_trap_exp (XVECEXP (x, i, j), is_store); + insn_class = WORST_CLASS (insn_class, tmp_class); + if (insn_class == TRAP_RISKY || insn_class == IRISKY) + break; + } + } + if (insn_class == TRAP_RISKY || insn_class == IRISKY) + break; + } + return insn_class; + } +} + +/* Classifies insn for the purpose of verifying that it can be + moved speculatively, by examining it's patterns, returning: + TRAP_RISKY: store, or risky non-load insn (e.g. division by variable). + TRAP_FREE: non-load insn. + IFREE: load from a globally safe location. + IRISKY: volatile load. + PFREE_CANDIDATE, PRISKY_CANDIDATE: load that need to be checked for + being either PFREE or PRISKY. */ + +int +haifa_classify_insn (rtx insn) +{ + rtx pat = PATTERN (insn); + int tmp_class = TRAP_FREE; + int insn_class = TRAP_FREE; + enum rtx_code code; + + if (GET_CODE (pat) == PARALLEL) + { + int i, len = XVECLEN (pat, 0); + + for (i = len - 1; i >= 0; i--) + { + code = GET_CODE (XVECEXP (pat, 0, i)); + switch (code) + { + case CLOBBER: + /* Test if it is a 'store'. */ + tmp_class = may_trap_exp (XEXP (XVECEXP (pat, 0, i), 0), 1); + break; + case SET: + /* Test if it is a store. */ + tmp_class = may_trap_exp (SET_DEST (XVECEXP (pat, 0, i)), 1); + if (tmp_class == TRAP_RISKY) + break; + /* Test if it is a load. */ + tmp_class + = WORST_CLASS (tmp_class, + may_trap_exp (SET_SRC (XVECEXP (pat, 0, i)), + 0)); + break; + case COND_EXEC: + case TRAP_IF: + tmp_class = TRAP_RISKY; + break; + default: + ; + } + insn_class = WORST_CLASS (insn_class, tmp_class); + if (insn_class == TRAP_RISKY || insn_class == IRISKY) + break; + } + } + else + { + code = GET_CODE (pat); + switch (code) + { + case CLOBBER: + /* Test if it is a 'store'. */ + tmp_class = may_trap_exp (XEXP (pat, 0), 1); + break; + case SET: + /* Test if it is a store. */ + tmp_class = may_trap_exp (SET_DEST (pat), 1); + if (tmp_class == TRAP_RISKY) + break; + /* Test if it is a load. */ + tmp_class = + WORST_CLASS (tmp_class, + may_trap_exp (SET_SRC (pat), 0)); + break; + case COND_EXEC: + case TRAP_IF: + tmp_class = TRAP_RISKY; + break; + default:; + } + insn_class = tmp_class; + } + + return insn_class; +} + /* Forward declarations. */ /* The scheduler using only DFA description should never use the following five functions: */ -static unsigned int blockage_range PARAMS ((int, rtx)); -static void clear_units PARAMS ((void)); -static void schedule_unit PARAMS ((int, rtx, int)); -static int actual_hazard PARAMS ((int, rtx, int, int)); -static int potential_hazard PARAMS ((int, rtx, int)); - -static int priority PARAMS ((rtx)); -static int rank_for_schedule PARAMS ((const PTR, const PTR)); -static void swap_sort PARAMS ((rtx *, int)); -static void queue_insn PARAMS ((rtx, int)); -static void schedule_insn PARAMS ((rtx, struct ready_list *, int)); -static void find_insn_reg_weight PARAMS ((int)); -static void adjust_priority PARAMS ((rtx)); -static void advance_one_cycle PARAMS ((void)); +static unsigned int blockage_range (int, rtx); +static void clear_units (void); +static void schedule_unit (int, rtx, int); +static int actual_hazard (int, rtx, int, int); +static int potential_hazard (int, rtx, int); + +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 find_set_reg_weight (rtx); +static void find_insn_reg_weight (int); +static void adjust_priority (rtx); +static void advance_one_cycle (void); /* Notes handling mechanism: ========================= @@ -345,28 +507,29 @@ static void advance_one_cycle PARAMS ((void)); unlink_other_notes ()). After scheduling the block, these notes are inserted at the beginning of the block (in schedule_block()). */ -static rtx unlink_other_notes PARAMS ((rtx, rtx)); -static rtx unlink_line_notes PARAMS ((rtx, rtx)); -static rtx reemit_notes PARAMS ((rtx, rtx)); +static rtx unlink_other_notes (rtx, rtx); +static rtx unlink_line_notes (rtx, rtx); +static rtx reemit_notes (rtx, rtx); -static rtx *ready_lastpos PARAMS ((struct ready_list *)); -static void ready_sort PARAMS ((struct ready_list *)); -static rtx ready_remove_first PARAMS ((struct ready_list *)); +static rtx *ready_lastpos (struct ready_list *); +static void ready_sort (struct ready_list *); +static rtx ready_remove_first (struct ready_list *); -static void queue_to_ready PARAMS ((struct ready_list *)); +static void queue_to_ready (struct ready_list *); +static int early_queue_to_ready (state_t, struct ready_list *); -static void debug_ready_list PARAMS ((struct ready_list *)); +static void debug_ready_list (struct ready_list *); -static rtx move_insn1 PARAMS ((rtx, rtx)); -static rtx move_insn PARAMS ((rtx, rtx)); +static rtx move_insn1 (rtx, rtx); +static rtx move_insn (rtx, rtx); /* The following functions are used to implement multi-pass scheduling on the first cycle. It is used only for DFA based scheduler. */ -static rtx ready_element PARAMS ((struct ready_list *, int)); -static rtx ready_remove PARAMS ((struct ready_list *, int)); -static int max_issue PARAMS ((struct ready_list *, int *)); +static rtx ready_element (struct ready_list *, int); +static rtx ready_remove (struct ready_list *, int); +static int max_issue (struct ready_list *, int *); -static rtx choose_ready PARAMS ((struct ready_list *)); +static rtx choose_ready (struct ready_list *); #endif /* INSN_SCHEDULING */ @@ -375,8 +538,7 @@ struct sched_info *current_sched_info; #ifndef INSN_SCHEDULING void -schedule_insns (dump_file) - FILE *dump_file ATTRIBUTE_UNUSED; +schedule_insns (FILE *dump_file ATTRIBUTE_UNUSED) { } #else @@ -395,8 +557,7 @@ static rtx last_scheduled_insn; should never use the following function. */ HAIFA_INLINE int -insn_unit (insn) - rtx insn; +insn_unit (rtx insn) { int unit = INSN_UNIT (insn); @@ -434,9 +595,7 @@ insn_unit (insn) function. */ HAIFA_INLINE static unsigned int -blockage_range (unit, insn) - int unit; - rtx insn; +blockage_range (int unit, rtx insn) { unsigned int blockage = INSN_BLOCKAGE (insn); unsigned int range; @@ -489,8 +648,7 @@ static int unit_n_insns[1]; following function. */ rtx -get_unit_last_insn (instance) - int instance; +get_unit_last_insn (int instance) { return unit_last_insn[instance]; } @@ -498,19 +656,18 @@ get_unit_last_insn (instance) /* Reset the function unit state to the null state. */ static void -clear_units () +clear_units (void) { - memset ((char *) unit_last_insn, 0, sizeof (unit_last_insn)); - memset ((char *) unit_tick, 0, sizeof (unit_tick)); - memset ((char *) unit_n_insns, 0, sizeof (unit_n_insns)); + memset (unit_last_insn, 0, sizeof (unit_last_insn)); + memset (unit_tick, 0, sizeof (unit_tick)); + memset (unit_n_insns, 0, sizeof (unit_n_insns)); } /* Return the issue-delay of an insn. The scheduler using only DFA description should never use the following function. */ HAIFA_INLINE int -insn_issue_delay (insn) - rtx insn; +insn_issue_delay (rtx insn) { int i, delay = 0; int unit = insn_unit (insn); @@ -540,9 +697,7 @@ insn_issue_delay (insn) use the following function. */ HAIFA_INLINE int -actual_hazard_this_instance (unit, instance, insn, clock, cost) - int unit, instance, clock, cost; - rtx insn; +actual_hazard_this_instance (int unit, int instance, rtx insn, int clock, int cost) { int tick = unit_tick[instance]; /* Issue time of the last issued insn. */ @@ -577,10 +732,8 @@ actual_hazard_this_instance (unit, instance, insn, clock, cost) at time CLOCK. The scheduler using only DFA description should never use the following function. */ -HAIFA_INLINE static void -schedule_unit (unit, insn, clock) - int unit, clock; - rtx insn; +static void +schedule_unit (int unit, rtx insn, int clock) { int i; @@ -611,10 +764,8 @@ schedule_unit (unit, insn, clock) was COST. The scheduler using only DFA description should never use the following function. */ -HAIFA_INLINE static int -actual_hazard (unit, insn, clock, cost) - int unit, clock, cost; - rtx insn; +static int +actual_hazard (int unit, rtx insn, int clock, int cost) { int i; @@ -663,9 +814,7 @@ actual_hazard (unit, insn, clock, cost) the following function. */ HAIFA_INLINE static int -potential_hazard (unit, insn, cost) - int unit, cost; - rtx insn; +potential_hazard (int unit, rtx insn, int cost) { int i, ncost; unsigned int minb, maxb; @@ -708,8 +857,7 @@ potential_hazard (unit, insn, cost) instruction results. */ HAIFA_INLINE int -insn_cost (insn, link, used) - rtx insn, link, used; +insn_cost (rtx insn, rtx link, rtx used) { int cost = INSN_COST (insn); @@ -731,10 +879,10 @@ insn_cost (insn, link, used) cost = insn_default_latency (insn); else cost = result_ready_cost (insn); - + if (cost < 0) cost = 0; - + INSN_COST (insn) = cost; } } @@ -775,15 +923,14 @@ insn_cost (insn, link, used) if (cost < 0) cost = 0; } - + return cost; } /* Compute the priority number for INSN. */ static int -priority (insn) - rtx insn; +priority (rtx insn) { rtx link; @@ -825,7 +972,7 @@ priority (insn) } /* Macros and functions for keeping the priority queue sorted, and - dealing with queueing and dequeueing of instructions. */ + dealing with queuing and dequeuing of instructions. */ #define SCHED_SORT(READY, N_READY) \ do { if ((N_READY) == 2) \ @@ -839,9 +986,7 @@ while (0) unstable. */ static int -rank_for_schedule (x, y) - const PTR x; - const PTR y; +rank_for_schedule (const void *x, const void *y) { rtx tmp = *(const rtx *) y; rtx tmp2 = *(const rtx *) x; @@ -849,15 +994,20 @@ rank_for_schedule (x, y) int tmp_class, tmp2_class, depend_count1, depend_count2; int val, priority_val, weight_val, info_val; + /* The insn in a schedule group should be issued the first. */ + if (SCHED_GROUP_P (tmp) != SCHED_GROUP_P (tmp2)) + return SCHED_GROUP_P (tmp2) ? 1 : -1; + /* Prefer insn with higher priority. */ priority_val = INSN_PRIORITY (tmp2) - INSN_PRIORITY (tmp); + if (priority_val) return priority_val; /* Prefer an insn with smaller contribution to registers-pressure. */ if (!reload_completed && (weight_val = INSN_REG_WEIGHT (tmp) - INSN_REG_WEIGHT (tmp2))) - return (weight_val); + return weight_val; info_val = (*current_sched_info->rank) (tmp, tmp2); if (info_val) @@ -915,9 +1065,7 @@ rank_for_schedule (x, y) /* Resort the array A in which only element at index N may be out of order. */ HAIFA_INLINE static void -swap_sort (a, n) - rtx *a; - int n; +swap_sort (rtx *a, int n) { rtx insn = a[n - 1]; int i = n - 2; @@ -935,9 +1083,7 @@ swap_sort (a, n) chain for debugging purposes. */ HAIFA_INLINE static void -queue_insn (insn, n_cycles) - rtx insn; - int n_cycles; +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]); @@ -957,8 +1103,7 @@ queue_insn (insn, n_cycles) with the lowest priority. */ HAIFA_INLINE static rtx * -ready_lastpos (ready) - struct ready_list *ready; +ready_lastpos (struct ready_list *ready) { if (ready->n_ready == 0) abort (); @@ -969,9 +1114,7 @@ ready_lastpos (ready) priority. */ HAIFA_INLINE void -ready_add (ready, insn) - struct ready_list *ready; - rtx insn; +ready_add (struct ready_list *ready, rtx insn) { if (ready->first == ready->n_ready) { @@ -988,8 +1131,7 @@ ready_add (ready, insn) return it. */ HAIFA_INLINE static rtx -ready_remove_first (ready) - struct ready_list *ready; +ready_remove_first (struct ready_list *ready) { rtx t; if (ready->n_ready == 0) @@ -1011,12 +1153,12 @@ ready_remove_first (ready) N_READY - 1. */ HAIFA_INLINE static rtx -ready_element (ready, index) - struct ready_list *ready; - int index; +ready_element (struct ready_list *ready, int index) { +#ifdef ENABLE_CHECKING if (ready->n_ready == 0 || index >= ready->n_ready) abort (); +#endif return ready->vec[ready->first - index]; } @@ -1025,9 +1167,7 @@ ready_element (ready, index) has N_READY - 1. */ HAIFA_INLINE static rtx -ready_remove (ready, index) - struct ready_list *ready; - int index; +ready_remove (struct ready_list *ready, int index) { rtx t; int i; @@ -1048,8 +1188,7 @@ ready_remove (ready, index) macro. */ HAIFA_INLINE static void -ready_sort (ready) - struct ready_list *ready; +ready_sort (struct ready_list *ready) { rtx *first = ready_lastpos (ready); SCHED_SORT (first, ready->n_ready); @@ -1060,8 +1199,7 @@ ready_sort (ready) provide a hook for the target to tweek itself. */ HAIFA_INLINE static void -adjust_priority (prev) - rtx prev; +adjust_priority (rtx prev) { /* ??? There used to be code here to try and estimate how an insn affected register lifetimes, but it did it by looking at REG_DEAD @@ -1077,7 +1215,7 @@ adjust_priority (prev) /* Advance time on one cycle. */ HAIFA_INLINE static void -advance_one_cycle () +advance_one_cycle (void) { if (targetm.sched.use_dfa_pipeline_interface && (*targetm.sched.use_dfa_pipeline_interface) ()) @@ -1099,17 +1237,17 @@ static int last_clock_var; /* INSN is the "currently executing insn". Launch each insn which was waiting on INSN. READY is the ready list which contains the insns - that are ready to fire. CLOCK is the current cycle. - */ + that are ready to fire. CLOCK is the current cycle. The function + returns necessary cycle advance after issuing the insn (it is not + zero for insns in a schedule group). */ -static void -schedule_insn (insn, ready, clock) - rtx insn; - struct ready_list *ready; - int clock; +static int +schedule_insn (rtx insn, struct ready_list *ready, int clock) { rtx link; + int advance = 0; int unit = 0; + int premature_issue = 0; if (!targetm.sched.use_dfa_pipeline_interface || !(*targetm.sched.use_dfa_pipeline_interface) ()) @@ -1122,7 +1260,7 @@ schedule_insn (insn, ready, clock) char buf[2048]; print_insn (buf, insn, 0); - buf[40]=0; + buf[40] = 0; fprintf (sched_dump, ";;\t%3i--> %-40s:", clock, buf); if (recog_memoized (insn) < 0) @@ -1148,9 +1286,16 @@ schedule_insn (insn, ready, clock) if (MAX_BLOCKAGE > 1 || issue_rate > 1 || sched_verbose) schedule_unit (unit, insn, clock); - + if (INSN_DEPEND (insn) == 0) - return; + return 0; + } + + if (INSN_TICK (insn) > clock) + { + /* 'insn' has been prematurely moved from the queue to the + ready list. */ + premature_issue = INSN_TICK (insn) - clock; } for (link = INSN_DEPEND (insn); link != 0; link = XEXP (link, 1)) @@ -1158,7 +1303,7 @@ schedule_insn (insn, ready, clock) rtx next = XEXP (link, 0); int cost = insn_cost (insn, link, next); - INSN_TICK (next) = MAX (INSN_TICK (next), clock + cost); + INSN_TICK (next) = MAX (INSN_TICK (next), clock + cost + premature_issue); if ((INSN_DEP_COUNT (next) -= 1) == 0) { @@ -1175,7 +1320,8 @@ schedule_insn (insn, ready, clock) if (effective_cost < 1) fprintf (sched_dump, "into ready\n"); else - fprintf (sched_dump, "into queue with cost=%d\n", effective_cost); + fprintf (sched_dump, "into queue with cost=%d\n", + effective_cost); } /* Adjust the priority of NEXT and either put it on the ready @@ -1184,7 +1330,12 @@ schedule_insn (insn, ready, clock) if (effective_cost < 1) ready_add (ready, next); else - queue_insn (next, effective_cost); + { + queue_insn (next, effective_cost); + + if (SCHED_GROUP_P (next) && advance < effective_cost) + advance = effective_cost; + } } } @@ -1193,13 +1344,15 @@ schedule_insn (insn, ready, clock) to issue on the same cycle as the previous insn. A machine may use this information to decide how the instruction should be aligned. */ - if (reload_completed && issue_rate > 1 + if (issue_rate > 1 && GET_CODE (PATTERN (insn)) != USE && GET_CODE (PATTERN (insn)) != CLOBBER) { - PUT_MODE (insn, clock > last_clock_var ? TImode : VOIDmode); + if (reload_completed) + PUT_MODE (insn, clock > last_clock_var ? TImode : VOIDmode); last_clock_var = clock; } + return advance; } /* Functions for handling of notes. */ @@ -1209,8 +1362,7 @@ schedule_insn (insn, ready, clock) Returns the insn following the notes. */ static rtx -unlink_other_notes (insn, tail) - rtx insn, tail; +unlink_other_notes (rtx insn, rtx tail) { rtx prev = PREV_INSN (insn); @@ -1226,6 +1378,7 @@ unlink_other_notes (insn, tail) /* See sched_analyze to see how these are handled. */ if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END + && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK && NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG && NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_END) { @@ -1245,8 +1398,7 @@ unlink_other_notes (insn, tail) they can be reused. Returns the insn following the notes. */ static rtx -unlink_line_notes (insn, tail) - rtx insn, tail; +unlink_line_notes (rtx insn, rtx tail) { rtx prev = PREV_INSN (insn); @@ -1276,14 +1428,11 @@ unlink_line_notes (insn, tail) /* Return the head and tail pointers of BB. */ void -get_block_head_tail (b, headp, tailp) - int b; - rtx *headp; - rtx *tailp; +get_block_head_tail (int b, rtx *headp, rtx *tailp) { /* HEAD and TAIL delimit the basic block being scheduled. */ - rtx head = BLOCK_HEAD (b); - rtx tail = BLOCK_END (b); + rtx head = BB_HEAD (BASIC_BLOCK (b)); + rtx tail = BB_END (BASIC_BLOCK (b)); /* Don't include any notes or labels at the beginning of the basic block, or notes at the ends of basic blocks. */ @@ -1306,8 +1455,7 @@ get_block_head_tail (b, headp, tailp) /* Return nonzero if there are no real insns in the range [ HEAD, TAIL ]. */ int -no_real_insns_p (head, tail) - rtx head, tail; +no_real_insns_p (rtx head, rtx tail) { while (head != NEXT_INSN (tail)) { @@ -1323,8 +1471,7 @@ no_real_insns_p (head, tail) block in which notes should be processed. */ void -rm_line_notes (head, tail) - rtx head, tail; +rm_line_notes (rtx head, rtx tail) { rtx next_tail; rtx insn; @@ -1356,9 +1503,7 @@ rm_line_notes (head, tail) the boundaries of the block in which notes should be processed. */ void -save_line_notes (b, head, tail) - int b; - rtx head, tail; +save_line_notes (int b, rtx head, rtx tail) { rtx next_tail; @@ -1384,8 +1529,7 @@ save_line_notes (b, head, tail) be processed. */ void -restore_line_notes (head, tail) - rtx head, tail; +restore_line_notes (rtx head, rtx tail) { rtx line, note, prev, new; int added_notes = 0; @@ -1448,7 +1592,7 @@ restore_line_notes (head, tail) insns list. */ void -rm_redundant_line_notes () +rm_redundant_line_notes (void) { rtx line = 0; rtx insn = get_insns (); @@ -1497,9 +1641,7 @@ rm_redundant_line_notes () of notes ended by NOTE_LIST. */ void -rm_other_notes (head, tail) - rtx head; - rtx tail; +rm_other_notes (rtx head, rtx tail) { rtx next_tail; rtx insn; @@ -1534,11 +1676,35 @@ rm_other_notes (head, tail) /* Functions for computation of registers live/usage info. */ +/* This function looks for a new register being defined. + If the destination register is already used by the source, + a new register is not needed. */ + +static int +find_set_reg_weight (rtx x) +{ + if (GET_CODE (x) == CLOBBER + && register_operand (SET_DEST (x), VOIDmode)) + return 1; + if (GET_CODE (x) == SET + && register_operand (SET_DEST (x), VOIDmode)) + { + if (GET_CODE (SET_DEST (x)) == REG) + { + if (!reg_mentioned_p (SET_DEST (x), SET_SRC (x))) + return 1; + else + return 0; + } + return 1; + } + return 0; +} + /* Calculate INSN_REG_WEIGHT for all insns of a block. */ static void -find_insn_reg_weight (b) - int b; +find_insn_reg_weight (int b) { rtx insn, next_tail, head, tail; @@ -1556,21 +1722,16 @@ find_insn_reg_weight (b) /* Increment weight for each register born here. */ x = PATTERN (insn); - if ((GET_CODE (x) == SET || GET_CODE (x) == CLOBBER) - && register_operand (SET_DEST (x), VOIDmode)) - reg_weight++; - else if (GET_CODE (x) == PARALLEL) + reg_weight += find_set_reg_weight (x); + if (GET_CODE (x) == PARALLEL) { int j; for (j = XVECLEN (x, 0) - 1; j >= 0; j--) { x = XVECEXP (PATTERN (insn), 0, j); - if ((GET_CODE (x) == SET || GET_CODE (x) == CLOBBER) - && register_operand (SET_DEST (x), VOIDmode)) - reg_weight++; + reg_weight += find_set_reg_weight (x); } } - /* Decrement weight for each register that dies here. */ for (x = REG_NOTES (insn); x; x = XEXP (x, 1)) { @@ -1589,8 +1750,7 @@ static int clock_var; /* Move insns that became ready to fire from queue to ready list. */ static void -queue_to_ready (ready) - struct ready_list *ready; +queue_to_ready (struct ready_list *ready) { rtx insn; rtx link; @@ -1657,11 +1817,163 @@ queue_to_ready (ready) } } +/* Used by early_queue_to_ready. Determines whether it is "ok" to + prematurely move INSN from the queue to the ready list. Currently, + if a target defines the hook 'is_costly_dependence', this function + uses the hook to check whether there exist any dependences which are + considered costly by the target, between INSN and other insns that + have already been scheduled. Dependences are checked up to Y cycles + back, with default Y=1; The flag -fsched-stalled-insns-dep=Y allows + controlling this value. + (Other considerations could be taken into account instead (or in + addition) depending on user flags and target hooks. */ + +static bool +ok_for_early_queue_removal (rtx insn) +{ + int n_cycles; + rtx prev_insn = last_scheduled_insn; + + if (targetm.sched.is_costly_dependence) + { + for (n_cycles = flag_sched_stalled_insns_dep; n_cycles; n_cycles--) + { + for ( ; prev_insn; prev_insn = PREV_INSN (prev_insn)) + { + rtx dep_link = 0; + int dep_cost; + + if (GET_CODE (prev_insn) != NOTE) + { + dep_link = find_insn_list (insn, INSN_DEPEND (prev_insn)); + if (dep_link) + { + dep_cost = insn_cost (prev_insn, dep_link, insn) ; + if (targetm.sched.is_costly_dependence (prev_insn, insn, + dep_link, dep_cost, + flag_sched_stalled_insns_dep - n_cycles)) + return false; + } + } + + if (GET_MODE (prev_insn) == TImode) /* end of dispatch group */ + break; + } + + if (!prev_insn) + break; + prev_insn = PREV_INSN (prev_insn); + } + } + + return true; +} + + +/* Remove insns from the queue, before they become "ready" with respect + to FU latency considerations. */ + +static int +early_queue_to_ready (state_t state, struct ready_list *ready) +{ + rtx insn; + rtx link; + rtx next_link; + rtx prev_link; + bool move_to_ready; + int cost; + state_t temp_state = alloca (dfa_state_size); + int stalls; + int insns_removed = 0; + + /* + Flag '-fsched-stalled-insns=X' determines the aggressiveness of this + function: + + X == 0: There is no limit on how many queued insns can be removed + prematurely. (flag_sched_stalled_insns = -1). + + X >= 1: Only X queued insns can be removed prematurely in each + invocation. (flag_sched_stalled_insns = X). + + Otherwise: Early queue removal is disabled. + (flag_sched_stalled_insns = 0) + */ + + if (! flag_sched_stalled_insns) + return 0; + + for (stalls = 0; stalls <= MAX_INSN_QUEUE_INDEX; stalls++) + { + if ((link = insn_queue[NEXT_Q_AFTER (q_ptr, stalls)])) + { + if (sched_verbose > 6) + fprintf (sched_dump, ";; look at index %d + %d\n", q_ptr, stalls); + + prev_link = 0; + while (link) + { + next_link = XEXP (link, 1); + insn = XEXP (link, 0); + if (insn && sched_verbose > 6) + print_rtl_single (sched_dump, insn); + + memcpy (temp_state, state, dfa_state_size); + if (recog_memoized (insn) < 0) + /* non-negative to indicate that it's not ready + to avoid infinite Q->R->Q->R... */ + cost = 0; + else + cost = state_transition (temp_state, insn); + + if (sched_verbose >= 6) + fprintf (sched_dump, "transition cost = %d\n", cost); + + move_to_ready = false; + if (cost < 0) + { + move_to_ready = ok_for_early_queue_removal (insn); + if (move_to_ready == true) + { + /* move from Q to R */ + q_size -= 1; + ready_add (ready, insn); + + if (prev_link) + XEXP (prev_link, 1) = next_link; + else + insn_queue[NEXT_Q_AFTER (q_ptr, stalls)] = next_link; + + free_INSN_LIST_node (link); + + if (sched_verbose >= 2) + fprintf (sched_dump, ";;\t\tEarly Q-->Ready: insn %s\n", + (*current_sched_info->print_insn) (insn, 0)); + + insns_removed++; + if (insns_removed == flag_sched_stalled_insns) + /* remove only one insn from Q at a time */ + return insns_removed; + } + } + + if (move_to_ready == false) + prev_link = link; + + link = next_link; + } /* while link */ + } /* if link */ + + } /* for stalls.. */ + + return insns_removed; +} + + /* Print the ready list for debugging purposes. Callable from debugger. */ static void -debug_ready_list (ready) - struct ready_list *ready; +debug_ready_list (struct ready_list *ready) { rtx *p; int i; @@ -1681,8 +1993,7 @@ debug_ready_list (ready) /* move_insn1: Remove INSN from insn chain, and link it after LAST insn. */ static rtx -move_insn1 (insn, last) - rtx insn, last; +move_insn1 (rtx insn, rtx last) { NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn); PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn); @@ -1704,9 +2015,7 @@ move_insn1 (insn, last) output by the instruction scheduler. Return the new value of LAST. */ static rtx -reemit_notes (insn, last) - rtx insn; - rtx last; +reemit_notes (rtx insn, rtx last) { rtx note, retval; @@ -1729,38 +2038,16 @@ reemit_notes (insn, last) return retval; } -/* Move INSN, and all insns which should be issued before it, - due to SCHED_GROUP_P flag. Reemit notes if needed. +/* Move INSN. Reemit notes if needed. Return the last insn emitted by the scheduler, which is the return value from the first call to reemit_notes. */ static rtx -move_insn (insn, last) - rtx insn, last; +move_insn (rtx insn, rtx last) { rtx retval = NULL; - /* If INSN has SCHED_GROUP_P set, then issue it and any other - insns with SCHED_GROUP_P set first. */ - while (SCHED_GROUP_P (insn)) - { - rtx prev = PREV_INSN (insn); - - /* Move a SCHED_GROUP_P insn. */ - move_insn1 (insn, last); - /* If this is the first call to reemit_notes, then record - its return value. */ - if (retval == NULL_RTX) - retval = reemit_notes (insn, insn); - else - reemit_notes (insn, insn); - /* Consume SCHED_GROUP_P flag. */ - SCHED_GROUP_P (insn) = 0; - insn = prev; - } - - /* Now move the first non SCHED_GROUP_P insn. */ move_insn1 (insn, last); /* If this is the first call to reemit_notes, then record @@ -1770,6 +2057,8 @@ move_insn (insn, last) else reemit_notes (insn, insn); + SCHED_GROUP_P (insn) = 0; + return retval; } @@ -1824,9 +2113,7 @@ static int cached_issue_rate = 0; of the best insn in READY. The following function is used only for first cycle multipass scheduling. */ static int -max_issue (ready, index) - struct ready_list *ready; - int *index; +max_issue (struct ready_list *ready, int *index) { int n, i, all, n_ready, best, delay, tries_num; struct choice_entry *top; @@ -1902,8 +2189,7 @@ max_issue (ready, index) cycle multipass scheduling. */ static rtx -choose_ready (ready) - struct ready_list *ready; +choose_ready (struct ready_list *ready) { int lookahead = 0; @@ -1914,7 +2200,7 @@ choose_ready (ready) else { /* Try to choose the better insn. */ - int index, i; + int index = 0, i; rtx insn; if (cached_first_cycle_multipass_dfa_lookahead != lookahead) @@ -1930,7 +2216,10 @@ choose_ready (ready) for (i = 1; i < ready->n_ready; i++) { insn = ready_element (ready, i); - ready_try [i] = INSN_CODE (insn) < 0; + ready_try [i] + = (INSN_CODE (insn) < 0 + || (targetm.sched.first_cycle_multipass_dfa_lookahead_guard + && !(*targetm.sched.first_cycle_multipass_dfa_lookahead_guard) (insn))); } if (max_issue (ready, &index) == 0) return ready_remove_first (ready); @@ -1943,8 +2232,7 @@ choose_ready (ready) the instruction stream. */ rtx -sched_emit_insn (pat) - rtx pat; +sched_emit_insn (rtx pat) { rtx insn = emit_insn_after (pat, last_scheduled_insn); last_scheduled_insn = insn; @@ -1955,15 +2243,13 @@ sched_emit_insn (pat) possibly bringing insns from subsequent blocks in the same region. */ void -schedule_block (b, rgn_n_insns) - int b; - int rgn_n_insns; +schedule_block (int b, int rgn_n_insns) { struct ready_list ready; - int i; - int first_cycle_insn_p; + int i, first_cycle_insn_p; int can_issue_more; state_t temp_state = NULL; /* It is used for multipass scheduling. */ + int sort_p, advance, start_clock_var; /* Head/tail info for this block. */ rtx prev_head = current_sched_info->prev_head; @@ -2005,7 +2291,7 @@ schedule_block (b, rgn_n_insns) /* Allocate the ready list. */ ready.veclen = rgn_n_insns + 1 + issue_rate; ready.first = ready.veclen - 1; - ready.vec = (rtx *) xmalloc (ready.veclen * sizeof (rtx)); + ready.vec = xmalloc (ready.veclen * sizeof (rtx)); ready.n_ready = 0; if (targetm.sched.use_dfa_pipeline_interface @@ -2013,13 +2299,11 @@ schedule_block (b, rgn_n_insns) { /* It is used for first cycle multipass scheduling. */ temp_state = alloca (dfa_state_size); - ready_try = (char *) xmalloc ((rgn_n_insns + 1) * sizeof (char)); - memset (ready_try, 0, (rgn_n_insns + 1) * sizeof (char)); - choice_stack - = (struct choice_entry *) xmalloc ((rgn_n_insns + 1) - * sizeof (struct choice_entry)); + ready_try = xcalloc ((rgn_n_insns + 1), sizeof (char)); + choice_stack = xmalloc ((rgn_n_insns + 1) + * sizeof (struct choice_entry)); for (i = 0; i <= rgn_n_insns; i++) - choice_stack[i].state = (state_t) xmalloc (dfa_state_size); + choice_stack[i].state = xmalloc (dfa_state_size); } (*current_sched_info->init_ready_list) (&ready); @@ -2041,41 +2325,61 @@ schedule_block (b, rgn_n_insns) else max_insn_queue_index_macro_value = max_insn_queue_index; - insn_queue = (rtx *) alloca ((MAX_INSN_QUEUE_INDEX + 1) * sizeof (rtx)); - memset ((char *) insn_queue, 0, (MAX_INSN_QUEUE_INDEX + 1) * sizeof (rtx)); + 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; + advance = 0; + sort_p = TRUE; /* Loop until all the insns in BB are scheduled. */ while ((*current_sched_info->schedule_more_p) ()) { - clock_var++; + do + { + start_clock_var = clock_var; - advance_one_cycle (); + clock_var++; - /* Add to the ready list all pending insns that can be issued now. - If there are no ready insns, increment clock until one - is ready and add all pending insns at that point to the ready - list. */ - queue_to_ready (&ready); + advance_one_cycle (); - if (ready.n_ready == 0) - abort (); + /* Add to the ready list all pending insns that can be issued now. + If there are no ready insns, increment clock until one + is ready and add all pending insns at that point to the ready + list. */ + queue_to_ready (&ready); - if (sched_verbose >= 2) - { - fprintf (sched_dump, ";;\t\tReady list after queue_to_ready: "); - debug_ready_list (&ready); + if (ready.n_ready == 0) + abort (); + + if (sched_verbose >= 2) + { + fprintf (sched_dump, ";;\t\tReady list after queue_to_ready: "); + debug_ready_list (&ready); + } + advance -= clock_var - start_clock_var; } + while (advance > 0); - /* Sort the ready list based on priority. */ - ready_sort (&ready); + if (sort_p) + { + /* Sort the ready list based on priority. */ + ready_sort (&ready); + + if (sched_verbose >= 2) + { + fprintf (sched_dump, ";;\t\tReady list after ready_sort: "); + debug_ready_list (&ready); + } + } /* Allow the target to reorder the list, typically for better instruction bundling. */ - if (targetm.sched.reorder) + if (sort_p && targetm.sched.reorder + && (ready.n_ready == 0 + || !SCHED_GROUP_P (ready_element (&ready, 0)))) can_issue_more = (*targetm.sched.reorder) (sched_dump, sched_verbose, ready_lastpos (&ready), @@ -2089,6 +2393,7 @@ schedule_block (b, rgn_n_insns) { rtx insn; int cost; + bool asm_p = false; if (sched_verbose >= 2) { @@ -2103,25 +2408,52 @@ schedule_block (b, rgn_n_insns) if (ready.n_ready == 0 || !can_issue_more || !(*current_sched_info->schedule_more_p) ()) break; - insn = choose_ready (&ready); + insn = ready_remove_first (&ready); cost = actual_hazard (insn_unit (insn), insn, clock_var, 0); } else { + if (ready.n_ready == 0 + && can_issue_more + && reload_completed) + { + /* Allow scheduling insns directly from the queue in case + there's nothing better to do (ready list is empty) but + there are still vacant dispatch slots in the current cycle. */ + if (sched_verbose >= 6) + fprintf(sched_dump,";;\t\tSecond chance\n"); + memcpy (temp_state, curr_state, dfa_state_size); + if (early_queue_to_ready (temp_state, &ready)) + ready_sort (&ready); + } + if (ready.n_ready == 0 || !can_issue_more || state_dead_lock_p (curr_state) || !(*current_sched_info->schedule_more_p) ()) break; - + /* Select and remove the insn from the ready list. */ - insn = choose_ready (&ready); - + if (sort_p) + insn = choose_ready (&ready); + else + insn = ready_remove_first (&ready); + + if (targetm.sched.dfa_new_cycle + && (*targetm.sched.dfa_new_cycle) (sched_dump, sched_verbose, + insn, last_clock_var, + clock_var, &sort_p)) + { + ready_add (&ready, insn); + break; + } + + sort_p = TRUE; memcpy (temp_state, curr_state, dfa_state_size); if (recog_memoized (insn) < 0) { - if (!first_cycle_insn_p - && (GET_CODE (PATTERN (insn)) == ASM_INPUT - || asm_noperands (PATTERN (insn)) >= 0)) + asm_p = (GET_CODE (PATTERN (insn)) == ASM_INPUT + || asm_noperands (PATTERN (insn)) >= 0); + if (!first_cycle_insn_p && asm_p) /* This is asm insn which is tryed to be issued on the cycle not first. Issue it on the next cycle. */ cost = 1; @@ -2143,32 +2475,32 @@ schedule_block (b, rgn_n_insns) { int j; rtx bubble; - + for (j = 0; (bubble = (*targetm.sched.dfa_bubble) (j)) != NULL_RTX; j++) { memcpy (temp_state, curr_state, dfa_state_size); - + if (state_transition (temp_state, bubble) < 0 && state_transition (temp_state, insn) < 0) break; } - + if (bubble != NULL_RTX) { if (insert_schedule_bubbles_p) { rtx copy; - + copy = copy_rtx (PATTERN (bubble)); emit_insn_after (copy, last_scheduled_insn); last_scheduled_insn = NEXT_INSN (last_scheduled_insn); INSN_CODE (last_scheduled_insn) = INSN_CODE (bubble); - + /* Annotate the same for the first insns scheduling by using mode. */ PUT_MODE (last_scheduled_insn, @@ -2176,20 +2508,20 @@ schedule_block (b, rgn_n_insns) ? clock_var - last_clock_var : VOIDmode)); last_clock_var = clock_var; - + if (sched_verbose >= 2) { fprintf (sched_dump, ";;\t\t--> scheduling bubble insn <<<%d>>>:reservation ", INSN_UID (last_scheduled_insn)); - + if (recog_memoized (last_scheduled_insn) < 0) fprintf (sched_dump, "nothing"); else print_reservation (sched_dump, last_scheduled_insn); - + fprintf (sched_dump, "\n"); } } @@ -2224,7 +2556,7 @@ schedule_block (b, rgn_n_insns) cycle_issued_insns++; memcpy (curr_state, temp_state, dfa_state_size); } - + if (targetm.sched.variable_issue) can_issue_more = (*targetm.sched.variable_issue) (sched_dump, sched_verbose, @@ -2235,18 +2567,29 @@ schedule_block (b, rgn_n_insns) && GET_CODE (PATTERN (insn)) != CLOBBER) can_issue_more--; - schedule_insn (insn, &ready, clock_var); + advance = schedule_insn (insn, &ready, clock_var); + + /* After issuing an asm insn we should start a new cycle. */ + if (advance == 0 && asm_p) + advance = 1; + if (advance != 0) + break; next: first_cycle_insn_p = 0; - if (targetm.sched.reorder2) + /* Sort the ready list based on priority. This must be + redone here, as schedule_insn may have readied additional + insns that will not be sorted correctly. */ + if (ready.n_ready > 0) + ready_sort (&ready); + + if (targetm.sched.reorder2 + && (ready.n_ready == 0 + || !SCHED_GROUP_P (ready_element (&ready, 0)))) { - /* Sort the ready list based on priority. */ - if (ready.n_ready > 0) - ready_sort (&ready); can_issue_more = - (*targetm.sched.reorder2) (sched_dump,sched_verbose, + (*targetm.sched.reorder2) (sched_dump, sched_verbose, ready.n_ready ? ready_lastpos (&ready) : NULL, &ready.n_ready, clock_var); @@ -2282,6 +2625,27 @@ schedule_block (b, rgn_n_insns) head = NEXT_INSN (prev_head); tail = last_scheduled_insn; + if (!reload_completed) + { + rtx insn, link, next; + + /* INSN_TICK (minimum clock tick at which the insn becomes + ready) may be not correct for the insn in the subsequent + blocks of the region. We should use a correct value of + `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; + } + } + } + /* 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. */ @@ -2329,12 +2693,12 @@ schedule_block (b, rgn_n_insns) /* Set_priorities: compute priority of each insn in the block. */ int -set_priorities (head, tail) - rtx head, tail; +set_priorities (rtx head, rtx tail) { rtx insn; int n_insn; - + int sched_max_insns_priority = + current_sched_info->sched_max_insns_priority; rtx prev_head; prev_head = PREV_INSN (head); @@ -2343,15 +2707,22 @@ set_priorities (head, tail) return 0; n_insn = 0; + sched_max_insns_priority = 0; for (insn = tail; insn != prev_head; insn = PREV_INSN (insn)) { if (GET_CODE (insn) == NOTE) continue; - if (!(SCHED_GROUP_P (insn))) - n_insn++; + n_insn++; (void) priority (insn); + + if (INSN_PRIORITY_KNOWN (insn)) + 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; return n_insn; } @@ -2360,8 +2731,7 @@ set_priorities (head, tail) for debugging output. */ void -sched_init (dump_file) - FILE *dump_file; +sched_init (FILE *dump_file) { int luid; basic_block b; @@ -2399,7 +2769,7 @@ sched_init (dump_file) pseudos which do not cross calls. */ old_max_uid = get_max_uid () + 1; - h_i_d = (struct haifa_insn_data *) xcalloc (old_max_uid, sizeof (*h_i_d)); + h_i_d = xcalloc (old_max_uid, sizeof (*h_i_d)); for (i = 0; i < old_max_uid; i++) h_i_d [i].cost = -1; @@ -2409,14 +2779,14 @@ sched_init (dump_file) { if (targetm.sched.init_dfa_pre_cycle_insn) (*targetm.sched.init_dfa_pre_cycle_insn) (); - + if (targetm.sched.init_dfa_post_cycle_insn) (*targetm.sched.init_dfa_post_cycle_insn) (); - + if (targetm.sched.first_cycle_multipass_dfa_lookahead && targetm.sched.init_dfa_bubbles) (*targetm.sched.init_dfa_bubbles) (); - + dfa_start (); dfa_state_size = state_size (); curr_state = xmalloc (dfa_state_size); @@ -2425,7 +2795,7 @@ sched_init (dump_file) h_i_d[0].luid = 0; luid = 1; FOR_EACH_BB (b) - for (insn = b->head;; insn = NEXT_INSN (insn)) + for (insn = BB_HEAD (b); ; insn = NEXT_INSN (insn)) { INSN_LUID (insn) = luid; @@ -2437,7 +2807,7 @@ sched_init (dump_file) if (GET_CODE (insn) != NOTE) ++luid; - if (insn == b->end) + if (insn == BB_END (b)) break; } @@ -2449,7 +2819,7 @@ sched_init (dump_file) { rtx line; - line_note_head = (rtx *) xcalloc (last_basic_block, sizeof (rtx)); + line_note_head = xcalloc (last_basic_block, sizeof (rtx)); /* Save-line-note-head: Determine the line-number at the start of each basic block. @@ -2459,7 +2829,7 @@ sched_init (dump_file) FOR_EACH_BB (b) { - for (line = b->head; line; line = PREV_INSN (line)) + for (line = BB_HEAD (b); line; line = PREV_INSN (line)) if (GET_CODE (line) == NOTE && NOTE_LINE_NUMBER (line) > 0) { line_note_head[b->index] = line; @@ -2467,7 +2837,7 @@ sched_init (dump_file) } /* Do a forward search as well, since we won't get to see the first notes in a basic block. */ - for (line = b->head; line; line = NEXT_INSN (line)) + for (line = BB_HEAD (b); line; line = NEXT_INSN (line)) { if (INSN_P (line)) break; @@ -2486,16 +2856,16 @@ sched_init (dump_file) /* ??? Add a NOTE after the last insn of the last basic block. It is not known why this is done. */ - insn = EXIT_BLOCK_PTR->prev_bb->end; + insn = BB_END (EXIT_BLOCK_PTR->prev_bb); if (NEXT_INSN (insn) == 0 || (GET_CODE (insn) != NOTE && GET_CODE (insn) != CODE_LABEL /* Don't emit a NOTE if it would end up before a BARRIER. */ && GET_CODE (NEXT_INSN (insn)) != BARRIER)) { - emit_note_after (NOTE_INSN_DELETED, EXIT_BLOCK_PTR->prev_bb->end); + emit_note_after (NOTE_INSN_DELETED, BB_END (EXIT_BLOCK_PTR->prev_bb)); /* Make insn to appear outside BB. */ - EXIT_BLOCK_PTR->prev_bb->end = PREV_INSN (EXIT_BLOCK_PTR->prev_bb->end); + BB_END (EXIT_BLOCK_PTR->prev_bb) = PREV_INSN (BB_END (EXIT_BLOCK_PTR->prev_bb)); } /* Compute INSN_REG_WEIGHT for all blocks. We must do this before @@ -2507,7 +2877,7 @@ sched_init (dump_file) /* Free global data used during insn scheduling. */ void -sched_finish () +sched_finish (void) { free (h_i_d); |