#include "config.h"
#include "system.h"
#include "toplev.h"
#include "rtl.h"
#include "basic-block.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "flags.h"
#include "insn-config.h"
#include "insn-attr.h"
#include "recog.h"
#ifndef INSN_SCHEDULING
void
schedule_insns (dump_file)
FILE *dump_file ATTRIBUTE_UNUSED;
{
}
#else
extern char *reg_known_equiv_p;
extern rtx *reg_known_value;
static int *sched_reg_n_calls_crossed;
static int *sched_reg_live_length;
static rtx *reg_last_uses;
static rtx *reg_last_sets;
static regset reg_pending_sets;
static int reg_pending_sets_all;
static int *insn_luid;
#define INSN_LUID(INSN) (insn_luid[INSN_UID (INSN)])
static int *insn_priority;
#define INSN_PRIORITY(INSN) (insn_priority[INSN_UID (INSN)])
static short *insn_costs;
#define INSN_COST(INSN) insn_costs[INSN_UID (INSN)]
static short *insn_units;
#define INSN_UNIT(INSN) insn_units[INSN_UID (INSN)]
static unsigned int *insn_blockage;
#define INSN_BLOCKAGE(INSN) insn_blockage[INSN_UID (INSN)]
#define UNIT_BITS 5
#define BLOCKAGE_MASK ((1 << BLOCKAGE_BITS) - 1)
#define ENCODE_BLOCKAGE(U,R) \
((((U) << UNIT_BITS) << BLOCKAGE_BITS \
| MIN_BLOCKAGE_COST (R)) << BLOCKAGE_BITS \
| MAX_BLOCKAGE_COST (R))
#define UNIT_BLOCKED(B) ((B) >> (2 * BLOCKAGE_BITS))
#define BLOCKAGE_RANGE(B) \
(((((B) >> BLOCKAGE_BITS) & BLOCKAGE_MASK) << (HOST_BITS_PER_INT / 2)) \
| ((B) & BLOCKAGE_MASK))
#define MIN_BLOCKAGE_COST(R) ((R) >> (HOST_BITS_PER_INT / 2))
#define MAX_BLOCKAGE_COST(R) ((R) & ((1 << (HOST_BITS_PER_INT / 2)) - 1))
#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)
static int *insn_ref_count;
#define INSN_REF_COUNT(INSN) (insn_ref_count[INSN_UID (INSN)])
static rtx *line_note;
#define LINE_NOTE(INSN) (line_note[INSN_UID (INSN)])
static rtx *line_note_head;
static rtx note_list;
static regset bb_dead_regs;
static regset bb_live_regs;
static regset old_live_regs;
static rtx dead_notes;
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))
static int *insn_tick;
#define INSN_TICK(INSN) (insn_tick[INSN_UID (INSN)])
struct sometimes
{
int regno;
int live_length;
int calls_crossed;
};
static void add_dependence PROTO((rtx, rtx, enum reg_note));
static void remove_dependence PROTO((rtx, rtx));
static rtx find_insn_list PROTO((rtx, rtx));
static int insn_unit PROTO((rtx));
static unsigned int blockage_range PROTO((int, rtx));
static void clear_units PROTO((void));
static void prepare_unit PROTO((int));
static int actual_hazard_this_instance PROTO((int, int, rtx, int, int));
static void schedule_unit PROTO((int, rtx, int));
static int actual_hazard PROTO((int, rtx, int, int));
static int potential_hazard PROTO((int, rtx, int));
static int insn_cost PROTO((rtx, rtx, rtx));
static int priority PROTO((rtx));
static void free_pending_lists PROTO((void));
static void add_insn_mem_dependence PROTO((rtx *, rtx *, rtx, rtx));
static void flush_pending_lists PROTO((rtx, int));
static void sched_analyze_1 PROTO((rtx, rtx));
static void sched_analyze_2 PROTO((rtx, rtx));
static void sched_analyze_insn PROTO((rtx, rtx, rtx));
static int sched_analyze PROTO((rtx, rtx));
static void sched_note_set PROTO((rtx, int));
static int rank_for_schedule PROTO((const GENERIC_PTR, const GENERIC_PTR));
static void swap_sort PROTO((rtx *, int));
static void queue_insn PROTO((rtx, int));
static int birthing_insn_p PROTO((rtx));
static void adjust_priority PROTO((rtx));
static int schedule_insn PROTO((rtx, rtx *, int, int));
static int schedule_select PROTO((rtx *, int, int, FILE *));
static void create_reg_dead_note PROTO((rtx, rtx));
static void attach_deaths PROTO((rtx, rtx, int));
static void attach_deaths_insn PROTO((rtx));
static rtx unlink_notes PROTO((rtx, rtx));
static int new_sometimes_live PROTO((struct sometimes *, int, int));
static void finish_sometimes_live PROTO((struct sometimes *, int));
static rtx reemit_notes PROTO((rtx, rtx));
static void schedule_block PROTO((int, FILE *));
static void split_hard_reg_notes PROTO((rtx, rtx, rtx));
static void new_insn_dead_notes PROTO((rtx, rtx, rtx, rtx));
static void update_n_sets PROTO((rtx, int));
void schedule_insns PROTO((FILE *));
#define SIZE_FOR_MODE(X) (GET_MODE_SIZE (GET_MODE (X)))
static void
add_dependence (insn, elem, dep_type)
rtx insn;
rtx elem;
enum reg_note dep_type;
{
rtx link, next;
if (insn == elem)
return;
next = NEXT_INSN (elem);
#ifdef HAVE_cc0
while (next && GET_CODE (next) == NOTE)
next = NEXT_INSN (next);
#endif
if (next && SCHED_GROUP_P (next)
&& GET_CODE (next) != CODE_LABEL)
{
while (NEXT_INSN (next) && SCHED_GROUP_P (NEXT_INSN (next))
&& GET_CODE (NEXT_INSN (next)) != CODE_LABEL)
next = NEXT_INSN (next);
if (insn == next)
return;
elem = next;
}
for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
if (XEXP (link, 0) == elem)
{
if ((int) dep_type < (int) REG_NOTE_KIND (link))
PUT_REG_NOTE_KIND (link, dep_type);
return;
}
link = rtx_alloc (INSN_LIST);
PUT_REG_NOTE_KIND (link, dep_type);
XEXP (link, 0) = elem;
XEXP (link, 1) = LOG_LINKS (insn);
LOG_LINKS (insn) = link;
}
static void
remove_dependence (insn, elem)
rtx insn;
rtx elem;
{
rtx prev, link;
int found = 0;
for (prev = 0, link = LOG_LINKS (insn); link; link = XEXP (link, 1))
{
if (XEXP (link, 0) == elem)
{
RTX_INTEGRATED_P (link) = 1;
if (prev)
XEXP (prev, 1) = XEXP (link, 1);
else
LOG_LINKS (insn) = XEXP (link, 1);
found = 1;
}
else
prev = link;
}
if (! found)
abort ();
return;
}
#ifndef __GNUC__
#define __inline
#endif
static rtx pending_read_insns;
static rtx pending_read_mems;
static rtx pending_write_insns;
static rtx pending_write_mems;
static int pending_lists_length;
static rtx unused_insn_list;
static rtx unused_expr_list;
static rtx last_pending_memory_flush;
static rtx last_function_call;
static rtx sched_before_next_call;
static rtx last_scheduled_insn;
__inline static rtx
find_insn_list (insn, list)
rtx insn;
rtx list;
{
while (list)
{
if (XEXP (list, 0) == insn)
return list;
list = XEXP (list, 1);
}
return 0;
}
__inline static int
insn_unit (insn)
rtx insn;
{
register 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);
}
__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];
static void
clear_units ()
{
bzero ((char *) unit_last_insn, sizeof (unit_last_insn));
bzero ((char *) unit_tick, sizeof (unit_tick));
bzero ((char *) unit_n_insns, sizeof (unit_n_insns));
}
__inline static void
prepare_unit (unit)
int unit;
{
int i;
if (unit >= 0)
unit_n_insns[unit]++;
else
for (i = 0, unit = ~unit; unit; i++, unit >>= 1)
if ((unit & 1) != 0)
prepare_unit (i);
}
__inline static 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
(insn, unit_last_insn[instance])
- 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;
}
__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);
}
__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;
}
__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;
}
__inline static int
insn_cost (insn, link, used)
rtx insn, link, used;
{
register 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;
}
}
recog_memoized (used);
if (INSN_CODE (used) < 0)
LINK_COST_FREE (link) = 1;
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;
}
#endif
return cost;
}
static int
priority (insn)
rtx insn;
{
if (insn && GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
int prev_priority;
int max_priority;
int this_priority = INSN_PRIORITY (insn);
rtx prev;
if (this_priority > 0)
return this_priority;
max_priority = 1;
if (SCHED_GROUP_P (insn))
{
prev = insn;
while (SCHED_GROUP_P (prev))
{
prev = PREV_INSN (prev);
INSN_REF_COUNT (prev) += 1;
}
}
for (prev = LOG_LINKS (insn); prev; prev = XEXP (prev, 1))
{
rtx x = XEXP (prev, 0);
if (RTX_INTEGRATED_P (prev))
continue;
if (GET_CODE (x) == NOTE || INSN_DELETED_P (x))
{
remove_dependence (insn, x);
continue;
}
LINK_COST_FREE (prev) = 0;
#ifdef ADJUST_COST
LINK_COST_ZERO (prev) = 0;
#endif
prev_priority = priority (x) + insn_cost (x, prev, insn) - 1;
if (prev_priority > max_priority)
max_priority = prev_priority;
INSN_REF_COUNT (x) += 1;
}
prepare_unit (insn_unit (insn));
INSN_PRIORITY (insn) = max_priority;
return INSN_PRIORITY (insn);
}
return 0;
}
static void
free_pending_lists ()
{
register rtx link, prev_link;
if (pending_read_insns)
{
prev_link = pending_read_insns;
link = XEXP (prev_link, 1);
while (link)
{
prev_link = link;
link = XEXP (link, 1);
}
XEXP (prev_link, 1) = unused_insn_list;
unused_insn_list = pending_read_insns;
pending_read_insns = 0;
}
if (pending_write_insns)
{
prev_link = pending_write_insns;
link = XEXP (prev_link, 1);
while (link)
{
prev_link = link;
link = XEXP (link, 1);
}
XEXP (prev_link, 1) = unused_insn_list;
unused_insn_list = pending_write_insns;
pending_write_insns = 0;
}
if (pending_read_mems)
{
prev_link = pending_read_mems;
link = XEXP (prev_link, 1);
while (link)
{
prev_link = link;
link = XEXP (link, 1);
}
XEXP (prev_link, 1) = unused_expr_list;
unused_expr_list = pending_read_mems;
pending_read_mems = 0;
}
if (pending_write_mems)
{
prev_link = pending_write_mems;
link = XEXP (prev_link, 1);
while (link)
{
prev_link = link;
link = XEXP (link, 1);
}
XEXP (prev_link, 1) = unused_expr_list;
unused_expr_list = pending_write_mems;
pending_write_mems = 0;
}
}
static void
add_insn_mem_dependence (insn_list, mem_list, insn, mem)
rtx *insn_list, *mem_list, insn, mem;
{
register rtx link;
if (unused_insn_list)
{
link = unused_insn_list;
unused_insn_list = XEXP (link, 1);
}
else
link = rtx_alloc (INSN_LIST);
XEXP (link, 0) = insn;
XEXP (link, 1) = *insn_list;
*insn_list = link;
if (unused_expr_list)
{
link = unused_expr_list;
unused_expr_list = XEXP (link, 1);
}
else
link = rtx_alloc (EXPR_LIST);
XEXP (link, 0) = mem;
XEXP (link, 1) = *mem_list;
*mem_list = link;
pending_lists_length++;
}
static void
flush_pending_lists (insn, only_write)
rtx insn;
int only_write;
{
rtx link;
while (pending_read_insns && ! only_write)
{
add_dependence (insn, XEXP (pending_read_insns, 0), REG_DEP_ANTI);
link = pending_read_insns;
pending_read_insns = XEXP (pending_read_insns, 1);
XEXP (link, 1) = unused_insn_list;
unused_insn_list = link;
link = pending_read_mems;
pending_read_mems = XEXP (pending_read_mems, 1);
XEXP (link, 1) = unused_expr_list;
unused_expr_list = link;
}
while (pending_write_insns)
{
add_dependence (insn, XEXP (pending_write_insns, 0), REG_DEP_ANTI);
link = pending_write_insns;
pending_write_insns = XEXP (pending_write_insns, 1);
XEXP (link, 1) = unused_insn_list;
unused_insn_list = link;
link = pending_write_mems;
pending_write_mems = XEXP (pending_write_mems, 1);
XEXP (link, 1) = unused_expr_list;
unused_expr_list = link;
}
pending_lists_length = 0;
if (last_pending_memory_flush)
add_dependence (insn, last_pending_memory_flush, REG_DEP_ANTI);
last_pending_memory_flush = insn;
}
static void
sched_analyze_1 (x, insn)
rtx x;
rtx insn;
{
register int regno;
register rtx dest = SET_DEST (x);
if (dest == 0)
return;
while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT)
{
if (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT)
{
sched_analyze_2 (XEXP (dest, 1), insn);
sched_analyze_2 (XEXP (dest, 2), insn);
}
dest = SUBREG_REG (dest);
}
if (GET_CODE (dest) == REG)
{
register int i;
regno = REGNO (dest);
if (regno < FIRST_PSEUDO_REGISTER)
{
i = HARD_REGNO_NREGS (regno, GET_MODE (dest));
while (--i >= 0)
{
rtx u;
for (u = reg_last_uses[regno+i]; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
reg_last_uses[regno + i] = 0;
if (reg_last_sets[regno + i])
add_dependence (insn, reg_last_sets[regno + i],
REG_DEP_OUTPUT);
SET_REGNO_REG_SET (reg_pending_sets, regno + i);
if ((call_used_regs[i] || global_regs[i])
&& last_function_call)
add_dependence (insn, last_function_call, REG_DEP_ANTI);
}
}
else
{
rtx u;
for (u = reg_last_uses[regno]; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
reg_last_uses[regno] = 0;
if (reg_last_sets[regno])
add_dependence (insn, reg_last_sets[regno], REG_DEP_OUTPUT);
SET_REGNO_REG_SET (reg_pending_sets, regno);
if (! reload_completed
&& reg_known_equiv_p[regno]
&& GET_CODE (reg_known_value[regno]) == MEM)
sched_analyze_2 (XEXP (reg_known_value[regno], 0), insn);
if (REG_N_CALLS_CROSSED (regno) == 0 && last_function_call)
add_dependence (insn, last_function_call, REG_DEP_ANTI);
}
}
else if (GET_CODE (dest) == MEM)
{
if (pending_lists_length > 32)
{
flush_pending_lists (insn, 0);
}
else
{
rtx pending, pending_mem;
pending = pending_read_insns;
pending_mem = pending_read_mems;
while (pending)
{
if (! find_insn_list (XEXP (pending, 0), LOG_LINKS (insn)))
if (anti_dependence (XEXP (pending_mem, 0), dest))
add_dependence (insn, XEXP (pending, 0), REG_DEP_ANTI);
pending = XEXP (pending, 1);
pending_mem = XEXP (pending_mem, 1);
}
pending = pending_write_insns;
pending_mem = pending_write_mems;
while (pending)
{
if (! find_insn_list (XEXP (pending, 0), LOG_LINKS (insn)))
if (output_dependence (XEXP (pending_mem, 0), dest))
add_dependence (insn, XEXP (pending, 0), REG_DEP_OUTPUT);
pending = XEXP (pending, 1);
pending_mem = XEXP (pending_mem, 1);
}
if (last_pending_memory_flush)
add_dependence (insn, last_pending_memory_flush, REG_DEP_ANTI);
add_insn_mem_dependence (&pending_write_insns, &pending_write_mems,
insn, dest);
}
sched_analyze_2 (XEXP (dest, 0), insn);
}
if (GET_CODE (x) == SET)
sched_analyze_2 (SET_SRC (x), insn);
}
static void
sched_analyze_2 (x, insn)
rtx x;
rtx insn;
{
register int i;
register int j;
register enum rtx_code code;
register char *fmt;
if (x == 0)
return;
code = GET_CODE (x);
switch (code)
{
case CONST_INT:
case CONST_DOUBLE:
case SYMBOL_REF:
case CONST:
case LABEL_REF:
return;
#ifdef HAVE_cc0
case CC0:
{
rtx link, prev;
SCHED_GROUP_P (insn) = 1;
prev = prev_nonnote_insn (insn);
if (find_insn_list (prev, LOG_LINKS (insn)))
remove_dependence (insn, prev);
for (link = LOG_LINKS (prev); link; link = XEXP (link, 1))
add_dependence (insn, XEXP (link, 0), REG_NOTE_KIND (link));
return;
}
#endif
case REG:
{
int regno = REGNO (x);
if (regno < FIRST_PSEUDO_REGISTER)
{
int i;
i = HARD_REGNO_NREGS (regno, GET_MODE (x));
while (--i >= 0)
{
reg_last_uses[regno + i]
= gen_rtx_INSN_LIST (VOIDmode,
insn, reg_last_uses[regno + i]);
if (reg_last_sets[regno + i])
add_dependence (insn, reg_last_sets[regno + i], 0);
if ((call_used_regs[regno + i] || global_regs[regno + i])
&& last_function_call)
add_dependence (insn, last_function_call, REG_DEP_ANTI);
}
}
else
{
reg_last_uses[regno]
= gen_rtx_INSN_LIST (VOIDmode, insn, reg_last_uses[regno]);
if (reg_last_sets[regno])
add_dependence (insn, reg_last_sets[regno], 0);
if (! reload_completed
&& reg_known_equiv_p[regno]
&& GET_CODE (reg_known_value[regno]) == MEM)
sched_analyze_2 (XEXP (reg_known_value[regno], 0), insn);
if (REG_N_CALLS_CROSSED (regno) == 0)
add_dependence (sched_before_next_call, insn, REG_DEP_ANTI);
}
return;
}
case MEM:
{
rtx pending, pending_mem;
pending = pending_read_insns;
pending_mem = pending_read_mems;
while (pending)
{
if (! find_insn_list (XEXP (pending, 0), LOG_LINKS (insn)))
if (read_dependence (XEXP (pending_mem, 0), x))
add_dependence (insn, XEXP (pending, 0), REG_DEP_ANTI);
pending = XEXP (pending, 1);
pending_mem = XEXP (pending_mem, 1);
}
pending = pending_write_insns;
pending_mem = pending_write_mems;
while (pending)
{
if (! find_insn_list (XEXP (pending, 0), LOG_LINKS (insn)))
if (true_dependence (XEXP (pending_mem, 0), VOIDmode,
x, rtx_varies_p))
add_dependence (insn, XEXP (pending, 0), 0);
pending = XEXP (pending, 1);
pending_mem = XEXP (pending_mem, 1);
}
if (last_pending_memory_flush)
add_dependence (insn, last_pending_memory_flush, REG_DEP_ANTI);
add_insn_mem_dependence (&pending_read_insns, &pending_read_mems,
insn, x);
sched_analyze_2 (XEXP (x, 0), insn);
return;
}
case ASM_OPERANDS:
case ASM_INPUT:
case UNSPEC_VOLATILE:
case TRAP_IF:
{
rtx u;
if (code != ASM_OPERANDS || MEM_VOLATILE_P (x))
{
int max_reg = max_reg_num ();
for (i = 0; i < max_reg; i++)
{
for (u = reg_last_uses[i]; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
reg_last_uses[i] = 0;
if (reg_last_sets[i])
add_dependence (insn, reg_last_sets[i], 0);
}
reg_pending_sets_all = 1;
flush_pending_lists (insn, 0);
}
if (code == ASM_OPERANDS)
{
for (j = 0; j < ASM_OPERANDS_INPUT_LENGTH (x); j++)
sched_analyze_2 (ASM_OPERANDS_INPUT (x, j), insn);
return;
}
break;
}
case PRE_DEC:
case POST_DEC:
case PRE_INC:
case POST_INC:
sched_analyze_2 (XEXP (x, 0), insn);
sched_analyze_1 (x, insn);
return;
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
sched_analyze_2 (XEXP (x, i), insn);
else if (fmt[i] == 'E')
for (j = 0; j < XVECLEN (x, i); j++)
sched_analyze_2 (XVECEXP (x, i, j), insn);
}
}
static void
sched_analyze_insn (x, insn, loop_notes)
rtx x, insn;
rtx loop_notes;
{
register RTX_CODE code = GET_CODE (x);
rtx link;
int maxreg = max_reg_num ();
int i;
if (code == SET || code == CLOBBER)
sched_analyze_1 (x, insn);
else if (code == PARALLEL)
{
register int i;
for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
{
code = GET_CODE (XVECEXP (x, 0, i));
if (code == SET || code == CLOBBER)
sched_analyze_1 (XVECEXP (x, 0, i), insn);
else
sched_analyze_2 (XVECEXP (x, 0, i), insn);
}
}
else
sched_analyze_2 (x, insn);
if (GET_CODE (insn) == CALL_INSN)
for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
{
if (GET_CODE (XEXP (link, 0)) == CLOBBER)
sched_analyze_1 (XEXP (link, 0), insn);
else
sched_analyze_2 (XEXP (link, 0), insn);
}
if (loop_notes)
{
int max_reg = max_reg_num ();
rtx link;
for (i = 0; i < max_reg; i++)
{
rtx u;
for (u = reg_last_uses[i]; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
reg_last_uses[i] = 0;
if (reg_last_sets[i])
add_dependence (insn, reg_last_sets[i], 0);
}
reg_pending_sets_all = 1;
flush_pending_lists (insn, 0);
link = loop_notes;
while (XEXP (link, 1))
link = XEXP (link, 1);
XEXP (link, 1) = REG_NOTES (insn);
REG_NOTES (insn) = loop_notes;
}
EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i,
{
reg_last_sets[i] = insn;
});
CLEAR_REG_SET (reg_pending_sets);
if (reg_pending_sets_all)
{
for (i = 0; i < maxreg; i++)
reg_last_sets[i] = insn;
reg_pending_sets_all = 0;
}
if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
{
rtx dep_insn;
rtx prev_dep_insn;
prev_dep_insn = insn;
dep_insn = PREV_INSN (insn);
while (GET_CODE (dep_insn) == INSN
&& GET_CODE (PATTERN (dep_insn)) == USE
&& GET_CODE (XEXP (PATTERN (dep_insn), 0)) == REG)
{
SCHED_GROUP_P (prev_dep_insn) = 1;
for (link = LOG_LINKS (dep_insn); link; link = XEXP (link, 1))
add_dependence (insn, XEXP (link, 0), REG_NOTE_KIND (link));
prev_dep_insn = dep_insn;
dep_insn = PREV_INSN (dep_insn);
}
}
}
static int
sched_analyze (head, tail)
rtx head, tail;
{
register rtx insn;
register int n_insns = 0;
register rtx u;
register int luid = 0;
rtx loop_notes = 0;
for (insn = head; ; insn = NEXT_INSN (insn))
{
INSN_LUID (insn) = luid++;
if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
{
sched_analyze_insn (PATTERN (insn), insn, loop_notes);
loop_notes = 0;
n_insns += 1;
}
else if (GET_CODE (insn) == CALL_INSN)
{
rtx x;
register int i;
if (NEXT_INSN (insn) && GET_CODE (NEXT_INSN (insn)) == NOTE
&& NOTE_LINE_NUMBER (NEXT_INSN (insn)) == NOTE_INSN_SETJMP)
{
int max_reg = max_reg_num ();
for (i = 0; i < max_reg; i++)
{
for (u = reg_last_uses[i]; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
reg_last_uses[i] = 0;
if (reg_last_sets[i])
add_dependence (insn, reg_last_sets[i], 0);
}
reg_pending_sets_all = 1;
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD,
GEN_INT (0),
REG_NOTES (insn));
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD,
GEN_INT (NOTE_INSN_SETJMP),
REG_NOTES (insn));
}
else
{
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (call_used_regs[i] || global_regs[i])
{
for (u = reg_last_uses[i]; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
reg_last_uses[i] = 0;
if (reg_last_sets[i])
add_dependence (insn, reg_last_sets[i], REG_DEP_ANTI);
SET_REGNO_REG_SET (reg_pending_sets, i);
}
}
x = LOG_LINKS (sched_before_next_call);
while (x)
{
add_dependence (insn, XEXP (x, 0), REG_DEP_ANTI);
x = XEXP (x, 1);
}
LOG_LINKS (sched_before_next_call) = 0;
sched_analyze_insn (PATTERN (insn), insn, loop_notes);
loop_notes = 0;
flush_pending_lists (insn, CONST_CALL_P (insn));
last_function_call = insn;
n_insns += 1;
}
else if (GET_CODE (insn) == NOTE
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_RANGE_START
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_RANGE_END
|| (NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP
&& GET_CODE (PREV_INSN (insn)) != CALL_INSN)))
{
loop_notes = gen_rtx_EXPR_LIST (REG_DEAD,
GEN_INT (NOTE_BLOCK_NUMBER (insn)),
loop_notes);
loop_notes = gen_rtx_EXPR_LIST (REG_DEAD,
GEN_INT (NOTE_LINE_NUMBER (insn)),
loop_notes);
CONST_CALL_P (loop_notes) = CONST_CALL_P (insn);
}
if (insn == tail)
return n_insns;
}
abort ();
}
static void
sched_note_set (x, death)
rtx x;
int death;
{
register int regno;
register rtx reg = SET_DEST (x);
int subreg_p = 0;
if (reg == 0)
return;
while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == STRICT_LOW_PART
|| GET_CODE (reg) == SIGN_EXTRACT || GET_CODE (reg) == ZERO_EXTRACT)
{
if (GET_CODE (reg) != SUBREG
|| REG_SIZE (SUBREG_REG (reg)) > REG_SIZE (reg))
subreg_p = 1;
reg = SUBREG_REG (reg);
}
if (GET_CODE (reg) != REG)
return;
regno = REGNO (reg);
if (regno >= FIRST_PSEUDO_REGISTER || ! global_regs[regno])
{
if (death)
{
if (subreg_p)
return;
if (regno < FIRST_PSEUDO_REGISTER)
{
int j = HARD_REGNO_NREGS (regno, GET_MODE (reg));
while (--j >= 0)
{
CLEAR_REGNO_REG_SET (bb_live_regs, regno + j);
SET_REGNO_REG_SET (bb_dead_regs, regno + j);
}
}
else
{
CLEAR_REGNO_REG_SET (bb_live_regs, regno);
SET_REGNO_REG_SET (bb_dead_regs, regno);
}
}
else
{
if (regno < FIRST_PSEUDO_REGISTER)
{
int j = HARD_REGNO_NREGS (regno, GET_MODE (reg));
while (--j >= 0)
{
SET_REGNO_REG_SET (bb_live_regs, regno + j);
CLEAR_REGNO_REG_SET (bb_dead_regs, regno + j);
}
}
else
{
SET_REGNO_REG_SET (bb_live_regs, regno);
CLEAR_REGNO_REG_SET (bb_dead_regs, regno);
}
}
}
}
#define SCHED_SORT(READY, NEW_READY, OLD_READY) \
do { if ((NEW_READY) - (OLD_READY) == 1) \
swap_sort (READY, NEW_READY); \
else if ((NEW_READY) - (OLD_READY) > 1) \
qsort (READY, NEW_READY, sizeof (rtx), rank_for_schedule); } \
while (0)
static int
rank_for_schedule (x, y)
const GENERIC_PTR x;
const GENERIC_PTR y;
{
rtx tmp = *(rtx *)y;
rtx tmp2 = *(rtx *)x;
rtx link;
int tmp_class, tmp2_class;
int value;
if ((value = INSN_PRIORITY (tmp) - INSN_PRIORITY (tmp2)))
return value;
if (last_scheduled_insn)
{
link = find_insn_list (tmp, LOG_LINKS (last_scheduled_insn));
if (link == 0 || insn_cost (tmp, link, last_scheduled_insn) == 1)
tmp_class = 3;
else if (REG_NOTE_KIND (link) == 0)
tmp_class = 1;
else
tmp_class = 2;
link = find_insn_list (tmp2, LOG_LINKS (last_scheduled_insn));
if (link == 0 || insn_cost (tmp2, link, last_scheduled_insn) == 1)
tmp2_class = 3;
else if (REG_NOTE_KIND (link) == 0)
tmp2_class = 1;
else
tmp2_class = 2;
if ((value = tmp_class - tmp2_class))
return value;
}
return INSN_LUID (tmp) - INSN_LUID (tmp2);
}
__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;
}
static int max_priority;
__inline static void
queue_insn (insn, n_cycles)
rtx insn;
int n_cycles;
{
int next_q = NEXT_Q_AFTER (q_ptr, n_cycles);
NEXT_INSN (insn) = insn_queue[next_q];
insn_queue[next_q] = insn;
q_size += 1;
}
__inline static int
birthing_insn_p (pat)
rtx pat;
{
int j;
if (reload_completed == 1)
return 0;
if (GET_CODE (pat) == SET
&& GET_CODE (SET_DEST (pat)) == REG)
{
rtx dest = SET_DEST (pat);
int i = REGNO (dest);
if (REGNO_REG_SET_P (bb_live_regs, i))
return (REG_N_SETS (i) == 1);
return 0;
}
if (GET_CODE (pat) == PARALLEL)
{
for (j = 0; j < XVECLEN (pat, 0); j++)
if (birthing_insn_p (XVECEXP (pat, 0, j)))
return 1;
}
return 0;
}
__inline static void
adjust_priority (prev)
rtx prev;
{
if (reload_completed == 0)
{
rtx note;
int n_deaths = 0;
for (note = REG_NOTES (prev); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_DEAD)
n_deaths += 1;
switch (n_deaths)
{
default:
INSN_PRIORITY (prev) >>= 3;
break;
case 3:
INSN_PRIORITY (prev) >>= 2;
break;
case 2:
case 1:
INSN_PRIORITY (prev) >>= 1;
break;
case 0:
if (birthing_insn_p (PATTERN (prev)))
{
int max = max_priority;
if (max > INSN_PRIORITY (prev))
INSN_PRIORITY (prev) = max;
}
break;
}
#ifdef ADJUST_PRIORITY
ADJUST_PRIORITY (prev);
#endif
}
}
static int
schedule_insn (insn, ready, n_ready, clock)
rtx insn;
rtx *ready;
int n_ready;
int clock;
{
rtx link;
int new_ready = n_ready;
if (MAX_BLOCKAGE > 1)
schedule_unit (insn_unit (insn), insn, clock);
if (LOG_LINKS (insn) == 0)
return n_ready;
if (n_ready > 0)
max_priority = MAX (INSN_PRIORITY (ready[0]), INSN_PRIORITY (insn));
else
max_priority = INSN_PRIORITY (insn);
for (link = LOG_LINKS (insn); link != 0; link = XEXP (link, 1))
{
rtx prev = XEXP (link, 0);
int cost = insn_cost (prev, link, insn);
if ((INSN_REF_COUNT (prev) -= 1) != 0)
{
if (cost > 1)
INSN_TICK (prev) = MAX (INSN_TICK (prev), clock + cost);
}
else
{
if (INSN_TICK (prev) - clock > cost)
cost = INSN_TICK (prev) - clock;
adjust_priority (prev);
if (cost <= 1)
ready[new_ready++] = prev;
else
queue_insn (prev, cost);
}
}
return new_ready;
}
static int
schedule_select (ready, n_ready, clock, file)
rtx *ready;
int n_ready, clock;
FILE *file;
{
int pri = INSN_PRIORITY (ready[0]);
int i, j, k, q, cost, best_cost, best_insn = 0, new_ready = n_ready;
rtx insn;
for (i = 0; i < n_ready; i = j)
{
int opri = pri;
for (j = i + 1; j < n_ready; j++)
if ((pri = INSN_PRIORITY (ready[j])) != opri)
break;
for (k = i, q = 0; k < j; k++)
{
insn = ready[k];
if ((cost = actual_hazard (insn_unit (insn), insn, clock, 0)) != 0)
{
q++;
ready[k] = 0;
queue_insn (insn, cost);
if (file)
fprintf (file, "\n;; blocking insn %d for %d cycles",
INSN_UID (insn), cost);
}
}
new_ready -= q;
if (j - i - q == 0)
continue;
else if (j - i - q > 1)
{
best_cost = -1;
for (k = i; k < j; k++)
{
if ((insn = ready[k]) == 0)
continue;
if ((cost = potential_hazard (insn_unit (insn), insn, 0))
> best_cost)
{
best_cost = cost;
best_insn = k;
}
}
}
break;
}
if (best_insn != 0)
{
if (file)
{
fprintf (file, ", now");
for (i = 0; i < n_ready; i++)
if (ready[i])
fprintf (file, " %d", INSN_UID (ready[i]));
fprintf (file, "\n;; insn %d has a greater potential hazard",
INSN_UID (ready[best_insn]));
}
for (i = best_insn; i > 0; i--)
{
insn = ready[i-1];
ready[i-1] = ready[i];
ready[i] = insn;
}
}
if (new_ready < n_ready)
for (i = j = 0; i < n_ready; i++)
if (ready[i])
ready[j++] = ready[i];
return new_ready;
}
static void
create_reg_dead_note (reg, insn)
rtx reg, insn;
{
rtx link;
if (dead_notes == 0)
{
#if 1
abort ();
#else
link = rtx_alloc (EXPR_LIST);
PUT_REG_NOTE_KIND (link, REG_DEAD);
#endif
}
else
{
int regs_killed = (REGNO (reg) >= FIRST_PSEUDO_REGISTER ? 1
: HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg)));
int reg_note_regs;
link = dead_notes;
reg_note_regs = (REGNO (XEXP (link, 0)) >= FIRST_PSEUDO_REGISTER ? 1
: HARD_REGNO_NREGS (REGNO (XEXP (link, 0)),
GET_MODE (XEXP (link, 0))));
while (reg_note_regs < regs_killed)
{
if (link == NULL_RTX)
abort ();
link = XEXP (link, 1);
reg_note_regs += (REGNO (XEXP (link, 0)) >= FIRST_PSEUDO_REGISTER ? 1
: HARD_REGNO_NREGS (REGNO (XEXP (link, 0)),
GET_MODE (XEXP (link, 0))));
}
dead_notes = XEXP (link, 1);
while (reg_note_regs > regs_killed)
{
rtx temp_reg, temp_link;
temp_reg = gen_rtx_REG (word_mode, 0);
temp_link = rtx_alloc (EXPR_LIST);
PUT_REG_NOTE_KIND (temp_link, REG_DEAD);
XEXP (temp_link, 0) = temp_reg;
XEXP (temp_link, 1) = dead_notes;
dead_notes = temp_link;
reg_note_regs--;
}
}
XEXP (link, 0) = reg;
XEXP (link, 1) = REG_NOTES (insn);
REG_NOTES (insn) = link;
}
static void
attach_deaths (x, insn, set_p)
rtx x;
rtx insn;
int set_p;
{
register int i;
register int j;
register enum rtx_code code;
register char *fmt;
if (x == 0)
return;
code = GET_CODE (x);
switch (code)
{
case CONST_INT:
case CONST_DOUBLE:
case LABEL_REF:
case SYMBOL_REF:
case CONST:
case CODE_LABEL:
case PC:
case CC0:
return;
case REG:
{
register int regno;
int some_needed;
int all_needed;
if (set_p)
return;
regno = REGNO (x);
all_needed = some_needed = REGNO_REG_SET_P (old_live_regs, regno);
if (regno < FIRST_PSEUDO_REGISTER)
{
int n;
n = HARD_REGNO_NREGS (regno, GET_MODE (x));
while (--n > 0)
{
int needed = (REGNO_REG_SET_P (old_live_regs, regno + n));
some_needed |= needed;
all_needed &= needed;
}
}
if (regno >= FIRST_PSEUDO_REGISTER || ! global_regs[regno])
{
if (! (regno == FRAME_POINTER_REGNUM
&& (! reload_completed || frame_pointer_needed))
#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
&& ! (regno == HARD_FRAME_POINTER_REGNUM
&& (! reload_completed || frame_pointer_needed))
#endif
#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
&& ! (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
#endif
&& regno != STACK_POINTER_REGNUM)
{
if (! all_needed && ! dead_or_set_p (insn, x))
{
if (regno < FIRST_PSEUDO_REGISTER
&& HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
{
int n = HARD_REGNO_NREGS (regno, GET_MODE (x));
while (--n >= 0)
some_needed |= dead_or_set_regno_p (insn, regno + n);
}
if (! some_needed)
create_reg_dead_note (x, insn);
else
{
int i;
for (i = HARD_REGNO_NREGS (regno, GET_MODE (x)) - 1;
i >= 0; i--)
if (! REGNO_REG_SET_P (old_live_regs, regno + i)
&& ! dead_or_set_regno_p (insn, regno + i))
create_reg_dead_note (gen_rtx_REG (reg_raw_mode[regno + i],
regno + i),
insn);
}
}
}
if (regno < FIRST_PSEUDO_REGISTER)
{
int j = HARD_REGNO_NREGS (regno, GET_MODE (x));
while (--j >= 0)
{
CLEAR_REGNO_REG_SET (bb_dead_regs, regno + j);
SET_REGNO_REG_SET (bb_live_regs, regno + j);
}
}
else
{
CLEAR_REGNO_REG_SET (bb_dead_regs, regno);
SET_REGNO_REG_SET (bb_live_regs, regno);
}
}
return;
}
case MEM:
attach_deaths (XEXP (x, 0), insn, 0);
return;
case SUBREG:
attach_deaths (SUBREG_REG (x), insn,
set_p && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
<= UNITS_PER_WORD)
|| (GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
== GET_MODE_SIZE (GET_MODE ((x))))));
return;
case STRICT_LOW_PART:
attach_deaths (XEXP (x, 0), insn, 0);
return;
case ZERO_EXTRACT:
case SIGN_EXTRACT:
attach_deaths (XEXP (x, 0), insn, 0);
attach_deaths (XEXP (x, 1), insn, 0);
attach_deaths (XEXP (x, 2), insn, 0);
return;
default:
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
attach_deaths (XEXP (x, i), insn, 0);
else if (fmt[i] == 'E')
for (j = 0; j < XVECLEN (x, i); j++)
attach_deaths (XVECEXP (x, i, j), insn, 0);
}
}
}
static void
attach_deaths_insn (insn)
rtx insn;
{
rtx x = PATTERN (insn);
register RTX_CODE code = GET_CODE (x);
rtx link;
if (code == SET)
{
attach_deaths (SET_SRC (x), insn, 0);
attach_deaths (SET_DEST (x), insn, 1);
}
else if (code == PARALLEL)
{
register int i;
for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
{
code = GET_CODE (XVECEXP (x, 0, i));
if (code == SET)
{
attach_deaths (SET_SRC (XVECEXP (x, 0, i)), insn, 0);
attach_deaths (SET_DEST (XVECEXP (x, 0, i)), insn, 1);
}
else if (code != CLOBBER)
attach_deaths (XVECEXP (x, 0, i), insn, 0);
}
}
else if (code == CLOBBER && GET_CODE (XEXP (x, 0)) == MEM)
attach_deaths (XEXP (XEXP (x, 0), 0), insn, 0);
else if (code != CLOBBER)
attach_deaths (x, insn, 0);
if (GET_CODE (insn) == CALL_INSN)
for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
attach_deaths (XEXP (XEXP (link, 0), 0), insn,
GET_CODE (XEXP (link, 0)) == CLOBBER);
}
static rtx
unlink_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 (write_symbols != NO_DEBUG && NOTE_LINE_NUMBER (insn) > 0)
LINE_NOTE (insn) = insn;
else if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_SETJMP
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_RANGE_START
&& 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 int
new_sometimes_live (regs_sometimes_live, regno, sometimes_max)
struct sometimes *regs_sometimes_live;
int regno;
int sometimes_max;
{
register struct sometimes *p;
if (regno >= max_regno)
abort ();
p = ®s_sometimes_live[sometimes_max];
p->regno = regno;
p->live_length = 0;
p->calls_crossed = 0;
sometimes_max++;
return sometimes_max;
}
static void
finish_sometimes_live (regs_sometimes_live, sometimes_max)
struct sometimes *regs_sometimes_live;
int sometimes_max;
{
int i;
for (i = 0; i < sometimes_max; i++)
{
register struct sometimes *p = ®s_sometimes_live[i];
int regno = p->regno;
sched_reg_live_length[regno] += p->live_length;
sched_reg_n_calls_crossed[regno] += p->calls_crossed;
}
}
static rtx
reemit_notes (insn, last)
rtx insn;
rtx last;
{
rtx note;
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
{
if (REG_NOTE_KIND (note) == REG_DEAD
&& GET_CODE (XEXP (note, 0)) == CONST_INT)
{
if (INTVAL (XEXP (note, 0)) == NOTE_INSN_SETJMP)
{
CONST_CALL_P (emit_note_after (INTVAL (XEXP (note, 0)), insn))
= CONST_CALL_P (note);
remove_note (insn, note);
note = XEXP (note, 1);
}
else
{
last = emit_note_before (INTVAL (XEXP (note, 0)), last);
remove_note (insn, note);
note = XEXP (note, 1);
NOTE_BLOCK_NUMBER (last) = INTVAL (XEXP (note, 0));
}
remove_note (insn, note);
}
}
return last;
}
static void
schedule_block (b, file)
int b;
FILE *file;
{
rtx insn, last;
rtx *ready, link;
int i, j, n_ready = 0, new_ready, n_insns;
int sched_n_insns = 0;
int clock;
#define NEED_NOTHING 0
#define NEED_HEAD 1
#define NEED_TAIL 2
int new_needs;
rtx head = BLOCK_HEAD (b);
rtx tail = BLOCK_END (b);
rtx next_tail;
rtx prev_head;
register struct sometimes *regs_sometimes_live;
int sometimes_max;
if (file)
fprintf (file, ";;\t -- basic block number %d from %d to %d --\n",
b, INSN_UID (BLOCK_HEAD (b)), INSN_UID (BLOCK_END (b)));
i = max_reg_num ();
reg_last_uses = (rtx *) alloca (i * sizeof (rtx));
bzero ((char *) reg_last_uses, i * sizeof (rtx));
reg_last_sets = (rtx *) alloca (i * sizeof (rtx));
bzero ((char *) reg_last_sets, i * sizeof (rtx));
reg_pending_sets = ALLOCA_REG_SET ();
CLEAR_REG_SET (reg_pending_sets);
reg_pending_sets_all = 0;
clear_units ();
#if 0
if (reload_completed == 0 && b == 0)
{
while (head != tail
&& GET_CODE (head) == NOTE
&& NOTE_LINE_NUMBER (head) != NOTE_INSN_FUNCTION_BEG)
head = NEXT_INSN (head);
while (head != tail
&& GET_CODE (head) == INSN
&& GET_CODE (PATTERN (head)) == SET)
{
rtx src = SET_SRC (PATTERN (head));
while (GET_CODE (src) == SUBREG
|| GET_CODE (src) == SIGN_EXTEND
|| GET_CODE (src) == ZERO_EXTEND
|| GET_CODE (src) == SIGN_EXTRACT
|| GET_CODE (src) == ZERO_EXTRACT)
src = XEXP (src, 0);
if (GET_CODE (src) != REG
|| REGNO (src) >= FIRST_PSEUDO_REGISTER)
break;
INSN_REF_COUNT (head) = 1;
head = NEXT_INSN (head);
}
}
#endif
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;
}
if (head == tail
&& (GET_CODE (head) == NOTE || GET_CODE (head) == CODE_LABEL))
goto ret;
#if 0
if (head == tail)
goto ret;
#endif
prev_head = PREV_INSN (head);
next_tail = NEXT_INSN (tail);
dead_notes = 0;
pending_read_insns = 0;
pending_read_mems = 0;
pending_write_insns = 0;
pending_write_mems = 0;
pending_lists_length = 0;
last_pending_memory_flush = 0;
last_function_call = 0;
last_scheduled_insn = 0;
LOG_LINKS (sched_before_next_call) = 0;
n_insns = sched_analyze (head, tail);
if (n_insns == 0)
{
free_pending_lists ();
goto ret;
}
ready = (rtx *) alloca ((n_insns+1) * sizeof (rtx));
insn = tail;
last = 0;
while (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN
|| (GET_CODE (insn) == INSN
&& (GET_CODE (PATTERN (insn)) == USE
#ifdef HAVE_cc0
|| sets_cc0_p (PATTERN (insn))
#endif
))
|| GET_CODE (insn) == NOTE)
{
if (GET_CODE (insn) != NOTE)
{
priority (insn);
if (last == 0)
{
ready[n_ready++] = insn;
INSN_PRIORITY (insn) = TAIL_PRIORITY - i;
INSN_REF_COUNT (insn) = 0;
}
else if (! find_insn_list (insn, LOG_LINKS (last)))
{
add_dependence (last, insn, REG_DEP_ANTI);
INSN_REF_COUNT (insn)++;
}
last = insn;
while (SCHED_GROUP_P (insn))
{
insn = prev_nonnote_insn (insn);
priority (insn);
}
}
insn = PREV_INSN (insn);
if (insn == prev_head)
break;
}
#if 0
i = reload_completed ? DONE_PRIORITY : MAX_PRIORITY;
#endif
for (; insn != prev_head; insn = PREV_INSN (insn))
{
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
priority (insn);
if (INSN_REF_COUNT (insn) == 0)
{
if (last == 0)
ready[n_ready++] = insn;
else
{
add_dependence (last, insn, REG_DEP_ANTI);
INSN_REF_COUNT (insn) = 1;
}
}
if (SCHED_GROUP_P (insn))
{
while (SCHED_GROUP_P (insn))
{
insn = prev_nonnote_insn (insn);
priority (insn);
}
continue;
}
#if 0
if (i < 0)
continue;
if (INSN_PRIORITY (insn) < i)
i = INSN_PRIORITY (insn);
else if (INSN_PRIORITY (insn) > i)
i = DONE_PRIORITY;
#endif
}
}
#if 0
if (i != DONE_PRIORITY)
{
if (file)
fprintf (file, ";; already scheduled\n");
if (reload_completed == 0)
{
for (i = 0; i < sometimes_max; i++)
regs_sometimes_live[i].live_length += n_insns;
finish_sometimes_live (regs_sometimes_live, sometimes_max);
}
free_pending_lists ();
goto ret;
}
#endif
if (reload_completed == 0)
{
COPY_REG_SET (bb_live_regs, BASIC_BLOCK (b)->global_live_at_start);
CLEAR_REG_SET (bb_dead_regs);
if (b == 0)
{
for (insn = BLOCK_HEAD (b); insn != head;
insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
if (GET_CODE (PATTERN (insn)) == SET
|| GET_CODE (PATTERN (insn)) == CLOBBER)
sched_note_set (PATTERN (insn), 0);
else if (GET_CODE (PATTERN (insn)) == PARALLEL)
{
int j;
for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET
|| GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == CLOBBER)
sched_note_set (XVECEXP (PATTERN (insn), 0, j), 0);
for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == USE)
sched_note_set (XVECEXP (PATTERN (insn), 0, j), 0);
}
if (GET_CODE (insn) == CALL_INSN)
{
int j;
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
if (call_used_regs[j] && ! global_regs[j]
&& ! fixed_regs[j])
{
SET_REGNO_REG_SET (bb_live_regs, j);
CLEAR_REGNO_REG_SET (bb_dead_regs, j);
}
}
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
{
if ((REG_NOTE_KIND (link) == REG_DEAD
|| REG_NOTE_KIND (link) == REG_UNUSED)
&& GET_CODE (XEXP (link, 0)) == REG)
{
register int regno = REGNO (XEXP (link, 0));
if (regno < FIRST_PSEUDO_REGISTER)
{
int j = HARD_REGNO_NREGS (regno,
GET_MODE (XEXP (link, 0)));
while (--j >= 0)
{
CLEAR_REGNO_REG_SET (bb_live_regs, regno + j);
SET_REGNO_REG_SET (bb_dead_regs, regno + j);
}
}
else
{
CLEAR_REGNO_REG_SET (bb_live_regs, regno);
SET_REGNO_REG_SET (bb_dead_regs, regno);
}
}
}
}
}
}
if (write_symbols != NO_DEBUG)
{
rtx line = line_note_head[b];
for (insn = BLOCK_HEAD (b);
insn != next_tail;
insn = NEXT_INSN (insn))
if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
line = insn;
else
LINE_NOTE (insn) = line;
}
for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
{
rtx prev, next, link;
if (GET_CODE (insn) == NOTE)
{
prev = insn;
insn = unlink_notes (insn, next_tail);
if (prev == tail)
abort ();
if (prev == head)
abort ();
if (insn == next_tail)
abort ();
}
if (reload_completed == 0
&& GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
if (GET_CODE (PATTERN (insn)) == SET
|| GET_CODE (PATTERN (insn)) == CLOBBER)
sched_note_set (PATTERN (insn), 0);
else if (GET_CODE (PATTERN (insn)) == PARALLEL)
{
int j;
for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET
|| GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == CLOBBER)
sched_note_set (XVECEXP (PATTERN (insn), 0, j), 0);
for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == USE)
sched_note_set (XVECEXP (PATTERN (insn), 0, j), 0);
}
if (GET_CODE (insn) == CALL_INSN)
{
int j;
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
if (call_used_regs[j] && ! global_regs[j]
&& ! fixed_regs[j])
{
SET_REGNO_REG_SET (bb_live_regs, j);
CLEAR_REGNO_REG_SET (bb_dead_regs, j);
}
}
for (prev = 0, link = REG_NOTES (insn); link; link = next)
{
next = XEXP (link, 1);
if ((REG_NOTE_KIND (link) == REG_DEAD
|| REG_NOTE_KIND (link) == REG_UNUSED)
&& GET_CODE (XEXP (link, 0)) == REG)
{
register int regno = REGNO (XEXP (link, 0));
if (REG_NOTE_KIND (link) == REG_DEAD)
{
if (prev)
XEXP (prev, 1) = next;
else
REG_NOTES (insn) = next;
XEXP (link, 1) = dead_notes;
dead_notes = link;
}
else
prev = link;
if (regno < FIRST_PSEUDO_REGISTER)
{
int j = HARD_REGNO_NREGS (regno,
GET_MODE (XEXP (link, 0)));
while (--j >= 0)
{
CLEAR_REGNO_REG_SET (bb_live_regs, regno + j);
SET_REGNO_REG_SET (bb_dead_regs, regno + j);
}
}
else
{
CLEAR_REGNO_REG_SET (bb_live_regs, regno);
SET_REGNO_REG_SET (bb_dead_regs, regno);
}
}
else
prev = link;
}
}
}
if (reload_completed == 0)
{
old_live_regs = ALLOCA_REG_SET ();
regs_sometimes_live
= (struct sometimes *) alloca (max_regno * sizeof (struct sometimes));
sometimes_max = 0;
COPY_REG_SET (old_live_regs, bb_live_regs);
EXECUTE_IF_SET_IN_REG_SET (bb_live_regs, 0, j,
{
sometimes_max
= new_sometimes_live (regs_sometimes_live,
j, sometimes_max);
});
}
SCHED_SORT (ready, n_ready, 1);
if (file)
{
fprintf (file, ";; ready list initially:\n;; ");
for (i = 0; i < n_ready; i++)
fprintf (file, "%d ", INSN_UID (ready[i]));
fprintf (file, "\n\n");
for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
if (INSN_PRIORITY (insn) > 0)
fprintf (file, ";; insn[%4d]: priority = %4d, ref_count = %4d\n",
INSN_UID (insn), INSN_PRIORITY (insn),
INSN_REF_COUNT (insn));
}
tail = 0;
q_ptr = 0; clock = 0;
bzero ((char *) insn_queue, sizeof (insn_queue));
last = next_tail;
new_needs = (NEXT_INSN (prev_head) == BLOCK_HEAD (b)
? NEED_HEAD : NEED_NOTHING);
if (PREV_INSN (next_tail) == BLOCK_END (b))
new_needs |= NEED_TAIL;
new_ready = n_ready;
while (sched_n_insns < n_insns)
{
q_ptr = NEXT_Q (q_ptr); clock++;
for (insn = insn_queue[q_ptr]; insn; insn = NEXT_INSN (insn))
{
if (file)
fprintf (file, ";; launching %d before %d with no stalls at T-%d\n",
INSN_UID (insn), INSN_UID (last), clock);
ready[new_ready++] = insn;
q_size -= 1;
}
insn_queue[q_ptr] = 0;
if (new_ready == 0)
{
register int stalls;
for (stalls = 1; stalls < INSN_QUEUE_SIZE; stalls++)
if ((insn = insn_queue[NEXT_Q_AFTER (q_ptr, stalls)]))
{
for (; insn; insn = NEXT_INSN (insn))
{
if (file)
fprintf (file, ";; launching %d before %d with %d stalls at T-%d\n",
INSN_UID (insn), INSN_UID (last), stalls, clock);
ready[new_ready++] = insn;
q_size -= 1;
}
insn_queue[NEXT_Q_AFTER (q_ptr, stalls)] = 0;
break;
}
q_ptr = NEXT_Q_AFTER (q_ptr, stalls); clock += stalls;
}
if (new_ready == 0)
abort ();
if (file)
{
fprintf (file, ";; ready list at T-%d:", clock);
for (i = 0; i < new_ready; i++)
fprintf (file, " %d (%x)",
INSN_UID (ready[i]), INSN_PRIORITY (ready[i]));
}
SCHED_SORT (ready, new_ready, n_ready);
if (MAX_BLOCKAGE > 1)
{
new_ready = schedule_select (ready, new_ready, clock, file);
if (new_ready == 0)
{
if (file)
fprintf (file, "\n");
n_ready = 0;
continue;
}
}
n_ready = new_ready;
last_scheduled_insn = insn = ready[0];
if (tail == 0)
tail = insn;
if (file)
{
fprintf (file, ", now");
for (i = 0; i < n_ready; i++)
fprintf (file, " %d", INSN_UID (ready[i]));
fprintf (file, "\n");
}
if (DONE_PRIORITY_P (insn))
abort ();
if (reload_completed == 0)
{
do
{
if (GET_CODE (PATTERN (insn)) == SET
|| GET_CODE (PATTERN (insn)) == CLOBBER)
sched_note_set (PATTERN (insn), 1);
else if (GET_CODE (PATTERN (insn)) == PARALLEL)
{
int j;
for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET
|| GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == CLOBBER)
sched_note_set (XVECEXP (PATTERN (insn), 0, j), 1);
}
if (GET_CODE (insn) == CALL_INSN)
{
register struct sometimes *p;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (call_used_regs[i] && ! global_regs[i]
&& ! fixed_regs[i])
{
CLEAR_REGNO_REG_SET (bb_live_regs, i);
SET_REGNO_REG_SET (bb_dead_regs, i);
}
p = regs_sometimes_live;
for (i = 0; i < sometimes_max; i++, p++)
if (REGNO_REG_SET_P (bb_live_regs, p->regno))
p->calls_crossed += 1;
}
attach_deaths_insn (insn);
EXECUTE_IF_AND_COMPL_IN_REG_SET (bb_live_regs, old_live_regs, 0, i,
{
sometimes_max
= new_sometimes_live (regs_sometimes_live,
i, sometimes_max);
});
IOR_REG_SET (old_live_regs, bb_live_regs);
for (i = 0; i < sometimes_max; i++)
{
register struct sometimes *p = ®s_sometimes_live[i];
int regno = p->regno;
p->live_length += 1;
if (!REGNO_REG_SET_P (bb_live_regs, p->regno))
{
sched_reg_live_length[regno] += p->live_length;
sched_reg_n_calls_crossed[regno] += p->calls_crossed;
CLEAR_REGNO_REG_SET (old_live_regs, p->regno);
*p = regs_sometimes_live[--sometimes_max];
i--;
}
}
link = insn;
insn = PREV_INSN (insn);
}
while (SCHED_GROUP_P (link));
insn = ready[0];
}
ready += 1;
n_ready -= 1;
sched_n_insns += 1;
NEXT_INSN (insn) = last;
PREV_INSN (last) = insn;
INSN_PRIORITY (insn) = LAUNCH_PRIORITY;
new_ready = schedule_insn (insn, ready, n_ready, clock);
INSN_PRIORITY (insn) = DONE_PRIORITY;
if (SCHED_GROUP_P (insn))
{
link = insn;
while (SCHED_GROUP_P (link))
{
link = PREV_INSN (link);
INSN_REF_COUNT (link) = 0;
}
link = insn;
while (SCHED_GROUP_P (link))
{
link = PREV_INSN (link);
sched_n_insns += 1;
new_ready = schedule_insn (link, ready, new_ready, clock);
INSN_PRIORITY (link) = DONE_PRIORITY;
}
}
last = NEXT_INSN (insn);
do
{
insn = PREV_INSN (last);
if (! SCHED_GROUP_P (insn))
{
NEXT_INSN (prev_head) = insn;
PREV_INSN (insn) = prev_head;
}
last = reemit_notes (insn, insn);
}
while (SCHED_GROUP_P (insn));
}
if (q_size != 0)
abort ();
if (reload_completed == 0)
finish_sometimes_live (regs_sometimes_live, sometimes_max);
head = last;
if (note_list != 0)
{
rtx note_head = note_list;
while (PREV_INSN (note_head))
note_head = PREV_INSN (note_head);
PREV_INSN (head) = note_list;
NEXT_INSN (note_list) = head;
head = note_head;
}
#if 1
if (dead_notes != 0)
abort ();
#endif
if (new_needs & NEED_HEAD)
BLOCK_HEAD (b) = head;
PREV_INSN (head) = prev_head;
NEXT_INSN (prev_head) = head;
if (new_needs & NEED_TAIL)
BLOCK_END (b) = tail;
NEXT_INSN (tail) = next_tail;
PREV_INSN (next_tail) = tail;
if (write_symbols != NO_DEBUG)
{
rtx line, note, prev, new;
int notes = 0;
head = BLOCK_HEAD (b);
next_tail = NEXT_INSN (BLOCK_END (b));
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
&& (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
{
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 (file && notes)
fprintf (file, ";; added %d line-number notes\n", notes);
}
if (file)
{
fprintf (file, ";; total time = %d\n;; new basic block head = %d\n;; new basic block end = %d\n\n",
clock, INSN_UID (BLOCK_HEAD (b)), INSN_UID (BLOCK_END (b)));
}
free_pending_lists ();
ret:
FREE_REG_SET (reg_pending_sets);
FREE_REG_SET (old_live_regs);
return;
}
static void
split_hard_reg_notes (note, first, last)
rtx note, first, last;
{
rtx reg, temp, link;
int n_regs, i, new_reg;
rtx insn;
if (REG_NOTE_KIND (note) != REG_DEAD)
abort ();
reg = XEXP (note, 0);
n_regs = HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg));
for (i = 0; i < n_regs; i++)
{
new_reg = REGNO (reg) + i;
for (insn = last; ; insn = PREV_INSN (insn))
{
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& (temp = regno_use_in (new_reg, PATTERN (insn))))
{
link = rtx_alloc (EXPR_LIST);
PUT_REG_NOTE_KIND (link, REG_DEAD);
XEXP (link, 0) = temp;
XEXP (link, 1) = REG_NOTES (insn);
REG_NOTES (insn) = link;
i += HARD_REGNO_NREGS (REGNO (temp), GET_MODE (temp)) - 1;
break;
}
if (insn == first)
break;
}
}
}
static void
new_insn_dead_notes (pat, insn, last, orig_insn)
rtx pat, insn, last, orig_insn;
{
rtx dest, tem, set;
dest = XEXP (pat, 0);
while (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == STRICT_LOW_PART
|| GET_CODE (dest) == SIGN_EXTRACT)
dest = XEXP (dest, 0);
if (GET_CODE (dest) == REG)
{
if (reg_referenced_p (dest, PATTERN (orig_insn)))
return;
for (tem = last; tem != insn; tem = PREV_INSN (tem))
{
if (GET_RTX_CLASS (GET_CODE (tem)) == 'i'
&& reg_overlap_mentioned_p (dest, PATTERN (tem))
&& (set = single_set (tem)))
{
rtx tem_dest = SET_DEST (set);
while (GET_CODE (tem_dest) == ZERO_EXTRACT
|| GET_CODE (tem_dest) == SUBREG
|| GET_CODE (tem_dest) == STRICT_LOW_PART
|| GET_CODE (tem_dest) == SIGN_EXTRACT)
tem_dest = XEXP (tem_dest, 0);
if (! rtx_equal_p (tem_dest, dest))
{
if (! find_regno_note (tem, REG_UNUSED, REGNO (dest))
&& ! find_regno_note (tem, REG_DEAD, REGNO (dest)))
{
rtx note = rtx_alloc (EXPR_LIST);
PUT_REG_NOTE_KIND (note, REG_DEAD);
XEXP (note, 0) = dest;
XEXP (note, 1) = REG_NOTES (tem);
REG_NOTES (tem) = note;
}
break;
}
else if (reg_overlap_mentioned_p (dest, SET_SRC (set)))
break;
}
}
if (tem == insn)
{
int live_after_orig_insn = 0;
rtx pattern = PATTERN (orig_insn);
int i;
if (GET_CODE (pat) == CLOBBER)
{
rtx note = rtx_alloc (EXPR_LIST);
PUT_REG_NOTE_KIND (note, REG_UNUSED);
XEXP (note, 0) = dest;
XEXP (note, 1) = REG_NOTES (insn);
REG_NOTES (insn) = note;
return;
}
if (GET_CODE (pattern) == SET)
{
if (reg_overlap_mentioned_p (dest, SET_DEST (pattern)))
live_after_orig_insn = 1;
}
else if (GET_CODE (pattern) == PARALLEL)
{
for (i = 0; i < XVECLEN (pattern, 0); i++)
if (GET_CODE (XVECEXP (pattern, 0, i)) == SET
&& reg_overlap_mentioned_p (dest,
SET_DEST (XVECEXP (pattern,
0, i))))
live_after_orig_insn = 1;
}
if (! live_after_orig_insn)
abort ();
}
}
}
static void
update_n_sets (x, inc)
rtx x;
int inc;
{
rtx dest = SET_DEST (x);
while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT)
dest = SUBREG_REG (dest);
if (GET_CODE (dest) == REG)
{
int regno = REGNO (dest);
if (regno < FIRST_PSEUDO_REGISTER)
{
register int i;
int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (dest));
for (i = regno; i < endregno; i++)
REG_N_SETS (i) += inc;
}
else
REG_N_SETS (regno) += inc;
}
}
void
update_flow_info (notes, first, last, orig_insn)
rtx notes;
rtx first, last;
rtx orig_insn;
{
rtx insn, note;
rtx next;
rtx orig_dest, temp;
rtx set;
orig_dest = single_set (orig_insn);
if (orig_dest)
orig_dest = SET_DEST (orig_dest);
for (note = notes; note; note = next)
{
next = XEXP (note, 1);
switch (REG_NOTE_KIND (note))
{
case REG_DEAD:
case REG_UNUSED:
for (insn = last; ; insn = PREV_INSN (insn))
{
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
{
temp = XEXP (note, 0);
if (REG_NOTE_KIND (note) == REG_DEAD
&& GET_CODE (temp) == REG
&& REGNO (temp) < FIRST_PSEUDO_REGISTER
&& HARD_REGNO_NREGS (REGNO (temp), GET_MODE (temp)) > 1)
split_hard_reg_notes (note, first, last);
else
{
XEXP (note, 1) = REG_NOTES (insn);
REG_NOTES (insn) = note;
}
if (REG_NOTE_KIND (note) == REG_UNUSED
&& GET_CODE (XEXP (note, 0)) != SCRATCH
&& ! dead_or_set_p (insn, XEXP (note, 0)))
PUT_REG_NOTE_KIND (note, REG_DEAD);
break;
}
if (insn == first)
{
if (REG_NOTE_KIND (note) != REG_UNUSED)
abort ();
break;
}
}
break;
case REG_WAS_0:
if (GET_CODE (XEXP (note, 0)) == NOTE
|| INSN_DELETED_P (XEXP (note, 0)))
break;
if (! orig_dest)
abort ();
for (insn = first; ; insn = NEXT_INSN (insn))
{
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& (temp = single_set (insn))
&& rtx_equal_p (SET_DEST (temp), orig_dest))
{
XEXP (note, 1) = REG_NOTES (insn);
REG_NOTES (insn) = note;
break;
}
if (GET_CODE (orig_dest) == REG
&& REGNO (orig_dest) < FIRST_PSEUDO_REGISTER
&& HARD_REGNO_NREGS (REGNO (orig_dest),
GET_MODE (orig_dest)) > 1)
break;
if (insn == last)
abort ();
}
break;
case REG_EQUAL:
case REG_EQUIV:
if (! orig_dest)
break;
case REG_NO_CONFLICT:
if (! orig_dest)
abort ();
for (insn = last; ; insn = PREV_INSN (insn))
{
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& (temp = single_set (insn))
&& rtx_equal_p (SET_DEST (temp), orig_dest))
{
XEXP (note, 1) = REG_NOTES (insn);
REG_NOTES (insn) = note;
break;
}
if (insn == first)
{
if (GET_CODE (orig_dest) == REG
&& REGNO (orig_dest) < FIRST_PSEUDO_REGISTER
&& HARD_REGNO_NREGS (REGNO (orig_dest),
GET_MODE (orig_dest)) > 1)
break;
if (GET_CODE (orig_dest) == MEM
&& SIZE_FOR_MODE (orig_dest) > MOVE_MAX)
break;
abort ();
}
}
break;
case REG_LIBCALL:
XEXP (note, 1) = REG_NOTES (first);
REG_NOTES (first) = note;
insn = XEXP (note, 0);
note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
if (note)
XEXP (note, 0) = first;
break;
case REG_EXEC_COUNT:
XEXP (note, 1) = REG_NOTES (first);
REG_NOTES (first) = note;
break;
case REG_RETVAL:
XEXP (note, 1) = REG_NOTES (last);
REG_NOTES (last) = note;
insn = XEXP (note, 0);
note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
if (note)
XEXP (note, 0) = last;
break;
case REG_NONNEG:
case REG_BR_PROB:
for (insn = last; ; insn = PREV_INSN (insn))
{
if (GET_CODE (insn) == JUMP_INSN)
{
XEXP (note, 1) = REG_NOTES (insn);
REG_NOTES (insn) = note;
break;
}
if (insn == first)
abort ();
}
break;
case REG_INC:
if (reload_completed)
break;
abort ();
case REG_LABEL:
for (insn = first; insn != NEXT_INSN (last); insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LABEL,
XEXP (note, 0),
REG_NOTES (insn));
break;
case REG_CC_SETTER:
case REG_CC_USER:
default:
abort ();
}
}
for (insn = first; insn != last; insn = NEXT_INSN (insn))
{
rtx pat;
int i;
pat = PATTERN (insn);
if (GET_CODE (pat) == SET || GET_CODE (pat) == CLOBBER)
new_insn_dead_notes (pat, insn, last, orig_insn);
else if (GET_CODE (pat) == PARALLEL)
{
for (i = 0; i < XVECLEN (pat, 0); i++)
if (GET_CODE (XVECEXP (pat, 0, i)) == SET
|| GET_CODE (XVECEXP (pat, 0, i)) == CLOBBER)
new_insn_dead_notes (XVECEXP (pat, 0, i), insn, last, orig_insn);
}
}
set = single_set (last);
if (set)
{
rtx dest = SET_DEST (set);
while (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == STRICT_LOW_PART
|| GET_CODE (dest) == SIGN_EXTRACT)
dest = XEXP (dest, 0);
if (GET_CODE (dest) == REG
&& (REGNO (dest) >= FIRST_PSEUDO_REGISTER
|| ! global_regs[REGNO (dest)]))
{
rtx stop_insn = PREV_INSN (first);
insn = last;
if (reg_overlap_mentioned_p (dest, SET_SRC (set)))
{
for (insn = PREV_INSN (insn); insn != first;
insn = PREV_INSN (insn))
{
if ((set = single_set (insn))
&& reg_mentioned_p (dest, SET_DEST (set))
&& ! reg_overlap_mentioned_p (dest, SET_SRC (set)))
break;
}
}
for (insn = PREV_INSN (insn); insn != stop_insn;
insn = PREV_INSN (insn))
{
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& reg_mentioned_p (dest, PATTERN (insn))
&& (set = single_set (insn)))
{
rtx insn_dest = SET_DEST (set);
while (GET_CODE (insn_dest) == ZERO_EXTRACT
|| GET_CODE (insn_dest) == SUBREG
|| GET_CODE (insn_dest) == STRICT_LOW_PART
|| GET_CODE (insn_dest) == SIGN_EXTRACT)
insn_dest = XEXP (insn_dest, 0);
if (insn_dest != dest)
{
note = rtx_alloc (EXPR_LIST);
PUT_REG_NOTE_KIND (note, REG_DEAD);
XEXP (note, 0) = dest;
XEXP (note, 1) = REG_NOTES (insn);
REG_NOTES (insn) = note;
break;
}
}
}
}
}
if (orig_dest && GET_CODE (orig_dest) == REG)
{
int found_orig_dest = 0;
int found_split_dest = 0;
for (insn = first; ; insn = NEXT_INSN (insn))
{
rtx pat = PATTERN (insn);
int i = GET_CODE (pat) == PARALLEL ? XVECLEN (pat, 0) : 0;
set = pat;
for (;;)
{
if (GET_CODE (set) == SET)
{
if (GET_CODE (SET_DEST (set)) == REG
&& REGNO (SET_DEST (set)) == REGNO (orig_dest))
{
found_orig_dest = 1;
break;
}
else if (GET_CODE (SET_DEST (set)) == SUBREG
&& SUBREG_REG (SET_DEST (set)) == orig_dest)
{
found_split_dest = 1;
break;
}
}
if (--i < 0)
break;
set = XVECEXP (pat, 0, i);
}
if (insn == last)
break;
}
if (found_split_dest)
{
for (insn = first; insn; insn = PREV_INSN (insn))
{
if (GET_CODE (insn) == CODE_LABEL
|| GET_CODE (insn) == JUMP_INSN)
break;
else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& reg_mentioned_p (orig_dest, insn))
{
note = find_regno_note (insn, REG_DEAD, REGNO (orig_dest));
if (note)
remove_note (insn, note);
}
}
}
else if (! found_orig_dest)
{
int i, regno;
if (REGNO (orig_dest) >= FIRST_PSEUDO_REGISTER)
abort ();
regno = REGNO (orig_dest);
for (i = HARD_REGNO_NREGS (regno, GET_MODE (orig_dest)) - 1;
i >= 0; i--)
if (! refers_to_regno_p (regno + i, regno + i + 1, orig_insn,
NULL_PTR))
break;
if (i >= 0)
abort ();
}
}
{
rtx x = PATTERN (orig_insn);
RTX_CODE code = GET_CODE (x);
if (code == SET || code == CLOBBER)
update_n_sets (x, -1);
else if (code == PARALLEL)
{
int i;
for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
{
code = GET_CODE (XVECEXP (x, 0, i));
if (code == SET || code == CLOBBER)
update_n_sets (XVECEXP (x, 0, i), -1);
}
}
for (insn = first; ; insn = NEXT_INSN (insn))
{
x = PATTERN (insn);
code = GET_CODE (x);
if (code == SET || code == CLOBBER)
update_n_sets (x, 1);
else if (code == PARALLEL)
{
int i;
for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
{
code = GET_CODE (XVECEXP (x, 0, i));
if (code == SET || code == CLOBBER)
update_n_sets (XVECEXP (x, 0, i), 1);
}
}
if (insn == last)
break;
}
}
}
void
schedule_insns (dump_file)
FILE *dump_file;
{
int max_uid = MAX_INSNS_PER_SPLIT * (get_max_uid () + 1);
int b;
rtx insn;
if (n_basic_blocks == 0)
return;
sched_before_next_call
= gen_rtx_INSN (VOIDmode, 0, NULL_RTX, NULL_RTX,
NULL_RTX, 0, NULL_RTX, NULL_RTX);
if (reload_completed == 0 || ! flag_schedule_insns)
{
unused_insn_list = 0;
unused_expr_list = 0;
}
insn_luid = (int *) xmalloc (max_uid * sizeof (int));
insn_priority = (int *) xmalloc (max_uid * sizeof (int));
insn_tick = (int *) xmalloc (max_uid * sizeof (int));
insn_costs = (short *) xmalloc (max_uid * sizeof (short));
insn_units = (short *) xmalloc (max_uid * sizeof (short));
insn_blockage = (unsigned int *) xmalloc (max_uid * sizeof (unsigned int));
insn_ref_count = (int *) xmalloc (max_uid * sizeof (int));
if (reload_completed == 0)
{
sched_reg_n_calls_crossed = (int *) alloca (max_regno * sizeof (int));
sched_reg_live_length = (int *) alloca (max_regno * sizeof (int));
bb_dead_regs = ALLOCA_REG_SET ();
bb_live_regs = ALLOCA_REG_SET ();
bzero ((char *) sched_reg_n_calls_crossed, max_regno * sizeof (int));
bzero ((char *) sched_reg_live_length, max_regno * sizeof (int));
}
else
{
sched_reg_n_calls_crossed = 0;
sched_reg_live_length = 0;
bb_dead_regs = 0;
bb_live_regs = 0;
}
init_alias_analysis ();
if (write_symbols != NO_DEBUG)
{
rtx line;
line_note = (rtx *) xmalloc (max_uid * sizeof (rtx));
bzero ((char *) line_note, max_uid * sizeof (rtx));
line_note_head = (rtx *) alloca (n_basic_blocks * sizeof (rtx));
bzero ((char *) line_note_head, 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;
}
}
bzero ((char *) insn_luid, max_uid * sizeof (int));
bzero ((char *) insn_priority, max_uid * sizeof (int));
bzero ((char *) insn_tick, max_uid * sizeof (int));
bzero ((char *) insn_costs, max_uid * sizeof (short));
bzero ((char *) insn_units, max_uid * sizeof (short));
bzero ((char *) insn_blockage, max_uid * sizeof (unsigned int));
bzero ((char *) insn_ref_count, max_uid * sizeof (int));
insn = BLOCK_END (n_basic_blocks-1);
if (NEXT_INSN (insn) == 0
|| (GET_CODE (insn) != NOTE
&& GET_CODE (insn) != CODE_LABEL
&& ! (GET_CODE (insn) == JUMP_INSN
&& GET_CODE (NEXT_INSN (insn)) == BARRIER)))
emit_note_after (NOTE_INSN_DELETED, BLOCK_END (n_basic_blocks-1));
for (b = 0; b < n_basic_blocks; b++)
{
note_list = 0;
split_block_insns (b, reload_completed == 0 || ! flag_schedule_insns);
schedule_block (b, dump_file);
#ifdef USE_C_ALLOCA
alloca (0);
#endif
}
if (reload_completed)
reposition_prologue_and_epilogue_notes (get_insns ());
if (write_symbols != NO_DEBUG)
{
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 (dump_file && notes)
fprintf (dump_file, ";; deleted %d line-number notes\n", notes);
}
if (reload_completed == 0)
{
int regno;
for (regno = 0; regno < max_regno; regno++)
if (sched_reg_live_length[regno])
{
if (dump_file)
{
if (REG_LIVE_LENGTH (regno) > sched_reg_live_length[regno])
fprintf (dump_file,
";; register %d life shortened from %d to %d\n",
regno, REG_LIVE_LENGTH (regno),
sched_reg_live_length[regno]);
else if (REG_LIVE_LENGTH (regno) < sched_reg_live_length[regno]
&& REG_LIVE_LENGTH (regno) >= 0)
fprintf (dump_file,
";; register %d life extended from %d to %d\n",
regno, REG_LIVE_LENGTH (regno),
sched_reg_live_length[regno]);
if (! REG_N_CALLS_CROSSED (regno)
&& sched_reg_n_calls_crossed[regno])
fprintf (dump_file,
";; register %d now crosses calls\n", regno);
else if (REG_N_CALLS_CROSSED (regno)
&& ! sched_reg_n_calls_crossed[regno]
&& REG_BASIC_BLOCK (regno) != REG_BLOCK_GLOBAL)
fprintf (dump_file,
";; register %d no longer crosses calls\n", regno);
}
if (REG_LIVE_LENGTH (regno) >= 0)
REG_LIVE_LENGTH (regno) = sched_reg_live_length[regno];
if (sched_reg_n_calls_crossed[regno]
|| REG_BASIC_BLOCK (regno) != REG_BLOCK_GLOBAL)
REG_N_CALLS_CROSSED (regno) = sched_reg_n_calls_crossed[regno];
}
}
free (insn_luid);
free (insn_priority);
free (insn_tick);
free (insn_costs);
free (insn_units);
free (insn_blockage);
free (insn_ref_count);
if (write_symbols != NO_DEBUG)
free (line_note);
if (reload_completed == 0)
{
FREE_REG_SET (bb_dead_regs);
FREE_REG_SET (bb_live_regs);
}
}
#endif