#include "config.h"
#include "system.h"
#include "toplev.h"
#include "rtl.h"
#include "tm_p.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "regs.h"
#include "function.h"
#include "flags.h"
#include "insn-config.h"
#include "insn-attr.h"
#include "except.h"
#include "toplev.h"
#include "recog.h"
#include "sched-int.h"
#include "target.h"
#ifdef INSN_SCHEDULING
static int issue_rate;
static int sched_verbose_param = 0;
int sched_verbose = 0;
FILE *sched_dump = 0;
static int old_max_uid;
void
fix_sched_param (param, val)
const char *param, *val;
{
if (!strcmp (param, "verbose"))
sched_verbose_param = atoi (val);
else
warning ("fix_sched_param: unknown param: %s", param);
}
struct haifa_insn_data *h_i_d;
#define DONE_PRIORITY -1
#define MAX_PRIORITY 0x7fffffff
#define TAIL_PRIORITY 0x7ffffffe
#define LAUNCH_PRIORITY 0x7f000001
#define DONE_PRIORITY_P(INSN) (INSN_PRIORITY (INSN) < 0)
#define LOW_PRIORITY_P(INSN) ((INSN_PRIORITY (INSN) & 0x7f000000) == 0)
#define LINE_NOTE(INSN) (h_i_d[INSN_UID (INSN)].line_note)
#define INSN_TICK(INSN) (h_i_d[INSN_UID (INSN)].tick)
static rtx *line_note_head;
static rtx note_list;
static rtx insn_queue[INSN_QUEUE_SIZE];
static int q_ptr = 0;
static int q_size = 0;
#define NEXT_Q(X) (((X)+1) & (INSN_QUEUE_SIZE-1))
#define NEXT_Q_AFTER(X, C) (((X)+C) & (INSN_QUEUE_SIZE-1))
struct ready_list
{
rtx *vec;
int veclen;
int first;
int n_ready;
};
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 rtx unlink_other_notes PARAMS ((rtx, rtx));
static rtx unlink_line_notes PARAMS ((rtx, rtx));
static rtx reemit_notes PARAMS ((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 void queue_to_ready PARAMS ((struct ready_list *));
static void debug_ready_list PARAMS ((struct ready_list *));
static rtx move_insn1 PARAMS ((rtx, rtx));
static rtx move_insn PARAMS ((rtx, rtx));
#endif
struct sched_info *current_sched_info;
#ifndef INSN_SCHEDULING
void
schedule_insns (dump_file)
FILE *dump_file ATTRIBUTE_UNUSED;
{
}
#else
static rtx last_scheduled_insn;
HAIFA_INLINE int
insn_unit (insn)
rtx insn;
{
int unit = INSN_UNIT (insn);
if (unit == 0)
{
recog_memoized (insn);
if (INSN_CODE (insn) < 0)
unit = -1;
else
{
unit = function_units_used (insn);
if (unit >= 0)
unit++;
}
if (FUNCTION_UNITS_SIZE < HOST_BITS_PER_SHORT
|| unit >= 0
|| (unit & ~((1 << (HOST_BITS_PER_SHORT - 1)) - 1)) == 0)
INSN_UNIT (insn) = unit;
}
return (unit > 0 ? unit - 1 : unit);
}
HAIFA_INLINE static unsigned int
blockage_range (unit, insn)
int unit;
rtx insn;
{
unsigned int blockage = INSN_BLOCKAGE (insn);
unsigned int range;
if ((int) UNIT_BLOCKED (blockage) != unit + 1)
{
range = function_units[unit].blockage_range_function (insn);
if (HOST_BITS_PER_INT >= UNIT_BITS + 2 * BLOCKAGE_BITS)
INSN_BLOCKAGE (insn) = ENCODE_BLOCKAGE (unit + 1, range);
}
else
range = BLOCKAGE_RANGE (blockage);
return range;
}
static rtx unit_last_insn[FUNCTION_UNITS_SIZE * MAX_MULTIPLICITY];
static int unit_tick[FUNCTION_UNITS_SIZE * MAX_MULTIPLICITY];
static int unit_n_insns[FUNCTION_UNITS_SIZE];
rtx
get_unit_last_insn (instance)
int instance;
{
return unit_last_insn[instance];
}
static void
clear_units ()
{
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));
}
HAIFA_INLINE int
insn_issue_delay (insn)
rtx insn;
{
int i, delay = 0;
int unit = insn_unit (insn);
if (unit >= 0)
{
if (function_units[unit].blockage_range_function &&
function_units[unit].blockage_function)
delay = function_units[unit].blockage_function (insn, insn);
}
else
for (i = 0, unit = ~unit; unit; i++, unit >>= 1)
if ((unit & 1) != 0 && function_units[i].blockage_range_function
&& function_units[i].blockage_function)
delay = MAX (delay, function_units[i].blockage_function (insn, insn));
return delay;
}
HAIFA_INLINE int
actual_hazard_this_instance (unit, instance, insn, clock, cost)
int unit, instance, clock, cost;
rtx insn;
{
int tick = unit_tick[instance];
if (tick - clock > cost)
{
if (function_units[unit].blockage_range_function)
{
if (function_units[unit].blockage_function)
tick += (function_units[unit].blockage_function
(unit_last_insn[instance], insn)
- function_units[unit].max_blockage);
else
tick += ((int) MAX_BLOCKAGE_COST (blockage_range (unit, insn))
- function_units[unit].max_blockage);
}
if (tick - clock > cost)
cost = tick - clock;
}
return cost;
}
HAIFA_INLINE static void
schedule_unit (unit, insn, clock)
int unit, clock;
rtx insn;
{
int i;
if (unit >= 0)
{
int instance = unit;
#if MAX_MULTIPLICITY > 1
for (i = function_units[unit].multiplicity - 1; i > 0; i--)
{
if (!actual_hazard_this_instance (unit, instance, insn, clock, 0))
break;
instance += FUNCTION_UNITS_SIZE;
}
#endif
unit_last_insn[instance] = insn;
unit_tick[instance] = (clock + function_units[unit].max_blockage);
}
else
for (i = 0, unit = ~unit; unit; i++, unit >>= 1)
if ((unit & 1) != 0)
schedule_unit (i, insn, clock);
}
HAIFA_INLINE static int
actual_hazard (unit, insn, clock, cost)
int unit, clock, cost;
rtx insn;
{
int i;
if (unit >= 0)
{
int instance = unit;
int best_cost = actual_hazard_this_instance (unit, instance, insn,
clock, cost);
#if MAX_MULTIPLICITY > 1
int this_cost;
if (best_cost > cost)
{
for (i = function_units[unit].multiplicity - 1; i > 0; i--)
{
instance += FUNCTION_UNITS_SIZE;
this_cost = actual_hazard_this_instance (unit, instance, insn,
clock, cost);
if (this_cost < best_cost)
{
best_cost = this_cost;
if (this_cost <= cost)
break;
}
}
}
#endif
cost = MAX (cost, best_cost);
}
else
for (i = 0, unit = ~unit; unit; i++, unit >>= 1)
if ((unit & 1) != 0)
cost = actual_hazard (i, insn, clock, cost);
return cost;
}
HAIFA_INLINE static int
potential_hazard (unit, insn, cost)
int unit, cost;
rtx insn;
{
int i, ncost;
unsigned int minb, maxb;
if (unit >= 0)
{
minb = maxb = function_units[unit].max_blockage;
if (maxb > 1)
{
if (function_units[unit].blockage_range_function)
{
maxb = minb = blockage_range (unit, insn);
maxb = MAX_BLOCKAGE_COST (maxb);
minb = MIN_BLOCKAGE_COST (minb);
}
if (maxb > 1)
{
ncost = minb * 0x40 + maxb;
ncost *= (unit_n_insns[unit] - 1) * 0x1000 + unit;
if (ncost > cost)
cost = ncost;
}
}
}
else
for (i = 0, unit = ~unit; unit; i++, unit >>= 1)
if ((unit & 1) != 0)
cost = potential_hazard (i, insn, cost);
return cost;
}
HAIFA_INLINE int
insn_cost (insn, link, used)
rtx insn, link, used;
{
int cost = INSN_COST (insn);
if (cost == 0)
{
recog_memoized (insn);
if (INSN_CODE (insn) < 0)
{
INSN_COST (insn) = 1;
return 1;
}
else
{
cost = result_ready_cost (insn);
if (cost < 1)
cost = 1;
INSN_COST (insn) = cost;
}
}
if (link == 0 && used == 0)
return cost;
recog_memoized (used);
if (INSN_CODE (used) < 0)
LINK_COST_FREE (link) = 1;
if (LINK_COST_FREE (link))
cost = 0;
else if (!LINK_COST_ZERO (link) && targetm.sched.adjust_cost)
{
int ncost = (*targetm.sched.adjust_cost) (used, link, insn, cost);
if (ncost < 1)
{
LINK_COST_FREE (link) = 1;
ncost = 0;
}
if (cost == ncost)
LINK_COST_ZERO (link) = 1;
cost = ncost;
}
return cost;
}
static int
priority (insn)
rtx insn;
{
rtx link;
if (! INSN_P (insn))
return 0;
if (! INSN_PRIORITY_KNOWN (insn))
{
int this_priority = 0;
if (INSN_DEPEND (insn) == 0)
this_priority = insn_cost (insn, 0, 0);
else
{
for (link = INSN_DEPEND (insn); link; link = XEXP (link, 1))
{
rtx next;
int next_priority;
if (RTX_INTEGRATED_P (link))
continue;
next = XEXP (link, 0);
if (! (*current_sched_info->contributes_to_priority) (next, insn))
continue;
next_priority = insn_cost (insn, link, next) + priority (next);
if (next_priority > this_priority)
this_priority = next_priority;
}
}
INSN_PRIORITY (insn) = this_priority;
INSN_PRIORITY_KNOWN (insn) = 1;
}
return INSN_PRIORITY (insn);
}
#define SCHED_SORT(READY, N_READY) \
do { if ((N_READY) == 2) \
swap_sort (READY, N_READY); \
else if ((N_READY) > 2) \
qsort (READY, N_READY, sizeof (rtx), rank_for_schedule); } \
while (0)
static int
rank_for_schedule (x, y)
const PTR x;
const PTR y;
{
rtx tmp = *(const rtx *) y;
rtx tmp2 = *(const rtx *) x;
rtx link;
int tmp_class, tmp2_class, depend_count1, depend_count2;
int val, priority_val, weight_val, info_val;
#if 1 && MAX_MULTIPLICITY > 1
{
int pri = INSN_PRIORITY(tmp);
int pri2 = INSN_PRIORITY(tmp2);
if ( insn_unit(tmp)>0 && function_units[insn_unit(tmp)].multiplicity>1 && INSN_COST(tmp)==1 )
pri -= 1;
if ( insn_unit(tmp2)>0 && function_units[insn_unit(tmp2)].multiplicity>1 && INSN_COST(tmp2)==1 )
pri2 -= 1;
priority_val = pri2 - pri;
}
#else
priority_val = INSN_PRIORITY (tmp2) - INSN_PRIORITY (tmp);
#endif
if (priority_val)
return priority_val;
if (!reload_completed &&
(weight_val = INSN_REG_WEIGHT (tmp) - INSN_REG_WEIGHT (tmp2)))
return (weight_val);
info_val = (*current_sched_info->rank) (tmp, tmp2);
if (info_val)
return info_val;
if (last_scheduled_insn)
{
link = find_insn_list (tmp, INSN_DEPEND (last_scheduled_insn));
if (link == 0 || insn_cost (last_scheduled_insn, link, tmp) == 1)
tmp_class = 3;
else if (REG_NOTE_KIND (link) == 0)
tmp_class = 1;
else
tmp_class = 2;
link = find_insn_list (tmp2, INSN_DEPEND (last_scheduled_insn));
if (link == 0 || insn_cost (last_scheduled_insn, link, tmp2) == 1)
tmp2_class = 3;
else if (REG_NOTE_KIND (link) == 0)
tmp2_class = 1;
else
tmp2_class = 2;
if ((val = tmp2_class - tmp_class))
return val;
}
depend_count1 = 0;
for (link = INSN_DEPEND (tmp); link; link = XEXP (link, 1))
depend_count1++;
depend_count2 = 0;
for (link = INSN_DEPEND (tmp2); link; link = XEXP (link, 1))
depend_count2++;
val = depend_count2 - depend_count1;
if (val)
return val;
return INSN_LUID (tmp) - INSN_LUID (tmp2);
}
HAIFA_INLINE static void
swap_sort (a, n)
rtx *a;
int n;
{
rtx insn = a[n - 1];
int i = n - 2;
while (i >= 0 && rank_for_schedule (a + i, &insn) >= 0)
{
a[i + 1] = a[i];
i -= 1;
}
a[i + 1] = insn;
}
HAIFA_INLINE static void
queue_insn (insn, n_cycles)
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]);
insn_queue[next_q] = link;
q_size += 1;
if (sched_verbose >= 2)
{
fprintf (sched_dump, ";;\t\tReady-->Q: insn %s: ",
(*current_sched_info->print_insn) (insn, 0));
fprintf (sched_dump, "queued for %d cycles.\n", n_cycles);
}
}
HAIFA_INLINE static rtx *
ready_lastpos (ready)
struct ready_list *ready;
{
if (ready->n_ready == 0)
abort ();
return ready->vec + ready->first - ready->n_ready + 1;
}
HAIFA_INLINE void
ready_add (ready, insn)
struct ready_list *ready;
rtx insn;
{
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->n_ready++;
}
HAIFA_INLINE static rtx
ready_remove_first (ready)
struct ready_list *ready;
{
rtx t;
if (ready->n_ready == 0)
abort ();
t = ready->vec[ready->first--];
ready->n_ready--;
if (ready->n_ready == 0)
ready->first = ready->veclen - 1;
return t;
}
HAIFA_INLINE static void
ready_sort (ready)
struct ready_list *ready;
{
rtx *first = ready_lastpos (ready);
SCHED_SORT (first, ready->n_ready);
}
HAIFA_INLINE static void
adjust_priority (prev)
rtx prev;
{
if (targetm.sched.adjust_priority)
INSN_PRIORITY (prev) =
(*targetm.sched.adjust_priority) (prev, INSN_PRIORITY (prev));
}
static int last_clock_var;
static void
schedule_insn (insn, ready, clock)
rtx insn;
struct ready_list *ready;
int clock;
{
rtx link;
int unit;
unit = insn_unit (insn);
if (sched_verbose >= 2)
{
fprintf (sched_dump, ";;\t\t--> scheduling insn <<<%d>>> on unit ",
INSN_UID (insn));
insn_print_units (insn);
fprintf (sched_dump, "\n");
}
if (sched_verbose && unit == -1)
visualize_no_unit (insn);
if (MAX_BLOCKAGE > 1 || issue_rate > 1 || sched_verbose)
schedule_unit (unit, insn, clock);
if (INSN_DEPEND (insn) == 0)
return;
for (link = INSN_DEPEND (insn); link != 0; link = XEXP (link, 1))
{
rtx next = XEXP (link, 0);
int cost = insn_cost (insn, link, next);
INSN_TICK (next) = MAX (INSN_TICK (next), clock + cost);
if ((INSN_DEP_COUNT (next) -= 1) == 0)
{
int effective_cost = INSN_TICK (next) - clock;
if (! (*current_sched_info->new_ready) (next))
continue;
if (sched_verbose >= 2)
{
fprintf (sched_dump, ";;\t\tdependences resolved: insn %s ",
(*current_sched_info->print_insn) (next, 0));
if (effective_cost < 1)
fprintf (sched_dump, "into ready\n");
else
fprintf (sched_dump, "into queue with cost=%d\n", effective_cost);
}
adjust_priority (next);
if (effective_cost < 1)
ready_add (ready, next);
else
queue_insn (next, effective_cost);
}
}
if (reload_completed && issue_rate > 1)
{
PUT_MODE (insn, clock > last_clock_var ? TImode : VOIDmode);
last_clock_var = clock;
}
}
static rtx
unlink_other_notes (insn, tail)
rtx insn, tail;
{
rtx prev = PREV_INSN (insn);
while (insn != tail && GET_CODE (insn) == NOTE)
{
rtx next = NEXT_INSN (insn);
if (prev)
NEXT_INSN (prev) = next;
if (next)
PREV_INSN (next) = prev;
if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_RANGE_BEG
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_RANGE_END
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_END)
{
PREV_INSN (insn) = note_list;
if (note_list)
NEXT_INSN (note_list) = insn;
note_list = insn;
}
insn = next;
}
return insn;
}
static rtx
unlink_line_notes (insn, tail)
rtx insn, tail;
{
rtx prev = PREV_INSN (insn);
while (insn != tail && GET_CODE (insn) == NOTE)
{
rtx next = NEXT_INSN (insn);
if (write_symbols != NO_DEBUG && NOTE_LINE_NUMBER (insn) > 0)
{
if (prev)
NEXT_INSN (prev) = next;
if (next)
PREV_INSN (next) = prev;
LINE_NOTE (insn) = insn;
}
else
prev = insn;
insn = next;
}
return insn;
}
void
get_block_head_tail (b, headp, tailp)
int b;
rtx *headp;
rtx *tailp;
{
rtx head = BLOCK_HEAD (b);
rtx tail = BLOCK_END (b);
while (head != tail)
{
if (GET_CODE (head) == NOTE)
head = NEXT_INSN (head);
else if (GET_CODE (tail) == NOTE)
tail = PREV_INSN (tail);
else if (GET_CODE (head) == CODE_LABEL)
head = NEXT_INSN (head);
else
break;
}
*headp = head;
*tailp = tail;
}
int
no_real_insns_p (head, tail)
rtx head, tail;
{
while (head != NEXT_INSN (tail))
{
if (GET_CODE (head) != NOTE && GET_CODE (head) != CODE_LABEL)
return 0;
head = NEXT_INSN (head);
}
return 1;
}
void
rm_line_notes (head, tail)
rtx head, tail;
{
rtx next_tail;
rtx insn;
next_tail = NEXT_INSN (tail);
for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
{
rtx prev;
if (GET_CODE (insn) == NOTE)
{
prev = insn;
insn = unlink_line_notes (insn, next_tail);
if (prev == tail)
abort ();
if (prev == head)
abort ();
if (insn == next_tail)
abort ();
}
}
}
void
save_line_notes (b, head, tail)
int b;
rtx head, tail;
{
rtx next_tail;
rtx line = line_note_head[b];
rtx insn;
next_tail = NEXT_INSN (tail);
for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
line = insn;
else
LINE_NOTE (insn) = line;
}
void
restore_line_notes (head, tail)
rtx head, tail;
{
rtx line, note, prev, new;
int added_notes = 0;
rtx next_tail, insn;
head = head;
next_tail = NEXT_INSN (tail);
for (line = head; line; line = PREV_INSN (line))
if (GET_CODE (line) == NOTE && NOTE_LINE_NUMBER (line) > 0)
break;
for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
line = insn;
else if (GET_CODE (insn) != NOTE
&& INSN_UID (insn) < old_max_uid
&& (note = LINE_NOTE (insn)) != 0
&& note != line
&& (line == 0
|| NOTE_LINE_NUMBER (note) != NOTE_LINE_NUMBER (line)
|| NOTE_SOURCE_FILE (note) != NOTE_SOURCE_FILE (line)))
{
line = note;
prev = PREV_INSN (insn);
if (LINE_NOTE (note))
{
LINE_NOTE (note) = 0;
PREV_INSN (note) = prev;
NEXT_INSN (prev) = note;
PREV_INSN (insn) = note;
NEXT_INSN (note) = insn;
}
else
{
added_notes++;
new = emit_note_after (NOTE_LINE_NUMBER (note), prev);
NOTE_SOURCE_FILE (new) = NOTE_SOURCE_FILE (note);
RTX_INTEGRATED_P (new) = RTX_INTEGRATED_P (note);
}
}
if (sched_verbose && added_notes)
fprintf (sched_dump, ";; added %d line-number notes\n", added_notes);
}
void
rm_redundant_line_notes ()
{
rtx line = 0;
rtx insn = get_insns ();
int active_insn = 0;
int notes = 0;
for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
{
if (active_insn == 0)
{
notes++;
NOTE_SOURCE_FILE (insn) = 0;
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
}
else if (line
&& NOTE_LINE_NUMBER (line) == NOTE_LINE_NUMBER (insn)
&& NOTE_SOURCE_FILE (line) == NOTE_SOURCE_FILE (insn))
{
notes++;
NOTE_SOURCE_FILE (line) = 0;
NOTE_LINE_NUMBER (line) = NOTE_INSN_DELETED;
line = insn;
}
else
line = insn;
active_insn = 0;
}
else if (!((GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED)
|| (GET_CODE (insn) == INSN
&& (GET_CODE (PATTERN (insn)) == USE
|| GET_CODE (PATTERN (insn)) == CLOBBER))))
active_insn++;
if (sched_verbose && notes)
fprintf (sched_dump, ";; deleted %d line-number notes\n", notes);
}
void
rm_other_notes (head, tail)
rtx head;
rtx tail;
{
rtx next_tail;
rtx insn;
note_list = 0;
if (head == tail && (! INSN_P (head)))
return;
next_tail = NEXT_INSN (tail);
for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
{
rtx prev;
if (GET_CODE (insn) == NOTE)
{
prev = insn;
insn = unlink_other_notes (insn, next_tail);
if (prev == tail)
abort ();
if (prev == head)
abort ();
if (insn == next_tail)
abort ();
}
}
}
static void
find_insn_reg_weight (b)
int b;
{
rtx insn, next_tail, head, tail;
get_block_head_tail (b, &head, &tail);
next_tail = NEXT_INSN (tail);
for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
{
int reg_weight = 0;
rtx x;
if (! INSN_P (insn))
continue;
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)
{
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++;
}
}
for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
{
if (REG_NOTE_KIND (x) == REG_DEAD
|| REG_NOTE_KIND (x) == REG_UNUSED)
reg_weight--;
}
INSN_REG_WEIGHT (insn) = reg_weight;
}
}
static int clock_var;
static void
queue_to_ready (ready)
struct ready_list *ready;
{
rtx insn;
rtx link;
q_ptr = NEXT_Q (q_ptr);
for (link = insn_queue[q_ptr]; link; link = XEXP (link, 1))
{
insn = XEXP (link, 0);
q_size -= 1;
if (sched_verbose >= 2)
fprintf (sched_dump, ";;\t\tQ-->Ready: insn %s: ",
(*current_sched_info->print_insn) (insn, 0));
ready_add (ready, insn);
if (sched_verbose >= 2)
fprintf (sched_dump, "moving to ready without stalls\n");
}
insn_queue[q_ptr] = 0;
if (ready->n_ready == 0)
{
int stalls;
for (stalls = 1; stalls < INSN_QUEUE_SIZE; stalls++)
{
if ((link = insn_queue[NEXT_Q_AFTER (q_ptr, stalls)]))
{
for (; link; link = XEXP (link, 1))
{
insn = XEXP (link, 0);
q_size -= 1;
if (sched_verbose >= 2)
fprintf (sched_dump, ";;\t\tQ-->Ready: insn %s: ",
(*current_sched_info->print_insn) (insn, 0));
ready_add (ready, insn);
if (sched_verbose >= 2)
fprintf (sched_dump, "moving to ready with %d stalls\n", stalls);
}
insn_queue[NEXT_Q_AFTER (q_ptr, stalls)] = 0;
if (ready->n_ready)
break;
}
}
if (sched_verbose && stalls)
visualize_stall_cycles (stalls);
q_ptr = NEXT_Q_AFTER (q_ptr, stalls);
clock_var += stalls;
}
}
static void
debug_ready_list (ready)
struct ready_list *ready;
{
rtx *p;
int i;
if (ready->n_ready == 0)
return;
p = ready_lastpos (ready);
for (i = 0; i < ready->n_ready; i++)
fprintf (sched_dump, " %s", (*current_sched_info->print_insn) (p[i], 0));
fprintf (sched_dump, "\n");
}
static rtx
move_insn1 (insn, last)
rtx insn, last;
{
NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
NEXT_INSN (insn) = NEXT_INSN (last);
PREV_INSN (NEXT_INSN (last)) = insn;
NEXT_INSN (last) = insn;
PREV_INSN (insn) = last;
return insn;
}
static rtx
reemit_notes (insn, last)
rtx insn;
rtx last;
{
rtx note, retval;
retval = last;
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
{
if (REG_NOTE_KIND (note) == REG_SAVE_NOTE)
{
enum insn_note note_type = INTVAL (XEXP (note, 0));
if (note_type == NOTE_INSN_RANGE_BEG
|| note_type == NOTE_INSN_RANGE_END)
{
last = emit_note_before (note_type, last);
remove_note (insn, note);
note = XEXP (note, 1);
NOTE_RANGE_INFO (last) = XEXP (note, 0);
}
else
{
last = emit_note_before (note_type, last);
remove_note (insn, note);
note = XEXP (note, 1);
if (note_type == NOTE_INSN_EH_REGION_BEG
|| note_type == NOTE_INSN_EH_REGION_END)
NOTE_EH_HANDLER (last) = INTVAL (XEXP (note, 0));
}
remove_note (insn, note);
}
}
return retval;
}
static rtx
move_insn (insn, last)
rtx insn, last;
{
rtx retval = NULL;
while (SCHED_GROUP_P (insn))
{
rtx prev = PREV_INSN (insn);
move_insn1 (insn, last);
if (retval == NULL_RTX)
retval = reemit_notes (insn, insn);
else
reemit_notes (insn, insn);
insn = prev;
}
move_insn1 (insn, last);
if (retval == NULL_RTX)
retval = reemit_notes (insn, insn);
else
reemit_notes (insn, insn);
return retval;
}
rtx
sched_emit_insn (pat)
rtx pat;
{
rtx insn = emit_insn_after (pat, last_scheduled_insn);
last_scheduled_insn = insn;
return insn;
}
void
schedule_block (b, rgn_n_insns)
int b;
int rgn_n_insns;
{
struct ready_list ready;
int can_issue_more;
rtx prev_head = current_sched_info->prev_head;
rtx next_tail = current_sched_info->next_tail;
rtx head = NEXT_INSN (prev_head);
rtx tail = PREV_INSN (next_tail);
if (head == tail && (! INSN_P (head)))
abort ();
if (sched_verbose)
{
fprintf (sched_dump, ";; ======================================================\n");
fprintf (sched_dump,
";; -- basic block %d from %d to %d -- %s reload\n",
b, INSN_UID (head), INSN_UID (tail),
(reload_completed ? "after" : "before"));
fprintf (sched_dump, ";; ======================================================\n");
fprintf (sched_dump, "\n");
visualize_alloc ();
init_block_visualization ();
}
clear_units ();
ready.veclen = rgn_n_insns + 1 + issue_rate;
ready.first = ready.veclen - 1;
ready.vec = (rtx *) xmalloc (ready.veclen * sizeof (rtx));
ready.n_ready = 0;
(*current_sched_info->init_ready_list) (&ready);
if (targetm.sched.md_init)
(*targetm.sched.md_init) (sched_dump, sched_verbose, ready.veclen);
last_scheduled_insn = prev_head;
q_ptr = 0;
q_size = 0;
last_clock_var = 0;
memset ((char *) insn_queue, 0, sizeof (insn_queue));
clock_var = -1;
while ((*current_sched_info->schedule_more_p) ())
{
clock_var++;
queue_to_ready (&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);
}
ready_sort (&ready);
if (targetm.sched.reorder)
can_issue_more =
(*targetm.sched.reorder) (sched_dump, sched_verbose,
ready_lastpos (&ready),
&ready.n_ready, clock_var);
else
can_issue_more = issue_rate;
if (sched_verbose && targetm.sched.cycle_display)
last_scheduled_insn
= (*targetm.sched.cycle_display) (clock_var, last_scheduled_insn);
if (sched_verbose)
{
fprintf (sched_dump, "\n;;\tReady list (t =%3d): ", clock_var);
debug_ready_list (&ready);
}
while (ready.n_ready != 0
&& can_issue_more
&& (*current_sched_info->schedule_more_p) ())
{
rtx insn = ready_remove_first (&ready);
int cost = actual_hazard (insn_unit (insn), insn, clock_var, 0);
if (cost >= 1)
{
queue_insn (insn, cost);
continue;
}
if (! (*current_sched_info->can_schedule_ready_p) (insn))
goto next;
last_scheduled_insn = move_insn (insn, last_scheduled_insn);
if (targetm.sched.variable_issue)
can_issue_more =
(*targetm.sched.variable_issue) (sched_dump, sched_verbose,
insn, can_issue_more);
else if ( INSN_CODE (insn) >= 0 )
can_issue_more--;
schedule_insn (insn, &ready, clock_var);
next:
if (targetm.sched.reorder2)
{
if (ready.n_ready > 0)
ready_sort (&ready);
can_issue_more =
(*targetm.sched.reorder2) (sched_dump,sched_verbose,
ready.n_ready
? ready_lastpos (&ready) : NULL,
&ready.n_ready, clock_var);
}
}
if (sched_verbose)
visualize_scheduled_insns (clock_var);
}
if (targetm.sched.md_finish)
(*targetm.sched.md_finish) (sched_dump, sched_verbose);
if (sched_verbose)
{
fprintf (sched_dump, ";;\tReady list (final): ");
debug_ready_list (&ready);
print_block_visualization ("");
}
if (current_sched_info->queue_must_finish_empty && q_size != 0)
abort ();
head = NEXT_INSN (prev_head);
tail = last_scheduled_insn;
if (note_list != 0)
{
rtx note_head = note_list;
while (PREV_INSN (note_head))
{
note_head = PREV_INSN (note_head);
}
PREV_INSN (note_head) = PREV_INSN (head);
NEXT_INSN (PREV_INSN (head)) = note_head;
PREV_INSN (head) = note_list;
NEXT_INSN (note_list) = head;
head = note_head;
}
if (sched_verbose)
{
fprintf (sched_dump, ";; total time = %d\n;; new head = %d\n",
clock_var, INSN_UID (head));
fprintf (sched_dump, ";; new tail = %d\n\n",
INSN_UID (tail));
visualize_free ();
}
current_sched_info->head = head;
current_sched_info->tail = tail;
free (ready.vec);
}
int
set_priorities (head, tail)
rtx head, tail;
{
rtx insn;
int n_insn;
rtx prev_head;
prev_head = PREV_INSN (head);
if (head == tail && (! INSN_P (head)))
return 0;
n_insn = 0;
for (insn = tail; insn != prev_head; insn = PREV_INSN (insn))
{
if (GET_CODE (insn) == NOTE)
continue;
if (!(SCHED_GROUP_P (insn)))
n_insn++;
(void) priority (insn);
}
return n_insn;
}
void
sched_init (dump_file)
FILE *dump_file;
{
int luid, b;
rtx insn;
#ifdef HAVE_cc0
flag_schedule_speculative_load = 0;
#endif
sched_verbose = sched_verbose_param;
if (sched_verbose_param == 0 && dump_file)
sched_verbose = 1;
sched_dump = ((sched_verbose_param >= 10 || !dump_file)
? stderr : dump_file);
if (targetm.sched.issue_rate)
issue_rate = (*targetm.sched.issue_rate) ();
else
issue_rate = 1;
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[0].luid = 0;
luid = 1;
for (b = 0; b < n_basic_blocks; b++)
for (insn = BLOCK_HEAD (b);; insn = NEXT_INSN (insn))
{
INSN_LUID (insn) = luid;
if (GET_CODE (insn) != NOTE)
++luid;
if (insn == BLOCK_END (b))
break;
}
init_dependency_caches (luid);
compute_bb_for_insn (old_max_uid);
init_alias_analysis ();
if (write_symbols != NO_DEBUG)
{
rtx line;
line_note_head = (rtx *) xcalloc (n_basic_blocks, sizeof (rtx));
for (b = 0; b < n_basic_blocks; b++)
{
for (line = BLOCK_HEAD (b); line; line = PREV_INSN (line))
if (GET_CODE (line) == NOTE && NOTE_LINE_NUMBER (line) > 0)
{
line_note_head[b] = line;
break;
}
for (line = BLOCK_HEAD (b); line; line = NEXT_INSN (line))
{
if (INSN_P (line))
break;
if (GET_CODE (line) == NOTE && NOTE_LINE_NUMBER (line) > 0)
line_note_head[b] = line;
}
}
}
if (sched_verbose)
init_target_units ();
insn = BLOCK_END (n_basic_blocks - 1);
if (NEXT_INSN (insn) == 0
|| (GET_CODE (insn) != NOTE
&& GET_CODE (insn) != CODE_LABEL
&& GET_CODE (NEXT_INSN (insn)) != BARRIER))
{
emit_note_after (NOTE_INSN_DELETED, BLOCK_END (n_basic_blocks - 1));
BLOCK_END (n_basic_blocks - 1) = PREV_INSN (BLOCK_END (n_basic_blocks - 1));
}
for (b = n_basic_blocks - 1; b >= 0; b--)
find_insn_reg_weight (b);
}
void
sched_finish ()
{
free (h_i_d);
free_dependency_caches ();
end_alias_analysis ();
if (write_symbols != NO_DEBUG)
free (line_note_head);
}
#endif