#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "toplev.h"
#include "rtl.h"
#include "tm_p.h"
#include "hard-reg-set.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"
#include "cfglayout.h"
#include "cfgloop.h"
#include "cfghooks.h"
#include "expr.h"
#include "params.h"
#include "gcov-io.h"
#include "df.h"
#include "ddg.h"
#ifdef INSN_SCHEDULING
typedef struct partial_schedule *partial_schedule_ptr;
typedef struct ps_insn *ps_insn_ptr;
#define PS_MIN_CYCLE(ps) (((partial_schedule_ptr)(ps))->min_cycle)
#define PS_MAX_CYCLE(ps) (((partial_schedule_ptr)(ps))->max_cycle)
#define SMODULO(x,y) ((x) % (y) < 0 ? ((x) % (y) + (y)) : (x) % (y))
#define PS_STAGE_COUNT(ps) ((PS_MAX_CYCLE (ps) - PS_MIN_CYCLE (ps) \
+ 1 + (ps)->ii - 1) / (ps)->ii)
#define CFG_HOOKS cfg_layout_rtl_cfg_hooks
struct ps_insn
{
ddg_node_ptr node;
int cycle;
ps_insn_ptr next_in_row,
prev_in_row;
int row_rest_count;
};
struct partial_schedule
{
int ii;
int history;
ps_insn_ptr *rows;
int min_cycle;
int max_cycle;
ddg_ptr g;
};
static partial_schedule_ptr create_partial_schedule (int ii, ddg_ptr, int history);
static void free_partial_schedule (partial_schedule_ptr);
static void reset_partial_schedule (partial_schedule_ptr, int new_ii);
void print_partial_schedule (partial_schedule_ptr, FILE *);
static ps_insn_ptr ps_add_node_check_conflicts (partial_schedule_ptr,
ddg_node_ptr node, int cycle,
sbitmap must_precede,
sbitmap must_follow);
static void rotate_partial_schedule (partial_schedule_ptr, int);
void set_row_column_for_ps (partial_schedule_ptr);
static int issue_rate;
static FILE *stats_file;
static int sms_order_nodes (ddg_ptr, int, int * result);
static void set_node_sched_params (ddg_ptr);
static partial_schedule_ptr sms_schedule_by_order (ddg_ptr, int, int,
int *, FILE*);
static void permute_partial_schedule (partial_schedule_ptr ps, rtx last);
static void generate_prolog_epilog (partial_schedule_ptr, rtx, rtx, int);
static void duplicate_insns_of_cycles (partial_schedule_ptr ps,
int from_stage, int to_stage,
int is_prolog);
#define SCHED_ASAP(x) (((node_sched_params_ptr)(x)->aux.info)->asap)
#define SCHED_TIME(x) (((node_sched_params_ptr)(x)->aux.info)->time)
#define SCHED_FIRST_REG_MOVE(x) \
(((node_sched_params_ptr)(x)->aux.info)->first_reg_move)
#define SCHED_NREG_MOVES(x) \
(((node_sched_params_ptr)(x)->aux.info)->nreg_moves)
#define SCHED_ROW(x) (((node_sched_params_ptr)(x)->aux.info)->row)
#define SCHED_STAGE(x) (((node_sched_params_ptr)(x)->aux.info)->stage)
#define SCHED_COLUMN(x) (((node_sched_params_ptr)(x)->aux.info)->column)
typedef struct node_sched_params
{
int asap;
int time;
rtx first_reg_move;
int nreg_moves;
int row;
int stage;
int column;
} *node_sched_params_ptr;
static const char *
sms_print_insn (rtx insn, int aligned ATTRIBUTE_UNUSED)
{
static char tmp[80];
sprintf (tmp, "i%4d", INSN_UID (insn));
return tmp;
}
static int
contributes_to_priority (rtx next, rtx insn)
{
return BLOCK_NUM (next) == BLOCK_NUM (insn);
}
static void
compute_jump_reg_dependencies (rtx insn ATTRIBUTE_UNUSED,
regset cond_exec ATTRIBUTE_UNUSED,
regset used ATTRIBUTE_UNUSED,
regset set ATTRIBUTE_UNUSED)
{
}
static struct sched_info sms_sched_info =
{
NULL,
NULL,
NULL,
NULL,
NULL,
sms_print_insn,
contributes_to_priority,
compute_jump_reg_dependencies,
NULL, NULL,
NULL, NULL,
0, 0, 0
};
static rtx
doloop_register_get (rtx insn, rtx *comp)
{
rtx pattern, cmp, inc, reg, condition;
if (!JUMP_P (insn))
return NULL_RTX;
pattern = PATTERN (insn);
if (GET_CODE (pattern) != PARALLEL)
return NULL_RTX;
cmp = XVECEXP (pattern, 0, 0);
inc = XVECEXP (pattern, 0, 1);
*comp = cmp;
if (GET_CODE (inc) != SET || ! REG_P (SET_DEST (inc)))
return NULL_RTX;
reg = SET_DEST (inc);
if (GET_CODE (SET_SRC (inc)) != PLUS
|| XEXP (SET_SRC (inc), 0) != reg
|| XEXP (SET_SRC (inc), 1) != constm1_rtx)
return NULL_RTX;
if (GET_CODE (cmp) != SET
|| SET_DEST (cmp) != pc_rtx
|| GET_CODE (SET_SRC (cmp)) != IF_THEN_ELSE
|| GET_CODE (XEXP (SET_SRC (cmp), 1)) != LABEL_REF
|| XEXP (SET_SRC (cmp), 2) != pc_rtx)
return NULL_RTX;
condition = XEXP (SET_SRC (cmp), 0);
if (GET_CODE (condition) != NE
|| XEXP (condition, 1) != const1_rtx)
return NULL_RTX;
if (XEXP (condition, 0) == reg)
return reg;
return NULL_RTX;
}
static rtx
const_iteration_count (rtx count_reg, basic_block pre_header,
HOST_WIDEST_INT * count)
{
rtx insn;
rtx head, tail;
if (! pre_header)
return NULL_RTX;
get_block_head_tail (pre_header->index, &head, &tail);
for (insn = tail; insn != PREV_INSN (head); insn = PREV_INSN (insn))
if (INSN_P (insn) && single_set (insn) &&
rtx_equal_p (count_reg, SET_DEST (single_set (insn))))
{
rtx pat = single_set (insn);
if (GET_CODE (SET_SRC (pat)) == CONST_INT)
{
*count = INTVAL (SET_SRC (pat));
return insn;
}
return NULL_RTX;
}
return NULL_RTX;
}
static int
res_MII (ddg_ptr g)
{
return (g->num_nodes / issue_rate);
}
static node_sched_params_ptr node_sched_params;
static void
set_node_sched_params (ddg_ptr g)
{
int i;
node_sched_params = (node_sched_params_ptr)
xcalloc (g->num_nodes,
sizeof (struct node_sched_params));
for (i = 0; i < g->num_nodes; i++)
{
node_sched_params[i].asap = g->nodes[i].aux.count;
g->nodes[i].aux.info = &node_sched_params[i];
}
}
static void
print_node_sched_params (FILE * dump_file, int num_nodes)
{
int i;
if (! dump_file)
return;
for (i = 0; i < num_nodes; i++)
{
node_sched_params_ptr nsp = &node_sched_params[i];
rtx reg_move = nsp->first_reg_move;
int j;
fprintf (dump_file, "Node %d:\n", i);
fprintf (dump_file, " asap = %d:\n", nsp->asap);
fprintf (dump_file, " time = %d:\n", nsp->time);
fprintf (dump_file, " nreg_moves = %d:\n", nsp->nreg_moves);
for (j = 0; j < nsp->nreg_moves; j++)
{
fprintf (dump_file, " reg_move = ");
print_rtl_single (dump_file, reg_move);
reg_move = PREV_INSN (reg_move);
}
}
}
static int
calculate_maxii (ddg_ptr g)
{
int i;
int maxii = 0;
for (i = 0; i < g->num_nodes; i++)
{
ddg_node_ptr u = &g->nodes[i];
ddg_edge_ptr e;
int max_edge_latency = 0;
for (e = u->out; e; e = e->next_out)
max_edge_latency = MAX (max_edge_latency, e->latency);
maxii += max_edge_latency;
}
return maxii;
}
static void
generate_reg_moves (partial_schedule_ptr ps)
{
ddg_ptr g = ps->g;
int ii = ps->ii;
int i;
for (i = 0; i < g->num_nodes; i++)
{
ddg_node_ptr u = &g->nodes[i];
ddg_edge_ptr e;
int nreg_moves = 0, i_reg_move;
sbitmap *uses_of_defs;
rtx last_reg_move;
rtx prev_reg, old_reg;
for (e = u->out; e; e = e->next_out)
if (e->type == TRUE_DEP && e->dest != e->src)
{
int nreg_moves4e = (SCHED_TIME (e->dest) - SCHED_TIME (e->src)) / ii;
if (e->distance == 1)
nreg_moves4e = (SCHED_TIME (e->dest) - SCHED_TIME (e->src) + ii) / ii;
if (SCHED_ROW (e->dest) == SCHED_ROW (e->src)
&& SCHED_COLUMN (e->dest) < SCHED_COLUMN (e->src))
nreg_moves4e--;
nreg_moves = MAX (nreg_moves, nreg_moves4e);
}
if (nreg_moves == 0)
continue;
uses_of_defs = sbitmap_vector_alloc (nreg_moves, g->num_nodes);
sbitmap_vector_zero (uses_of_defs, nreg_moves);
for (e = u->out; e; e = e->next_out)
if (e->type == TRUE_DEP && e->dest != e->src)
{
int dest_copy = (SCHED_TIME (e->dest) - SCHED_TIME (e->src)) / ii;
if (e->distance == 1)
dest_copy = (SCHED_TIME (e->dest) - SCHED_TIME (e->src) + ii) / ii;
if (SCHED_ROW (e->dest) == SCHED_ROW (e->src)
&& SCHED_COLUMN (e->dest) < SCHED_COLUMN (e->src))
dest_copy--;
if (dest_copy)
SET_BIT (uses_of_defs[dest_copy - 1], e->dest->cuid);
}
SCHED_NREG_MOVES (u) = nreg_moves;
old_reg = prev_reg = copy_rtx (SET_DEST (single_set (u->insn)));
last_reg_move = u->insn;
for (i_reg_move = 0; i_reg_move < nreg_moves; i_reg_move++)
{
int i_use;
rtx new_reg = gen_reg_rtx (GET_MODE (prev_reg));
rtx reg_move = gen_move_insn (new_reg, prev_reg);
add_insn_before (reg_move, last_reg_move);
last_reg_move = reg_move;
if (!SCHED_FIRST_REG_MOVE (u))
SCHED_FIRST_REG_MOVE (u) = reg_move;
EXECUTE_IF_SET_IN_SBITMAP (uses_of_defs[i_reg_move], 0, i_use,
replace_rtx (g->nodes[i_use].insn, old_reg, new_reg));
prev_reg = new_reg;
}
}
}
static void
normalize_sched_times (partial_schedule_ptr ps)
{
int i;
ddg_ptr g = ps->g;
int amount = PS_MIN_CYCLE (ps);
int ii = ps->ii;
for (i = 0; i < g->num_nodes - 1; i++)
{
ddg_node_ptr u = &g->nodes[i];
int normalized_time = SCHED_TIME (u) - amount;
if (normalized_time < 0)
abort ();
SCHED_TIME (u) = normalized_time;
SCHED_ROW (u) = normalized_time % ii;
SCHED_STAGE (u) = normalized_time / ii;
}
}
static void
set_columns_for_ps (partial_schedule_ptr ps)
{
int row;
for (row = 0; row < ps->ii; row++)
{
ps_insn_ptr cur_insn = ps->rows[row];
int column = 0;
for (; cur_insn; cur_insn = cur_insn->next_in_row)
SCHED_COLUMN (cur_insn->node) = column++;
}
}
static void
permute_partial_schedule (partial_schedule_ptr ps, rtx last)
{
int ii = ps->ii;
int row;
ps_insn_ptr ps_ij;
for (row = 0; row < ii ; row++)
for (ps_ij = ps->rows[row]; ps_ij; ps_ij = ps_ij->next_in_row)
if (PREV_INSN (last) != ps_ij->node->insn)
reorder_insns_nobb (ps_ij->node->first_note, ps_ij->node->insn,
PREV_INSN (last));
}
static void
duplicate_insns_of_cycles (partial_schedule_ptr ps, int from_stage,
int to_stage, int for_prolog)
{
int row;
ps_insn_ptr ps_ij;
for (row = 0; row < ps->ii; row++)
for (ps_ij = ps->rows[row]; ps_ij; ps_ij = ps_ij->next_in_row)
{
ddg_node_ptr u_node = ps_ij->node;
int j, i_reg_moves;
rtx reg_move = NULL_RTX;
if (for_prolog)
{
i_reg_moves = to_stage - SCHED_STAGE (u_node) + 1;
i_reg_moves = MAX (i_reg_moves, 0);
i_reg_moves = MIN (i_reg_moves, SCHED_NREG_MOVES (u_node));
if (i_reg_moves)
{
reg_move = SCHED_FIRST_REG_MOVE (u_node);
for (j = 1; j < i_reg_moves; j++)
reg_move = PREV_INSN (reg_move);
}
}
else
{
i_reg_moves = SCHED_NREG_MOVES (u_node)
- (from_stage - SCHED_STAGE (u_node) - 1);
i_reg_moves = MAX (i_reg_moves, 0);
i_reg_moves = MIN (i_reg_moves, SCHED_NREG_MOVES (u_node));
if (i_reg_moves)
{
reg_move = SCHED_FIRST_REG_MOVE (u_node);
for (j = 1; j < SCHED_NREG_MOVES (u_node); j++)
reg_move = PREV_INSN (reg_move);
}
}
for (j = 0; j < i_reg_moves; j++, reg_move = NEXT_INSN (reg_move))
emit_insn (copy_rtx (PATTERN (reg_move)));
if (SCHED_STAGE (u_node) >= from_stage
&& SCHED_STAGE (u_node) <= to_stage)
duplicate_insn_chain (u_node->first_note, u_node->insn);
}
}
static void
generate_prolog_epilog (partial_schedule_ptr ps, rtx orig_loop_beg,
rtx orig_loop_end, int unknown_count)
{
int i;
int last_stage = PS_STAGE_COUNT (ps) - 1;
edge e;
rtx c_reg = NULL_RTX;
rtx cmp = NULL_RTX;
rtx precond_jump = NULL_RTX;
rtx precond_exit_label = NULL_RTX;
rtx precond_exit_label_insn = NULL_RTX;
rtx last_epilog_insn = NULL_RTX;
rtx loop_exit_label = NULL_RTX;
rtx loop_exit_label_insn = NULL_RTX;
rtx orig_loop_bct = NULL_RTX;
e = EDGE_PRED (ps->g->bb, 0);
if (e->src == ps->g->bb)
e = EDGE_PRED (ps->g->bb, 1);
start_sequence ();
if (unknown_count)
precond_jump = emit_note (NOTE_INSN_DELETED);
for (i = 0; i < last_stage; i++)
duplicate_insns_of_cycles (ps, 0, i, 1);
e->insns.r = get_insns ();
end_sequence ();
start_sequence ();
for (i = 0; i < last_stage; i++)
duplicate_insns_of_cycles (ps, i + 1, last_stage, 0);
last_epilog_insn = emit_note (NOTE_INSN_DELETED);
if (unknown_count)
{
rtx label, cond;
precond_exit_label = gen_label_rtx ();
precond_exit_label_insn = emit_label (precond_exit_label);
reorder_insns_nobb (orig_loop_beg, orig_loop_end, precond_exit_label_insn);
orig_loop_bct = get_last_insn ();
c_reg = doloop_register_get (orig_loop_bct, &cmp);
label = XEXP (SET_SRC (cmp), 1);
cond = XEXP (SET_SRC (cmp), 0);
if (! c_reg || GET_CODE (cond) != NE)
abort ();
XEXP (label, 0) = precond_exit_label;
JUMP_LABEL (orig_loop_bct) = precond_exit_label_insn;
LABEL_NUSES (precond_exit_label_insn)++;
loop_exit_label = gen_label_rtx ();
loop_exit_label_insn = emit_label (loop_exit_label);
}
e = EDGE_SUCC (ps->g->bb, 0);
if (e->dest == ps->g->bb)
e = EDGE_SUCC (ps->g->bb, 1);
e->insns.r = get_insns ();
end_sequence ();
commit_edge_insertions ();
if (unknown_count)
{
rtx precond_insns, epilog_jump, insert_after_insn;
basic_block loop_exit_bb = BLOCK_FOR_INSN (loop_exit_label_insn);
basic_block epilog_bb = BLOCK_FOR_INSN (last_epilog_insn);
basic_block precond_bb = BLOCK_FOR_INSN (precond_jump);
basic_block orig_loop_bb = BLOCK_FOR_INSN (precond_exit_label_insn);
edge epilog_exit_edge = EDGE_SUCC (epilog_bb, 0);
insert_after_insn = precond_jump;
start_sequence ();
c_reg = doloop_register_get (ps->g->closing_branch->insn, &cmp);
emit_cmp_and_jump_insns (c_reg, GEN_INT (PS_STAGE_COUNT (ps)), LT, NULL,
GET_MODE (c_reg), 1, precond_exit_label);
precond_insns = get_insns ();
precond_jump = get_last_insn ();
end_sequence ();
reorder_insns (precond_insns, precond_jump, insert_after_insn);
emit_insn_after (gen_sub2_insn (c_reg, GEN_INT (PS_STAGE_COUNT (ps) - 1)),
precond_jump);
update_bb_for_insn (precond_bb);
delete_insn (insert_after_insn);
JUMP_LABEL (precond_jump) = precond_exit_label_insn;
LABEL_NUSES (precond_exit_label_insn)++;
split_block (precond_bb, precond_jump);
make_edge (precond_bb, orig_loop_bb, 0);
epilog_jump = emit_jump_insn_after (gen_jump (loop_exit_label),
last_epilog_insn);
delete_insn (last_epilog_insn);
JUMP_LABEL (epilog_jump) = loop_exit_label_insn;
LABEL_NUSES (loop_exit_label_insn)++;
redirect_edge_succ (epilog_exit_edge, loop_exit_bb);
epilog_exit_edge->flags &= ~EDGE_FALLTHRU;
emit_barrier_after (BB_END (epilog_bb));
}
}
static rtx
find_line_note (rtx insn)
{
for (; insn; insn = PREV_INSN (insn))
if (NOTE_P (insn)
&& NOTE_LINE_NUMBER (insn) >= 0)
break;
return insn;
}
void
sms_schedule (FILE *dump_file)
{
static int passes = 0;
rtx insn;
ddg_ptr *g_arr, g;
basic_block bb, pre_header = NULL;
int * node_order;
int maxii;
int i;
partial_schedule_ptr ps;
int max_bb_index = last_basic_block;
struct df *df;
stats_file = dump_file;
if (targetm.sched.issue_rate)
{
int temp = reload_completed;
reload_completed = 1;
issue_rate = (*targetm.sched.issue_rate) ();
reload_completed = temp;
}
else
issue_rate = 1;
current_sched_info = &sms_sched_info;
sched_init (NULL);
df = df_init ();
df_analyze (df, 0, DF_ALL);
g_arr = xcalloc (max_bb_index, sizeof (ddg_ptr));
FOR_EACH_BB (bb)
{
rtx head, tail;
rtx count_reg, comp;
edge e, pre_header_edge;
if (bb->index < 0)
continue;
if (EDGE_COUNT (bb->succs) != 2)
continue;
if (EDGE_SUCC (bb, 0)->dest != bb && EDGE_SUCC (bb, 1)->dest != bb)
continue;
if ((EDGE_SUCC (bb, 0)->flags & EDGE_COMPLEX)
|| (EDGE_SUCC (bb, 1)->flags & EDGE_COMPLEX))
continue;
if (EDGE_COUNT (bb->preds) != 2)
continue;
if (EDGE_PRED (bb, 0)->src != bb && EDGE_PRED (bb, 1)->src != bb)
continue;
if ((EDGE_PRED (bb, 0)->flags & EDGE_COMPLEX)
|| (EDGE_PRED (bb, 1)->flags & EDGE_COMPLEX))
continue;
if ((passes++ > MAX_SMS_LOOP_NUMBER) && (MAX_SMS_LOOP_NUMBER != -1))
{
if (dump_file)
fprintf (dump_file, "SMS reached MAX_PASSES... \n");
break;
}
get_block_head_tail (bb->index, &head, &tail);
pre_header_edge = EDGE_PRED (bb, 0);
if (EDGE_PRED (bb, 0)->src != bb)
pre_header_edge = EDGE_PRED (bb, 1);
if (bb->count < pre_header_edge->count * SMS_LOOP_AVERAGE_COUNT_THRESHOLD)
{
if (stats_file)
{
rtx line_note = find_line_note (tail);
if (line_note)
{
expanded_location xloc;
NOTE_EXPANDED_LOCATION (xloc, line_note);
fprintf (stats_file, "SMS bb %s %d (file, line)\n",
xloc.file, xloc.line);
}
fprintf (stats_file, "SMS single-bb-loop\n");
if (profile_info && flag_branch_probabilities)
{
fprintf (stats_file, "SMS loop-count ");
fprintf (stats_file, HOST_WIDEST_INT_PRINT_DEC,
(HOST_WIDEST_INT) bb->count);
fprintf (stats_file, "\n");
fprintf (stats_file, "SMS preheader-count ");
fprintf (stats_file, HOST_WIDEST_INT_PRINT_DEC,
(HOST_WIDEST_INT) pre_header_edge->count);
fprintf (stats_file, "\n");
fprintf (stats_file, "SMS profile-sum-max ");
fprintf (stats_file, HOST_WIDEST_INT_PRINT_DEC,
(HOST_WIDEST_INT) profile_info->sum_max);
fprintf (stats_file, "\n");
}
}
continue;
}
if ( !(count_reg = doloop_register_get (tail, &comp)))
continue;
e = EDGE_PRED (bb, 0);
if (e->src == bb)
pre_header = EDGE_PRED (bb, 1)->src;
else
pre_header = e->src;
for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn))
if (CALL_P (insn)
|| BARRIER_P (insn)
|| (INSN_P (insn) && !JUMP_P (insn)
&& !single_set (insn) && GET_CODE (PATTERN (insn)) != USE))
break;
if (insn != NEXT_INSN (tail))
{
if (stats_file)
{
if (CALL_P (insn))
fprintf (stats_file, "SMS loop-with-call\n");
else if (BARRIER_P (insn))
fprintf (stats_file, "SMS loop-with-barrier\n");
else
fprintf (stats_file, "SMS loop-with-not-single-set\n");
print_rtl_single (stats_file, insn);
}
continue;
}
if (! (g = create_ddg (bb, df, 0)))
{
if (stats_file)
fprintf (stats_file, "SMS doloop\n");
continue;
}
g_arr[bb->index] = g;
}
df_finish (df);
for (i = 0; i < max_bb_index; i++)
{
rtx head, tail;
rtx count_reg, count_init, comp;
edge pre_header_edge;
int mii, rec_mii;
int stage_count = 0;
HOST_WIDEST_INT loop_count = 0;
if (! (g = g_arr[i]))
continue;
if (dump_file)
print_ddg (dump_file, g);
get_block_head_tail (g->bb->index, &head, &tail);
pre_header_edge = EDGE_PRED (g->bb, 0);
if (EDGE_PRED (g->bb, 0)->src != g->bb)
pre_header_edge = EDGE_PRED (g->bb, 1);
if (stats_file)
{
rtx line_note = find_line_note (tail);
if (line_note)
{
expanded_location xloc;
NOTE_EXPANDED_LOCATION (xloc, line_note);
fprintf (stats_file, "SMS bb %s %d (file, line)\n",
xloc.file, xloc.line);
}
fprintf (stats_file, "SMS single-bb-loop\n");
if (profile_info && flag_branch_probabilities)
{
fprintf (stats_file, "SMS loop-count ");
fprintf (stats_file, HOST_WIDEST_INT_PRINT_DEC,
(HOST_WIDEST_INT) bb->count);
fprintf (stats_file, "\n");
fprintf (stats_file, "SMS preheader-count ");
fprintf (stats_file, HOST_WIDEST_INT_PRINT_DEC,
(HOST_WIDEST_INT) pre_header_edge->count);
fprintf (stats_file, "\n");
fprintf (stats_file, "SMS profile-sum-max ");
fprintf (stats_file, HOST_WIDEST_INT_PRINT_DEC,
(HOST_WIDEST_INT) profile_info->sum_max);
fprintf (stats_file, "\n");
}
fprintf (stats_file, "SMS doloop\n");
fprintf (stats_file, "SMS built-ddg %d\n", g->num_nodes);
fprintf (stats_file, "SMS num-loads %d\n", g->num_loads);
fprintf (stats_file, "SMS num-stores %d\n", g->num_stores);
}
if ( !(count_reg = doloop_register_get (tail, &comp)))
abort ();
count_init = const_iteration_count (count_reg, pre_header, &loop_count);
if (stats_file && count_init)
{
fprintf (stats_file, "SMS const-doloop ");
fprintf (stats_file, HOST_WIDEST_INT_PRINT_DEC, loop_count);
fprintf (stats_file, "\n");
}
node_order = (int *) xmalloc (sizeof (int) * g->num_nodes);
mii = 1;
rec_mii = sms_order_nodes (g, mii, node_order);
mii = MAX (res_MII (g), rec_mii);
maxii = (calculate_maxii (g) * SMS_MAX_II_FACTOR) / 100;
if (stats_file)
fprintf (stats_file, "SMS iis %d %d %d (rec_mii, mii, maxii)\n",
rec_mii, mii, maxii);
set_node_sched_params (g);
ps = sms_schedule_by_order (g, mii, maxii, node_order, dump_file);
if (ps)
stage_count = PS_STAGE_COUNT (ps);
if (stage_count == 0 || (count_init && (stage_count > loop_count)))
{
if (dump_file)
fprintf (dump_file, "SMS failed... \n");
if (stats_file)
fprintf (stats_file, "SMS sched-failed %d\n", stage_count);
}
else
{
rtx orig_loop_beg = NULL_RTX;
rtx orig_loop_end = NULL_RTX;
if (stats_file)
{
fprintf (stats_file,
"SMS succeeded %d %d (with ii, sc)\n", ps->ii,
stage_count);
print_partial_schedule (ps, dump_file);
fprintf (dump_file,
"SMS Branch (%d) will later be scheduled at cycle %d.\n",
g->closing_branch->cuid, PS_MIN_CYCLE (ps) - 1);
}
if (! count_init)
{
int i;
start_sequence ();
for (i = 0; i < ps->g->num_nodes; i++)
duplicate_insn_chain (ps->g->nodes[i].first_note,
ps->g->nodes[i].insn);
orig_loop_beg = get_insns ();
orig_loop_end = get_last_insn ();
end_sequence ();
}
normalize_sched_times (ps);
rotate_partial_schedule (ps, PS_MIN_CYCLE (ps));
set_columns_for_ps (ps);
permute_partial_schedule (ps, g->closing_branch->first_note);
if (! flag_resched_modulo_sched)
g->bb->flags |= BB_DISABLE_SCHEDULE;
g->bb->flags |= BB_DIRTY;
generate_reg_moves (ps);
if (dump_file)
print_node_sched_params (dump_file, g->num_nodes);
if (count_init)
SET_SRC (single_set (count_init)) = GEN_INT (loop_count
- stage_count + 1);
generate_prolog_epilog (ps, orig_loop_beg, orig_loop_end,
count_init ? 0 : 1);
}
free_partial_schedule (ps);
free (node_sched_params);
free (node_order);
free_ddg (g);
}
sched_finish ();
}
#define DFA_HISTORY SMS_DFA_HISTORY
static partial_schedule_ptr
sms_schedule_by_order (ddg_ptr g, int mii, int maxii, int *nodes_order, FILE *dump_file)
{
int ii = mii;
int i, c, success;
int try_again_with_larger_ii = true;
int num_nodes = g->num_nodes;
ddg_edge_ptr e;
int start, end, step;
sbitmap sched_nodes = sbitmap_alloc (num_nodes);
sbitmap must_precede = sbitmap_alloc (num_nodes);
sbitmap must_follow = sbitmap_alloc (num_nodes);
partial_schedule_ptr ps = create_partial_schedule (ii, g, DFA_HISTORY);
while (try_again_with_larger_ii && ii < maxii)
{
if (dump_file)
fprintf(dump_file, "Starting with ii=%d\n", ii);
try_again_with_larger_ii = false;
sbitmap_zero (sched_nodes);
for (i = 0; i < num_nodes; i++)
{
int u = nodes_order[i];
ddg_node_ptr u_node = &g->nodes[u];
sbitmap u_node_preds = NODE_PREDECESSORS (u_node);
sbitmap u_node_succs = NODE_SUCCESSORS (u_node);
int psp_not_empty;
int pss_not_empty;
rtx insn = u_node->insn;
if (!INSN_P (insn))
continue;
if (JUMP_P (insn))
continue;
psp_not_empty = sbitmap_any_common_bits (u_node_preds, sched_nodes);
pss_not_empty = sbitmap_any_common_bits (u_node_succs, sched_nodes);
if (psp_not_empty && !pss_not_empty)
{
int early_start = 0;
end = INT_MAX;
for (e = u_node->in; e != 0; e = e->next_in)
{
ddg_node_ptr v_node = e->src;
if (TEST_BIT (sched_nodes, v_node->cuid))
{
int node_st = SCHED_TIME (v_node)
+ e->latency - (e->distance * ii);
early_start = MAX (early_start, node_st);
if (e->data_type == MEM_DEP)
end = MIN (end, SCHED_TIME (v_node) + ii - 1);
}
}
start = early_start;
end = MIN (end, early_start + ii);
step = 1;
}
else if (!psp_not_empty && pss_not_empty)
{
int late_start = INT_MAX;
end = INT_MIN;
for (e = u_node->out; e != 0; e = e->next_out)
{
ddg_node_ptr v_node = e->dest;
if (TEST_BIT (sched_nodes, v_node->cuid))
{
late_start = MIN (late_start,
SCHED_TIME (v_node) - e->latency
+ (e->distance * ii));
if (e->data_type == MEM_DEP)
end = MAX (end, SCHED_TIME (v_node) - ii + 1);
}
}
start = late_start;
end = MAX (end, late_start - ii);
step = -1;
}
else if (psp_not_empty && pss_not_empty)
{
int early_start = 0;
int late_start = INT_MAX;
start = INT_MIN;
end = INT_MAX;
for (e = u_node->in; e != 0; e = e->next_in)
{
ddg_node_ptr v_node = e->src;
if (TEST_BIT (sched_nodes, v_node->cuid))
{
early_start = MAX (early_start,
SCHED_TIME (v_node) + e->latency
- (e->distance * ii));
if (e->data_type == MEM_DEP)
end = MIN (end, SCHED_TIME (v_node) + ii - 1);
}
}
for (e = u_node->out; e != 0; e = e->next_out)
{
ddg_node_ptr v_node = e->dest;
if (TEST_BIT (sched_nodes, v_node->cuid))
{
late_start = MIN (late_start,
SCHED_TIME (v_node) - e->latency
+ (e->distance * ii));
if (e->data_type == MEM_DEP)
start = MAX (start, SCHED_TIME (v_node) - ii + 1);
}
}
start = MAX (start, early_start);
end = MIN (end, MIN (early_start + ii, late_start + 1));
step = 1;
}
else
{
start = SCHED_ASAP (u_node);
end = start + ii;
step = 1;
}
if (dump_file)
fprintf(dump_file, "Trying to schedule node %d in (%d .. %d) step %d\n",
u, start, end, step);
sbitmap_zero (must_precede);
sbitmap_zero (must_follow);
for (e = u_node->in; e != 0; e = e->next_in)
if (TEST_BIT (sched_nodes, e->src->cuid)
&& e->latency == (ii * e->distance)
&& start == SCHED_TIME (e->src))
SET_BIT (must_precede, e->src->cuid);
for (e = u_node->out; e != 0; e = e->next_out)
if (TEST_BIT (sched_nodes, e->dest->cuid)
&& e->latency == (ii * e->distance)
&& end == SCHED_TIME (e->dest))
SET_BIT (must_follow, e->dest->cuid);
success = 0;
if ((step > 0 && start < end) || (step < 0 && start > end))
for (c = start; c != end; c += step)
{
ps_insn_ptr psi;
psi = ps_add_node_check_conflicts (ps, u_node, c,
must_precede,
must_follow);
if (psi)
{
SCHED_TIME (u_node) = c;
SET_BIT (sched_nodes, u);
success = 1;
if (dump_file)
fprintf(dump_file, "Schedule in %d\n", c);
break;
}
}
if (!success)
{
ii++;
try_again_with_larger_ii = true;
reset_partial_schedule (ps, ii);
break;
}
}
}
sbitmap_free (sched_nodes);
if (ii >= maxii)
{
free_partial_schedule (ps);
ps = NULL;
}
return ps;
}
#define ORDER_PARAMS(x) ((struct node_order_params *) (x)->aux.info)
#define ASAP(x) (ORDER_PARAMS ((x))->asap)
#define ALAP(x) (ORDER_PARAMS ((x))->alap)
#define HEIGHT(x) (ORDER_PARAMS ((x))->height)
#define MOB(x) (ALAP ((x)) - ASAP ((x)))
#define DEPTH(x) (ASAP ((x)))
typedef struct node_order_params * nopa;
static void order_nodes_of_sccs (ddg_all_sccs_ptr, int * result);
static int order_nodes_in_scc (ddg_ptr, sbitmap, sbitmap, int*, int);
static nopa calculate_order_params (ddg_ptr, int mii);
static int find_max_asap (ddg_ptr, sbitmap);
static int find_max_hv_min_mob (ddg_ptr, sbitmap);
static int find_max_dv_min_mob (ddg_ptr, sbitmap);
enum sms_direction {BOTTOMUP, TOPDOWN};
struct node_order_params
{
int asap;
int alap;
int height;
};
static void
check_nodes_order (int *node_order, int num_nodes)
{
int i;
sbitmap tmp = sbitmap_alloc (num_nodes);
sbitmap_zero (tmp);
for (i = 0; i < num_nodes; i++)
{
int u = node_order[i];
if (u >= num_nodes || u < 0 || TEST_BIT (tmp, u))
abort ();
SET_BIT (tmp, u);
}
sbitmap_free (tmp);
}
static int
sms_order_nodes (ddg_ptr g, int mii, int * node_order)
{
int i;
int rec_mii = 0;
ddg_all_sccs_ptr sccs = create_ddg_all_sccs (g);
nopa nops = calculate_order_params (g, mii);
order_nodes_of_sccs (sccs, node_order);
if (sccs->num_sccs > 0)
rec_mii = sccs->sccs[0]->recurrence_length;
for (i = 0; i < g->num_nodes; i++)
{
ddg_node_ptr v = &g->nodes[i];
v->aux.count = ASAP (v);
}
free (nops);
free_ddg_all_sccs (sccs);
check_nodes_order (node_order, g->num_nodes);
return rec_mii;
}
static void
order_nodes_of_sccs (ddg_all_sccs_ptr all_sccs, int * node_order)
{
int i, pos = 0;
ddg_ptr g = all_sccs->ddg;
int num_nodes = g->num_nodes;
sbitmap prev_sccs = sbitmap_alloc (num_nodes);
sbitmap on_path = sbitmap_alloc (num_nodes);
sbitmap tmp = sbitmap_alloc (num_nodes);
sbitmap ones = sbitmap_alloc (num_nodes);
sbitmap_zero (prev_sccs);
sbitmap_ones (ones);
for (i = 0; i < all_sccs->num_sccs; i++)
{
ddg_scc_ptr scc = all_sccs->sccs[i];
find_nodes_on_paths (on_path, g, prev_sccs, scc->nodes);
sbitmap_a_or_b (tmp, scc->nodes, on_path);
find_nodes_on_paths (on_path, g, scc->nodes, prev_sccs);
sbitmap_a_or_b (tmp, tmp, on_path);
sbitmap_difference (tmp, tmp, prev_sccs);
pos = order_nodes_in_scc (g, prev_sccs, tmp, node_order, pos);
}
while (pos < g->num_nodes)
{
sbitmap_difference (tmp, ones, prev_sccs);
pos = order_nodes_in_scc (g, prev_sccs, tmp, node_order, pos);
}
sbitmap_free (prev_sccs);
sbitmap_free (on_path);
sbitmap_free (tmp);
sbitmap_free (ones);
}
static struct node_order_params *
calculate_order_params (ddg_ptr g, int mii ATTRIBUTE_UNUSED)
{
int u;
int max_asap;
int num_nodes = g->num_nodes;
ddg_edge_ptr e;
nopa node_order_params_arr;
node_order_params_arr = (nopa) xcalloc (num_nodes,
sizeof (struct node_order_params));
for (u = 0; u < num_nodes; u++)
g->nodes[u].aux.info = &node_order_params_arr[u];
max_asap = 0;
for (u = 0; u < num_nodes; u++)
{
ddg_node_ptr u_node = &g->nodes[u];
ASAP (u_node) = 0;
for (e = u_node->in; e; e = e->next_in)
if (e->distance == 0)
ASAP (u_node) = MAX (ASAP (u_node),
ASAP (e->src) + e->latency);
max_asap = MAX (max_asap, ASAP (u_node));
}
for (u = num_nodes - 1; u > -1; u--)
{
ddg_node_ptr u_node = &g->nodes[u];
ALAP (u_node) = max_asap;
HEIGHT (u_node) = 0;
for (e = u_node->out; e; e = e->next_out)
if (e->distance == 0)
{
ALAP (u_node) = MIN (ALAP (u_node),
ALAP (e->dest) - e->latency);
HEIGHT (u_node) = MAX (HEIGHT (u_node),
HEIGHT (e->dest) + e->latency);
}
}
return node_order_params_arr;
}
static int
find_max_asap (ddg_ptr g, sbitmap nodes)
{
int u;
int max_asap = -1;
int result = -1;
EXECUTE_IF_SET_IN_SBITMAP (nodes, 0, u,
{
ddg_node_ptr u_node = &g->nodes[u];
if (max_asap < ASAP (u_node))
{
max_asap = ASAP (u_node);
result = u;
}
});
return result;
}
static int
find_max_hv_min_mob (ddg_ptr g, sbitmap nodes)
{
int u;
int max_hv = -1;
int min_mob = INT_MAX;
int result = -1;
EXECUTE_IF_SET_IN_SBITMAP (nodes, 0, u,
{
ddg_node_ptr u_node = &g->nodes[u];
if (max_hv < HEIGHT (u_node))
{
max_hv = HEIGHT (u_node);
min_mob = MOB (u_node);
result = u;
}
else if ((max_hv == HEIGHT (u_node))
&& (min_mob > MOB (u_node)))
{
min_mob = MOB (u_node);
result = u;
}
});
return result;
}
static int
find_max_dv_min_mob (ddg_ptr g, sbitmap nodes)
{
int u;
int max_dv = -1;
int min_mob = INT_MAX;
int result = -1;
EXECUTE_IF_SET_IN_SBITMAP (nodes, 0, u,
{
ddg_node_ptr u_node = &g->nodes[u];
if (max_dv < DEPTH (u_node))
{
max_dv = DEPTH (u_node);
min_mob = MOB (u_node);
result = u;
}
else if ((max_dv == DEPTH (u_node))
&& (min_mob > MOB (u_node)))
{
min_mob = MOB (u_node);
result = u;
}
});
return result;
}
static int
order_nodes_in_scc (ddg_ptr g, sbitmap nodes_ordered, sbitmap scc,
int * node_order, int pos)
{
enum sms_direction dir;
int num_nodes = g->num_nodes;
sbitmap workset = sbitmap_alloc (num_nodes);
sbitmap tmp = sbitmap_alloc (num_nodes);
sbitmap zero_bitmap = sbitmap_alloc (num_nodes);
sbitmap predecessors = sbitmap_alloc (num_nodes);
sbitmap successors = sbitmap_alloc (num_nodes);
sbitmap_zero (predecessors);
find_predecessors (predecessors, g, nodes_ordered);
sbitmap_zero (successors);
find_successors (successors, g, nodes_ordered);
sbitmap_zero (tmp);
if (sbitmap_a_and_b_cg (tmp, predecessors, scc))
{
sbitmap_copy (workset, tmp);
dir = BOTTOMUP;
}
else if (sbitmap_a_and_b_cg (tmp, successors, scc))
{
sbitmap_copy (workset, tmp);
dir = TOPDOWN;
}
else
{
int u;
sbitmap_zero (workset);
if ((u = find_max_asap (g, scc)) >= 0)
SET_BIT (workset, u);
dir = BOTTOMUP;
}
sbitmap_zero (zero_bitmap);
while (!sbitmap_equal (workset, zero_bitmap))
{
int v;
ddg_node_ptr v_node;
sbitmap v_node_preds;
sbitmap v_node_succs;
if (dir == TOPDOWN)
{
while (!sbitmap_equal (workset, zero_bitmap))
{
v = find_max_hv_min_mob (g, workset);
v_node = &g->nodes[v];
node_order[pos++] = v;
v_node_succs = NODE_SUCCESSORS (v_node);
sbitmap_a_and_b (tmp, v_node_succs, scc);
sbitmap_difference (tmp, tmp, nodes_ordered);
sbitmap_a_or_b (workset, workset, tmp);
RESET_BIT (workset, v);
SET_BIT (nodes_ordered, v);
}
dir = BOTTOMUP;
sbitmap_zero (predecessors);
find_predecessors (predecessors, g, nodes_ordered);
sbitmap_a_and_b (workset, predecessors, scc);
}
else
{
while (!sbitmap_equal (workset, zero_bitmap))
{
v = find_max_dv_min_mob (g, workset);
v_node = &g->nodes[v];
node_order[pos++] = v;
v_node_preds = NODE_PREDECESSORS (v_node);
sbitmap_a_and_b (tmp, v_node_preds, scc);
sbitmap_difference (tmp, tmp, nodes_ordered);
sbitmap_a_or_b (workset, workset, tmp);
RESET_BIT (workset, v);
SET_BIT (nodes_ordered, v);
}
dir = TOPDOWN;
sbitmap_zero (successors);
find_successors (successors, g, nodes_ordered);
sbitmap_a_and_b (workset, successors, scc);
}
}
sbitmap_free (tmp);
sbitmap_free (workset);
sbitmap_free (zero_bitmap);
sbitmap_free (predecessors);
sbitmap_free (successors);
return pos;
}
static partial_schedule_ptr
create_partial_schedule (int ii, ddg_ptr g, int history)
{
partial_schedule_ptr ps = (partial_schedule_ptr)
xmalloc (sizeof (struct partial_schedule));
ps->rows = (ps_insn_ptr *) xcalloc (ii, sizeof (ps_insn_ptr));
ps->ii = ii;
ps->history = history;
ps->min_cycle = INT_MAX;
ps->max_cycle = INT_MIN;
ps->g = g;
return ps;
}
static void
free_ps_insns (partial_schedule_ptr ps)
{
int i;
for (i = 0; i < ps->ii; i++)
{
while (ps->rows[i])
{
ps_insn_ptr ps_insn = ps->rows[i]->next_in_row;
free (ps->rows[i]);
ps->rows[i] = ps_insn;
}
ps->rows[i] = NULL;
}
}
static void
free_partial_schedule (partial_schedule_ptr ps)
{
if (!ps)
return;
free_ps_insns (ps);
free (ps->rows);
free (ps);
}
static void
reset_partial_schedule (partial_schedule_ptr ps, int new_ii)
{
if (!ps)
return;
free_ps_insns (ps);
if (new_ii == ps->ii)
return;
ps->rows = (ps_insn_ptr *) xrealloc (ps->rows, new_ii
* sizeof (ps_insn_ptr));
memset (ps->rows, 0, new_ii * sizeof (ps_insn_ptr));
ps->ii = new_ii;
ps->min_cycle = INT_MAX;
ps->max_cycle = INT_MIN;
}
void
print_partial_schedule (partial_schedule_ptr ps, FILE *dump)
{
int i;
for (i = 0; i < ps->ii; i++)
{
ps_insn_ptr ps_i = ps->rows[i];
fprintf (dump, "\n[CYCLE %d ]: ", i);
while (ps_i)
{
fprintf (dump, "%d, ",
INSN_UID (ps_i->node->insn));
ps_i = ps_i->next_in_row;
}
}
}
static ps_insn_ptr
create_ps_insn (ddg_node_ptr node, int rest_count, int cycle)
{
ps_insn_ptr ps_i = xmalloc (sizeof (struct ps_insn));
ps_i->node = node;
ps_i->next_in_row = NULL;
ps_i->prev_in_row = NULL;
ps_i->row_rest_count = rest_count;
ps_i->cycle = cycle;
return ps_i;
}
static int
remove_node_from_ps (partial_schedule_ptr ps, ps_insn_ptr ps_i)
{
int row;
if (!ps || !ps_i)
return false;
row = SMODULO (ps_i->cycle, ps->ii);
if (! ps_i->prev_in_row)
{
if (ps_i != ps->rows[row])
return false;
ps->rows[row] = ps_i->next_in_row;
if (ps->rows[row])
ps->rows[row]->prev_in_row = NULL;
}
else
{
ps_i->prev_in_row->next_in_row = ps_i->next_in_row;
if (ps_i->next_in_row)
ps_i->next_in_row->prev_in_row = ps_i->prev_in_row;
}
free (ps_i);
return true;
}
static bool
ps_insn_find_column (partial_schedule_ptr ps, ps_insn_ptr ps_i,
sbitmap must_precede, sbitmap must_follow)
{
ps_insn_ptr next_ps_i;
ps_insn_ptr first_must_follow = NULL;
ps_insn_ptr last_must_precede = NULL;
int row;
if (! ps_i)
return false;
row = SMODULO (ps_i->cycle, ps->ii);
for (next_ps_i = ps->rows[row];
next_ps_i;
next_ps_i = next_ps_i->next_in_row)
{
if (TEST_BIT (must_follow, next_ps_i->node->cuid)
&& ! first_must_follow)
first_must_follow = next_ps_i;
if (TEST_BIT (must_precede, next_ps_i->node->cuid))
{
if (first_must_follow)
return false;
else
last_must_precede = next_ps_i;
}
}
if (! last_must_precede)
{
ps_i->next_in_row = ps->rows[row];
ps_i->prev_in_row = NULL;
if (ps_i->next_in_row)
ps_i->next_in_row->prev_in_row = ps_i;
ps->rows[row] = ps_i;
}
else
{
ps_i->next_in_row = last_must_precede->next_in_row;
last_must_precede->next_in_row = ps_i;
ps_i->prev_in_row = last_must_precede;
if (ps_i->next_in_row)
ps_i->next_in_row->prev_in_row = ps_i;
}
return true;
}
static int
ps_insn_advance_column (partial_schedule_ptr ps, ps_insn_ptr ps_i,
sbitmap must_follow)
{
ps_insn_ptr prev, next;
int row;
ddg_node_ptr next_node;
if (!ps || !ps_i)
return false;
row = SMODULO (ps_i->cycle, ps->ii);
if (! ps_i->next_in_row)
return false;
next_node = ps_i->next_in_row->node;
if (TEST_BIT (must_follow, next_node->cuid))
return false;
prev = ps_i->prev_in_row;
next = ps_i->next_in_row;
if (ps_i == ps->rows[row])
ps->rows[row] = next;
ps_i->next_in_row = next->next_in_row;
if (next->next_in_row)
next->next_in_row->prev_in_row = ps_i;
next->next_in_row = ps_i;
ps_i->prev_in_row = next;
next->prev_in_row = prev;
if (prev)
prev->next_in_row = next;
return true;
}
static ps_insn_ptr
add_node_to_ps (partial_schedule_ptr ps, ddg_node_ptr node, int cycle,
sbitmap must_precede, sbitmap must_follow)
{
ps_insn_ptr ps_i;
int rest_count = 1;
int row = SMODULO (cycle, ps->ii);
if (ps->rows[row]
&& ps->rows[row]->row_rest_count >= issue_rate)
return NULL;
if (ps->rows[row])
rest_count += ps->rows[row]->row_rest_count;
ps_i = create_ps_insn (node, rest_count, cycle);
if (! ps_insn_find_column (ps, ps_i, must_precede, must_follow))
{
free (ps_i);
return NULL;
}
return ps_i;
}
static void
advance_one_cycle (void)
{
if (targetm.sched.dfa_pre_cycle_insn)
state_transition (curr_state,
(*targetm.sched.dfa_pre_cycle_insn) ());
state_transition (curr_state, NULL);
if (targetm.sched.dfa_post_cycle_insn)
state_transition (curr_state,
(*targetm.sched.dfa_post_cycle_insn) ());
}
static int
ps_has_conflicts (partial_schedule_ptr ps, int from, int to)
{
int cycle;
state_reset (curr_state);
for (cycle = from; cycle <= to; cycle++)
{
ps_insn_ptr crr_insn;
int can_issue_more = issue_rate;
for (crr_insn = ps->rows[SMODULO (cycle, ps->ii)];
crr_insn;
crr_insn = crr_insn->next_in_row)
{
rtx insn = crr_insn->node->insn;
if (!INSN_P (insn))
continue;
if (!can_issue_more || state_dead_lock_p (curr_state))
return true;
if (state_transition (curr_state, insn) >= 0)
return true;
if (targetm.sched.variable_issue)
can_issue_more =
(*targetm.sched.variable_issue) (sched_dump, sched_verbose,
insn, can_issue_more);
else if (GET_CODE (PATTERN (insn)) != USE
&& GET_CODE (PATTERN (insn)) != CLOBBER)
can_issue_more--;
}
advance_one_cycle ();
}
return false;
}
static ps_insn_ptr
ps_add_node_check_conflicts (partial_schedule_ptr ps, ddg_node_ptr n,
int c, sbitmap must_precede,
sbitmap must_follow)
{
int has_conflicts = 0;
ps_insn_ptr ps_i;
if (! (ps_i = add_node_to_ps (ps, n, c, must_precede, must_follow)))
return NULL;
has_conflicts = ps_has_conflicts (ps, c, c)
|| (ps->history > 0
&& ps_has_conflicts (ps,
c - ps->history,
c + ps->history));
while (has_conflicts)
{
if (! ps_insn_advance_column (ps, ps_i, must_follow))
break;
has_conflicts = ps_has_conflicts (ps, c, c)
|| (ps->history > 0
&& ps_has_conflicts (ps,
c - ps->history,
c + ps->history));
}
if (has_conflicts)
{
remove_node_from_ps (ps, ps_i);
return NULL;
}
ps->min_cycle = MIN (ps->min_cycle, c);
ps->max_cycle = MAX (ps->max_cycle, c);
return ps_i;
}
static void
rotate_partial_schedule (partial_schedule_ptr ps, int start_cycle)
{
int i, row, backward_rotates;
int last_row = ps->ii - 1;
if (start_cycle == 0)
return;
backward_rotates = SMODULO (start_cycle, ps->ii);
for (i = 0; i < backward_rotates; i++)
{
ps_insn_ptr first_row = ps->rows[0];
for (row = 0; row < last_row; row++)
ps->rows[row] = ps->rows[row+1];
ps->rows[last_row] = first_row;
}
ps->max_cycle -= start_cycle;
ps->min_cycle -= start_cycle;
}
#endif